The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

OverView.vala in libbirdfont

This file is a part of the Birdfont project.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git

Revisions

View the latest version of libbirdfont/OverView.vala.
Use fixed size glyphs in overview
1 /* 2 Copyright (C) 2012 - 2016 Johan Mattsson 3 4 This library is free software; you can redistribute it and/or modify 5 it under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 3 of the 7 License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Lesser General Public License for more details. 13 */ 14 15 using Cairo; 16 17 namespace BirdFont { 18 19 /** A display with all glyphs present in this font. */ 20 public class OverView : FontDisplay { 21 public WidgetAllocation allocation = new WidgetAllocation (); 22 23 public OverViewItem selected_item = new OverViewItem (); 24 25 public Gee.ArrayList<GlyphCollection> copied_glyphs = new Gee.ArrayList<GlyphCollection> (); 26 public Gee.ArrayList<GlyphCollection> selected_items = new Gee.ArrayList<GlyphCollection> (); 27 28 int selected = 0; 29 int first_visible = 0; 30 int rows = 0; 31 int items_per_row = 0; 32 33 double view_offset_y = 0; 34 double view_offset_x = 0; 35 36 public signal void open_new_glyph_signal (unichar c); 37 public signal void open_glyph_signal (GlyphCollection c); 38 39 public GlyphRange glyph_range { 40 get { 41 return _glyph_range; 42 } 43 44 set { 45 _glyph_range = value; 46 } 47 } 48 49 GlyphRange _glyph_range; 50 51 string search_query = ""; 52 53 public Gee.ArrayList<OverViewItem> visible_items = new Gee.ArrayList<OverViewItem> (); 54 55 /** List of undo commands. */ 56 public Gee.ArrayList<OverViewUndoItem> undo_items = new Gee.ArrayList<OverViewUndoItem> (); 57 public Gee.ArrayList<OverViewUndoItem> redo_items = new Gee.ArrayList<OverViewUndoItem> (); 58 59 /** Show all characters that has been drawn. */ 60 public bool all_available { 61 set { 62 _all_available = value; 63 update_item_list (); 64 } 65 66 get { 67 return _all_available; 68 } 69 } 70 71 bool _all_available = false; 72 73 /** Show unicode database info. */ 74 CharacterInfo? character_info = null; 75 76 double scroll_size = 1; 77 const double UCD_LINE_HEIGHT = 17 * 1.3; 78 79 private bool update_scheduled = true; 80 81 public OverView (GlyphRange? range = null, 82 bool open_selected = true, bool default_character_set = true) { 83 84 GlyphRange gr; 85 86 if (range == null) { 87 gr = new GlyphRange (); 88 set_current_glyph_range (gr); 89 } 90 91 if (open_selected) { 92 this.open_glyph_signal.connect ((glyph_collection) => { 93 TabBar tabs = MainWindow.get_tab_bar (); 94 string n = glyph_collection.get_current ().name; 95 bool selected = tabs.select_char (n); 96 Glyph g = glyph_collection.get_current (); 97 GlyphTab glyph_tab; 98 99 if (!selected) { 100 glyph_tab = new GlyphTab (glyph_collection); 101 tabs.add_tab (glyph_tab, true, glyph_collection); 102 set_glyph_zoom (glyph_collection); 103 PenTool.update_orientation (); 104 } 105 }); 106 107 this.open_new_glyph_signal.connect ((character) => { 108 // ignore control characters 109 if (character <= 0x1F) { 110 return; 111 } 112 113 create_new_glyph (character); 114 }); 115 } 116 117 if (default_character_set) { 118 IdleSource idle = new IdleSource (); 119 120 idle.set_callback (() => { 121 use_default_character_set (); 122 selected_canvas (); 123 return false; 124 }); 125 126 idle.attach (null); 127 } 128 129 update_item_list (); 130 update_scrollbar (); 131 reset_zoom (); 132 133 string? zoom = Preferences.get ("overview_zoom"); 134 135 if (zoom != null) { 136 string z = (!) zoom; 137 138 if (z != "") { 139 set_zoom (double.parse (z)); 140 } 141 } 142 } 143 144 public void reset_cache () { 145 foreach (OverViewItem i in visible_items) { 146 i.clear_cache (); 147 } 148 } 149 150 public Glyph? get_selected_glyph () { 151 if (selected_items.size == 0) { 152 return null; 153 } 154 155 return selected_items.get (0).get_current (); 156 } 157 158 public void select_all_glyphs () { 159 Font f; 160 GlyphCollection? glyphs; 161 162 f = BirdFont.get_current_font (); 163 164 for (int index = 0; index < f.length (); index++) { 165 glyphs = f.get_glyph_collection_index ((uint32) index); 166 return_if_fail (glyphs != null); 167 168 selected_items.add ((!) glyphs); 169 } 170 171 foreach (OverViewItem item in visible_items) { 172 item.selected = item.glyphs != null; 173 } 174 175 GlyphCanvas.redraw (); 176 } 177 178 public void use_default_character_set () { 179 GlyphRange gr = new GlyphRange (); 180 all_available = false; 181 DefaultCharacterSet.use_default_range (gr); 182 set_current_glyph_range (gr); 183 OverviewTools.update_overview_characterset (); 184 FontDisplay.dirty_scrollbar = true; 185 } 186 187 public GlyphCollection create_new_glyph (unichar character) { 188 StringBuilder name = new StringBuilder (); 189 TabBar tabs = MainWindow.get_tab_bar (); 190 bool selected; 191 Glyph glyph; 192 GlyphCollection glyph_collection; 193 GlyphCanvas canvas; 194 GlyphTab glyph_tab; 195 196 glyph_collection = MainWindow.get_current_glyph_collection (); 197 name.append_unichar (character); 198 selected = tabs.select_char (name.str); 199 200 if (!selected) { 201 glyph_collection = add_character_to_font (character); 202 glyph_tab = new GlyphTab (glyph_collection); 203 glyph = glyph_collection.get_current (); 204 glyph.layers.add_layer (new Layer ()); 205 tabs.add_tab (glyph_tab, true, glyph_collection); 206 207 selected_items.add (glyph_collection); 208 209 canvas = MainWindow.get_glyph_canvas (); 210 canvas.set_current_glyph_collection (glyph_collection); 211 212 set_glyph_zoom (glyph_collection); 213 } else { 214 warning ("Glyph is already open"); 215 } 216 217 OverviewTools.update_overview_characterset (); 218 return glyph_collection; 219 } 220 221 public GlyphCollection add_empty_character_to_font (unichar character, bool unassigned, string name) { 222 return add_character_to_font (character, true, unassigned); 223 } 224 225 public GlyphCollection add_character_to_font (unichar character, bool empty = false, 226 bool unassigned = false, string glyph_name = "") { 227 StringBuilder name = new StringBuilder (); 228 Font font = BirdFont.get_current_font (); 229 GlyphCollection? fg; 230 Glyph glyph; 231 GlyphCollection glyph_collection; 232 233 if (glyph_name == "") { 234 name.append_unichar (character); 235 } else { 236 name.append (glyph_name); 237 } 238 239 if (all_available) { 240 fg = font.get_glyph_collection_by_name (name.str); 241 } else { 242 fg = font.get_glyph_collection (name.str); 243 } 244 245 if (fg != null) { 246 glyph_collection = (!) fg; 247 } else { 248 glyph_collection = new GlyphCollection (character, name.str); 249 250 if (!empty) { 251 glyph = new Glyph (name.str, !unassigned ? character : '\0'); 252 glyph_collection.add_master (new GlyphMaster ()); 253 glyph_collection.insert_glyph (glyph, true); 254 } 255 256 font.add_glyph_collection (glyph_collection); 257 } 258 259 glyph_collection.set_unassigned (unassigned); 260 261 return glyph_collection; 262 } 263 264 public static void search () { 265 OverView ow = MainWindow.get_overview (); 266 TextListener listener = new TextListener (t_("Search"), ow.search_query, t_("Filter")); 267 268 listener.signal_text_input.connect ((text) => { 269 OverView o = MainWindow.get_overview (); 270 o.search_query = text; 271 }); 272 273 listener.signal_submit.connect (() => { 274 OverView o = MainWindow.get_overview (); 275 string q = o.search_query; 276 277 if (q.char_count () > 1) { 278 q = q.down (); 279 } 280 281 GlyphRange r = CharDatabase.search (q); 282 o.set_current_glyph_range (r); 283 MainWindow.get_tab_bar ().select_tab_name ("Overview"); 284 285 TextListener tl = new TextListener (t_("Search"), o.search_query, t_("Filter")); 286 TabContent.show_text_input (tl); 287 }); 288 289 TabContent.show_text_input (listener); 290 } 291 292 public Glyph? get_current_glyph () { 293 OverViewItem oi = selected_item; 294 if (oi.glyphs != null) { 295 return ((!) oi.glyphs).get_current (); 296 } 297 return null; 298 } 299 300 public void set_glyph_zoom (GlyphCollection glyphs) { 301 GlyphCanvas canvas; 302 canvas = MainWindow.get_glyph_canvas (); 303 canvas.set_current_glyph_collection (glyphs); 304 Toolbox tools = MainWindow.get_toolbox (); 305 ZoomTool z = (ZoomTool) tools.get_tool ("zoom_tool"); 306 z.store_current_view (); 307 glyphs.get_current ().default_zoom (); 308 z.store_current_view (); 309 OverViewItem.reset_label (); 310 } 311 312 public double get_height () { 313 double l; 314 Font f; 315 316 if (rows == 0) { 317 return 0; 318 } 319 320 if (all_available) { 321 f = BirdFont.get_current_font (); 322 l = f.length (); 323 } else { 324 l = glyph_range.length (); 325 } 326 327 return 2.0 * OverViewItem.height * (l / rows); 328 } 329 330 public bool selected_char_is_visible () { 331 return first_visible <= selected <= first_visible + items_per_row * rows; 332 } 333 334 public override bool has_scrollbar () { 335 return true; 336 } 337 338 public bool all_characters_in_view () { 339 double length; 340 Font f; 341 342 if (all_available) { 343 f = BirdFont.get_current_font (); 344 length = f.length (); 345 } else { 346 length = glyph_range.length (); 347 } 348 349 return length < items_per_row * rows; 350 } 351 352 public void move_up () { 353 first_visible -= items_per_row; 354 selected += items_per_row; 355 356 if (first_visible < 0) { 357 selected -= items_per_row; 358 first_visible = 0; 359 view_offset_y = 0; 360 } 361 } 362 363 public void move_down () { 364 if (!at_bottom ()) { 365 first_visible += items_per_row; 366 selected -= items_per_row; 367 } 368 } 369 370 public override void scroll_wheel (double x, double y, double dx, double dy) { 371 double pixel_delta = 3 * dy; 372 373 if (dy > 0) { 374 view_offset_y += pixel_delta; 375 376 while (view_offset_y > 0) { 377 view_offset_y -= OverViewItem.height; 378 move_up (); 379 } 380 } else { 381 if (at_bottom ()) { 382 if (view_offset_y > -2 * OverViewItem.height && !all_characters_in_view ()) { 383 view_offset_y += pixel_delta; 384 } 385 } else { 386 view_offset_y += pixel_delta; 387 while (view_offset_y < -OverViewItem.height) { 388 view_offset_y += OverViewItem.height; 389 move_down (); 390 } 391 } 392 } 393 394 if (view_offset_y < -2 * OverViewItem.height) { 395 view_offset_y = -2 * OverViewItem.height; 396 } 397 398 update_item_list (); 399 update_scrollbar (); 400 hide_menu (); 401 GlyphCanvas.redraw (); 402 } 403 404 public override void selected_canvas () { 405 OverviewTools.update_overview_characterset (); 406 KeyBindings.set_require_modifier (true); 407 update_scrollbar (); 408 update_zoom_bar (); 409 OverViewItem.glyph_scale = 1; 410 update_item_list (); 411 selected_item = get_selected_item (); 412 GlyphCanvas.redraw (); 413 } 414 415 public void update_zoom_bar () { 416 double z = OverViewItem.width / OverViewItem.DEFAULT_WIDTH - 0.5; 417 Toolbox.overview_tools.zoom_bar.set_zoom (z); 418 Toolbox.redraw_tool_box (); 419 update_item_list (); 420 } 421 422 public void set_zoom (double zoom) { 423 double z = zoom + 0.5; 424 OverViewItem.glyph_scale = 1; 425 OverViewItem.width = OverViewItem.DEFAULT_WIDTH * z; 426 OverViewItem.height = OverViewItem.DEFAULT_HEIGHT * z; 427 OverViewItem.margin = OverViewItem.DEFAULT_MARGIN * z; 428 update_item_list (); 429 OverViewItem.reset_label (); 430 Preferences.set ("overview_zoom", @"$zoom"); 431 432 Font font = BirdFont.get_current_font (); 433 for (int index = 0; index < font.length (); index++) { 434 GlyphCollection? glyphs = font.get_glyph_collection_index ((uint32) index); 435 return_if_fail (glyphs != null); 436 GlyphCollection g = (!) glyphs; 437 g.get_current ().overview_thumbnail = null; 438 } 439 440 GlyphCanvas.redraw (); 441 } 442 443 public override void zoom_min () { 444 OverViewItem.width = OverViewItem.DEFAULT_WIDTH * 0.5; 445 OverViewItem.height = OverViewItem.DEFAULT_HEIGHT * 0.5; 446 OverViewItem.margin = OverViewItem.DEFAULT_MARGIN * 0.5; 447 update_item_list (); 448 OverViewItem.reset_label (); 449 GlyphCanvas.redraw (); 450 update_zoom_bar (); 451 } 452 453 public override void reset_zoom () { 454 OverViewItem.width = OverViewItem.DEFAULT_WIDTH; 455 OverViewItem.height = OverViewItem.DEFAULT_HEIGHT; 456 OverViewItem.margin = OverViewItem.DEFAULT_MARGIN; 457 update_item_list (); 458 OverViewItem.reset_label (); 459 GlyphCanvas.redraw (); 460 update_zoom_bar (); 461 } 462 463 public override void zoom_max () { 464 OverViewItem.width = allocation.width; 465 OverViewItem.height = allocation.height; 466 update_item_list (); 467 OverViewItem.reset_label (); 468 GlyphCanvas.redraw (); 469 } 470 471 public override void zoom_in () { 472 OverViewItem.width *= 1.1; 473 OverViewItem.height *= 1.1; 474 OverViewItem.margin *= 1.1; 475 update_item_list (); 476 OverViewItem.reset_label (); 477 GlyphCanvas.redraw (); 478 update_zoom_bar (); 479 } 480 481 public override void zoom_out () { 482 OverViewItem.width *= 0.9; 483 OverViewItem.height *= 0.9; 484 OverViewItem.margin *= 0.9; 485 update_item_list (); 486 OverViewItem.reset_label (); 487 GlyphCanvas.redraw (); 488 update_zoom_bar (); 489 } 490 491 public override void store_current_view () { 492 } 493 494 public override void restore_last_view () { 495 } 496 497 public override void next_view () { 498 } 499 500 public override string get_label () { 501 return t_("Overview"); 502 } 503 504 public override string get_name () { 505 return "Overview"; 506 } 507 508 public void display_all_available_glyphs () { 509 all_available = true; 510 511 view_offset_y = 0; 512 first_visible = 0; 513 selected = 0; 514 515 update_item_list (); 516 selected_item = get_selected_item (); 517 GlyphCanvas.redraw (); 518 } 519 520 OverViewItem get_selected_item () { 521 if (visible_items.size == 0) { 522 return new OverViewItem (); 523 } 524 525 if (!(0 <= selected < visible_items.size)) { 526 return selected_item; 527 } 528 529 OverViewItem item = visible_items.get (selected); 530 item.selected = true; 531 return item; 532 } 533 534 int get_items_per_row () { 535 int i = 1; 536 double tab_with = allocation.width - 30; // 30 px for the scroll bar 537 OverViewItem.margin = OverViewItem.width * 0.1; 538 double l = OverViewItem.margin + OverViewItem.full_width (); 539 540 while (l <= tab_with) { 541 l += OverViewItem.full_width (); 542 i++; 543 } 544 545 return i - 1; 546 } 547 548 public void update_item_list () { 549 update_scheduled = true; 550 } 551 552 public void process_item_list_update () { 553 string character_string; 554 Font f = BirdFont.get_current_font (); 555 GlyphCollection? glyphs = null; 556 uint32 index; 557 OverViewItem item; 558 double x, y; 559 unichar character; 560 Glyph glyph; 561 double tab_with; 562 int item_list_length; 563 int visible_size; 564 565 tab_with = allocation.width - 30; // scrollbar 566 567 items_per_row = get_items_per_row (); 568 rows = (int) (allocation.height / OverViewItem.full_height ()) + 2; 569 570 item_list_length = items_per_row * rows; 571 visible_items.clear (); 572 573 index = (uint32) first_visible; 574 x = OverViewItem.margin; 575 y = OverViewItem.margin; 576 577 if (all_available) { 578 uint font_length = f.length (); 579 580 for (int i = 0; i < item_list_length && index < font_length; i++) { 581 glyphs = f.get_glyph_collection_index ((uint32) index); 582 return_if_fail (glyphs != null); 583 584 glyph = ((!) glyphs).get_current (); 585 character_string = glyph.name; 586 character = glyph.unichar_code; 587 588 item = new OverViewItem (); 589 item.set_character (character); 590 item.set_glyphs (glyphs); 591 item.x = x; 592 item.y = y; 593 visible_items.add (item); 594 index++; 595 } 596 } else { 597 uint32 glyph_range_size = glyph_range.get_length (); 598 599 uint max_length = glyph_range.length () - first_visible; 600 601 if (item_list_length > max_length) { 602 item_list_length = (int) max_length; 603 } 604 605 for (int i = 0; i < item_list_length && index < glyph_range_size; i++) { 606 item = new OverViewItem (); 607 visible_items.add (item); 608 } 609 610 index = (uint32) first_visible; 611 visible_size = visible_items.size; 612 for (int i = 0; i < visible_size; i++) { 613 item = visible_items.get (i); 614 character = glyph_range.get_character ((uint32) index); 615 item.set_character (character); 616 index++; 617 } 618 619 visible_size = visible_items.size; 620 for (int i = 0; i < visible_size; i++) { 621 item = visible_items.get (i); 622 glyphs = f.get_glyph_collection_by_name ((!) item.character.to_string ()); 623 item.set_glyphs (glyphs); 624 } 625 } 626 627 x = OverViewItem.margin; 628 y = OverViewItem.margin; 629 630 visible_size = visible_items.size; 631 int selected_index; 632 bool selected_item; 633 double full_width = OverViewItem.full_width (); 634 635 for (int i = 0; i < visible_size; i++) { 636 item = visible_items.get (i); 637 638 selected_item = false; 639 640 if (all_available) { 641 glyphs = f.get_glyph_collection_index ((uint32) i); 642 } else { 643 glyphs = f.get_glyph_collection_by_name ((!) item.character.to_string ()); 644 } 645 646 if (glyphs != null) { 647 selected_index = selected_items.index_of ((!) glyphs); 648 selected_item = (selected_index != -1); 649 } 650 651 selected_item |= (i == selected); 652 item.selected = selected_item; 653 654 item.x = x + view_offset_x; 655 item.y = y + view_offset_y; 656 657 x += full_width; 658 659 if (x + full_width >= tab_with) { 660 x = OverViewItem.margin; 661 y += OverViewItem.full_height (); 662 } 663 } 664 665 update_scheduled = false; 666 } 667 668 public override void draw (WidgetAllocation allocation, Context cr) { 669 if (update_scheduled 670 || this.allocation.width != allocation.width 671 || this.allocation.height != allocation.height 672 || this.allocation.width == 0) { 673 this.allocation = allocation; 674 process_item_list_update (); 675 } 676 677 this.allocation = allocation; 678 679 // clear canvas 680 cr.save (); 681 Theme.color (cr, "Background 1"); 682 cr.rectangle (0, 0, allocation.width, allocation.height); 683 cr.fill (); 684 cr.restore (); 685 686 foreach (OverViewItem i in visible_items) { 687 i.draw (allocation, cr); 688 } 689 690 if (unlikely (visible_items.size == 0)) { 691 draw_empty_canvas (allocation, cr); 692 } 693 694 if (unlikely (character_info != null)) { 695 draw_character_info (cr); 696 } 697 } 698 699 void draw_empty_canvas (WidgetAllocation allocation, Context cr) { 700 Text t; 701 702 cr.save (); 703 t = new Text (t_("No glyphs in this view."), 24); 704 Theme.text_color (t, "Text Foreground"); 705 t.widget_x = 40; 706 t.widget_y = 30; 707 t.draw (cr); 708 cr.restore (); 709 } 710 711 public void scroll_rows (int row_adjustment) { 712 for (int i = 0; i < row_adjustment; i++) { 713 scroll (-OverViewItem.height); 714 } 715 716 for (int i = 0; i > row_adjustment; i--) { 717 scroll (OverViewItem.height); 718 } 719 } 720 721 public void scroll_adjustment (double pixel_adjustment) { 722 double l; 723 Font f; 724 725 if (all_available) { 726 f = BirdFont.get_current_font (); 727 l = f.length (); 728 } else { 729 l = glyph_range.length (); 730 } 731 732 if (first_visible <= 0) { 733 return; 734 } 735 736 if (first_visible + rows * items_per_row >= l) { 737 return; 738 } 739 740 scroll ((int64) pixel_adjustment); 741 } 742 743 void scroll_to_position (int64 r) { 744 if (r < 0) { 745 scroll_top (); 746 return; 747 } 748 749 selected -= (int) (r - first_visible); 750 first_visible = (int) r; 751 update_item_list (); 752 } 753 754 public override void scroll_to (double position) requires (items_per_row > 0) { 755 double r; 756 int nrows; 757 Font f; 758 759 if (all_available) { 760 f = BirdFont.get_current_font (); 761 nrows = (int) (f.length () / items_per_row); 762 } else { 763 nrows = (int) (glyph_range.length () / items_per_row); 764 } 765 766 view_offset_y = 0; 767 r = (int64) (position * (nrows - rows + 3)); // 3 invisible rows 768 r *= items_per_row; 769 770 scroll_to_position ((int64) r); 771 update_item_list (); 772 GlyphCanvas.redraw (); 773 } 774 775 private void scroll (double pixel_adjustment) { 776 if (first_visible < 0 && pixel_adjustment < 0) { 777 scroll_top (); 778 return; 779 } 780 781 view_offset_y += pixel_adjustment; 782 783 if (view_offset_y >= 0) { 784 while (view_offset_y > OverViewItem.height) { 785 view_offset_y -= OverViewItem.height; 786 first_visible -= items_per_row; 787 } 788 789 first_visible -= items_per_row; 790 view_offset_y -= OverViewItem.height; 791 } else if (view_offset_y < -OverViewItem.height) { 792 view_offset_y = 0; 793 first_visible += items_per_row; 794 } 795 796 update_item_list (); 797 } 798 799 public void scroll_top () { 800 first_visible = 0; 801 view_offset_y = 0; 802 803 update_item_list (); 804 805 if (visible_items.size != 0) { 806 selected_item = get_selected_item (); 807 } 808 } 809 810 /** Returns true if the selected glyph is at the last row. */ 811 private bool last_row () { 812 return visible_items.size - selected <= items_per_row; 813 } 814 815 public void key_down () { 816 Font f = BirdFont.get_current_font (); 817 int64 len = (all_available) ? f.length () : glyph_range.length (); 818 819 if (at_bottom () && last_row ()) { 820 return; 821 } 822 823 selected += items_per_row; 824 825 if (selected >= items_per_row * rows) { 826 first_visible += items_per_row; 827 selected -= items_per_row; 828 } 829 830 if (first_visible + selected >= len) { 831 selected = (int) (len - first_visible - 1); 832 833 if (selected < items_per_row * (rows - 1)) { 834 first_visible -= items_per_row; 835 selected += items_per_row; 836 } 837 } 838 839 if (selected >= visible_items.size) { 840 selected = (int) (visible_items.size - 1); 841 } 842 843 selected_item = get_selected_item (); 844 update_item_list (); 845 } 846 847 public void key_right () { 848 Font f = BirdFont.get_current_font (); 849 int64 len = (all_available) ? f.length () : glyph_range.length (); 850 851 if (at_bottom () && first_visible + selected + 1 >= len) { 852 selected = (int) (visible_items.size - 1); 853 selected_item = get_selected_item (); 854 return; 855 } 856 857 selected += 1; 858 859 if (selected >= items_per_row * rows) { 860 first_visible += items_per_row; 861 selected -= items_per_row; 862 selected -= 1; 863 } 864 865 if (first_visible + selected > len) { 866 first_visible -= items_per_row; 867 selected = (int) (len - first_visible - 1); 868 selected_item = get_selected_item (); 869 } 870 update_item_list (); 871 } 872 873 public void key_up () { 874 selected -= items_per_row; 875 876 if (selected < 0) { 877 first_visible -= items_per_row; 878 selected += items_per_row; 879 } 880 881 if (first_visible < 0) { 882 first_visible = 0; 883 } 884 update_item_list (); 885 } 886 887 public void key_left () { 888 selected -= 1; 889 890 if (selected < 0) { 891 first_visible -= items_per_row; 892 selected += items_per_row; 893 selected += 1; 894 } 895 896 if (first_visible < 0) { 897 scroll_top (); 898 } 899 update_item_list (); 900 } 901 902 public string get_selected_char () { 903 Font f; 904 Glyph? g; 905 906 if (all_available) { 907 f = BirdFont.get_current_font (); 908 g = f.get_glyph_index (selected); 909 return_val_if_fail (g != null, "".dup ()); 910 return ((!) g).get_name (); 911 } 912 913 return glyph_range.get_char (selected); 914 } 915 916 public override void key_press (uint keyval) { 917 hide_menu (); 918 update_item_list (); 919 GlyphCanvas.redraw (); 920 921 if (KeyBindings.has_ctrl () || KeyBindings.has_logo ()) { 922 return; 923 } 924 925 switch (keyval) { 926 case Key.ENTER: 927 open_current_glyph (); 928 return; 929 930 case Key.UP: 931 get_selected_item ().selected = false; 932 933 key_up (); 934 selected_item = get_selected_item (); 935 936 selected_items.clear (); 937 if (selected_item.glyphs != null) { 938 selected_items.add ((!) selected_item.glyphs); 939 } 940 941 update_scrollbar (); 942 return; 943 944 case Key.RIGHT: 945 get_selected_item ().selected = false; 946 947 key_right (); 948 selected_item = get_selected_item (); 949 950 selected_items.clear (); 951 if (selected_item.glyphs != null) { 952 selected_items.add ((!) selected_item.glyphs); 953 } 954 955 update_scrollbar (); 956 return; 957 958 case Key.LEFT: 959 get_selected_item ().selected = false; 960 961 key_left (); 962 selected_item = get_selected_item (); 963 964 selected_items.clear (); 965 if (selected_item.glyphs != null) { 966 selected_items.add ((!) selected_item.glyphs); 967 } 968 969 update_scrollbar(); 970 return; 971 972 case Key.DOWN: 973 get_selected_item ().selected = false; 974 975 key_down (); 976 selected_item = get_selected_item (); 977 978 selected_items.clear (); 979 if (selected_item.glyphs != null) { 980 selected_items.add ((!) selected_item.glyphs); 981 } 982 983 update_scrollbar (); 984 return; 985 986 case Key.PG_UP: 987 get_selected_item ().selected = false; 988 989 for (int i = 0; i < rows; i++) { 990 key_up (); 991 } 992 selected_item = get_selected_item (); 993 994 selected_items.clear (); 995 if (selected_item.glyphs != null) { 996 selected_items.add ((!) selected_item.glyphs); 997 } 998 999 update_scrollbar (); 1000 return; 1001 1002 case Key.PG_DOWN: 1003 get_selected_item ().selected = false; 1004 1005 for (int i = 0; i < rows; i++) { 1006 key_down (); 1007 } 1008 selected_item = get_selected_item (); 1009 1010 selected_items.clear (); 1011 if (selected_item.glyphs != null) { 1012 selected_items.add ((!) selected_item.glyphs); 1013 } 1014 1015 update_scrollbar (); 1016 return; 1017 1018 case Key.DEL: 1019 delete_selected_glyph (); 1020 selected_item = get_selected_item (); 1021 return; 1022 1023 case Key.BACK_SPACE: 1024 delete_selected_glyph (); 1025 selected_item = get_selected_item (); 1026 return; 1027 } 1028 1029 if (!KeyBindings.has_ctrl () && !KeyBindings.has_logo ()) { 1030 scroll_to_char (keyval); 1031 } 1032 1033 selected_item = get_selected_item (); 1034 1035 selected_items.clear (); 1036 if (selected_item.glyphs != null) { 1037 selected_items.add ((!) selected_item.glyphs); 1038 } 1039 1040 update_item_list (); 1041 GlyphCanvas.redraw (); 1042 } 1043 1044 public void delete_selected_glyph () { 1045 Font font = BirdFont.get_current_font (); 1046 OverViewUndoItem undo_item = new OverViewUndoItem (); 1047 1048 undo_item.alternate_sets = font.alternates.copy (); 1049 1050 foreach (GlyphCollection g in selected_items) { 1051 undo_item.glyphs.add (g.copy ()); 1052 } 1053 store_undo_items (undo_item); 1054 1055 foreach (GlyphCollection glyph_collection in selected_items) { 1056 font.delete_glyph (glyph_collection); 1057 string name = glyph_collection.get_name (); 1058 MainWindow.get_tab_bar ().close_background_tab_by_name (name); 1059 } 1060 1061 update_item_list (); 1062 GlyphCanvas.redraw (); 1063 } 1064 1065 public override void undo () { 1066 Font font = BirdFont.get_current_font (); 1067 OverViewUndoItem previous_collection; 1068 1069 if (undo_items.size == 0) { 1070 return; 1071 } 1072 1073 previous_collection = undo_items.get (undo_items.size - 1); 1074 redo_items.add (get_current_state (previous_collection)); 1075 1076 // remove the old glyph and add the new one 1077 foreach (GlyphCollection g in previous_collection.glyphs) { 1078 font.delete_glyph (g); 1079 1080 if (g.length () > 0) { 1081 font.add_glyph_collection (g); 1082 } 1083 1084 TabBar tabs = MainWindow.get_tab_bar (); 1085 Tab? tab = tabs.get_tab (g.get_name ()); 1086 1087 if (tab != null) { 1088 Tab t = (!) tab; 1089 set_glyph_zoom (g); 1090 t.set_glyph_collection (g); 1091 t.set_display (new GlyphTab (g)); 1092 } 1093 } 1094 1095 Font f = BirdFont.get_current_font (); 1096 f.alternates = previous_collection.alternate_sets.copy (); 1097 1098 undo_items.remove_at (undo_items.size - 1); 1099 update_item_list (); 1100 GlyphCanvas.redraw (); 1101 } 1102 1103 public override void redo () { 1104 Font font = BirdFont.get_current_font (); 1105 OverViewUndoItem previous_collection; 1106 1107 if (redo_items.size == 0) { 1108 return; 1109 } 1110 1111 previous_collection = redo_items.get (redo_items.size - 1); 1112 undo_items.add (get_current_state (previous_collection)); 1113 1114 // remove the old glyph and add the new one 1115 foreach (GlyphCollection g in previous_collection.glyphs) { 1116 font.delete_glyph (g); 1117 font.add_glyph_collection (g); 1118 1119 TabBar tabs = MainWindow.get_tab_bar (); 1120 Tab? tab = tabs.get_tab (g.get_name ()); 1121 1122 if (tab != null) { 1123 Tab t = (!) tab; 1124 set_glyph_zoom (g); 1125 t.set_glyph_collection (g); 1126 t.set_display (new GlyphTab (g)); 1127 } 1128 } 1129 font.alternates = previous_collection.alternate_sets.copy (); 1130 1131 redo_items.remove_at (redo_items.size - 1); 1132 GlyphCanvas.redraw (); 1133 } 1134 1135 public OverViewUndoItem get_current_state (OverViewUndoItem previous_collection) { 1136 GlyphCollection? gc; 1137 OverViewUndoItem ui = new OverViewUndoItem (); 1138 Font font = BirdFont.get_current_font (); 1139 1140 ui.alternate_sets = font.alternates.copy (); 1141 1142 foreach (GlyphCollection g in previous_collection.glyphs) { 1143 gc = font.get_glyph_collection (g.get_name ()); 1144 1145 if (gc != null) { 1146 ui.glyphs.add (((!) gc).copy ()); 1147 } else { 1148 ui.glyphs.add (new GlyphCollection (g.get_unicode_character (), g.get_name ())); 1149 } 1150 } 1151 1152 return ui; 1153 } 1154 1155 public void store_undo_state (GlyphCollection gc) { 1156 OverViewUndoItem i = new OverViewUndoItem (); 1157 Font f = BirdFont.get_current_font (); 1158 i.alternate_sets = f.alternates.copy (); 1159 i.glyphs.add (gc); 1160 store_undo_items (i); 1161 } 1162 1163 public void store_undo_items (OverViewUndoItem i) { 1164 undo_items.add (i); 1165 redo_items.clear (); 1166 } 1167 1168 bool select_visible_glyph (string name) { 1169 int i = 0; 1170 1171 foreach (OverViewItem o in visible_items) { 1172 if (o.get_name () == name) { 1173 selected = i; 1174 selected_item = get_selected_item (); 1175 1176 if (selected_item.y > allocation.height - OverViewItem.height) { 1177 view_offset_y -= (selected_item.y + OverViewItem.height) - allocation.height; 1178 } 1179 1180 if (selected_item.y < 0) { 1181 view_offset_y = 0; 1182 } 1183 1184 return true; 1185 } 1186 1187 if (i > 1000) { 1188 warning ("selected character not found"); 1189 return true; 1190 } 1191 1192 i++; 1193 } 1194 1195 return false; 1196 } 1197 1198 public void scroll_to_char (unichar c) { 1199 StringBuilder s = new StringBuilder (); 1200 1201 if (is_modifier_key (c)) { 1202 return; 1203 } 1204 1205 s.append_unichar (c); 1206 scroll_to_glyph (s.str); 1207 } 1208 1209 public void scroll_to_glyph (string name) { 1210 GlyphRange gr = glyph_range; 1211 int i, r, index; 1212 string ch; 1213 Font font = BirdFont.get_current_font (); 1214 GlyphCollection? glyphs = null; 1215 Glyph glyph; 1216 1217 index = -1; 1218 1219 if (items_per_row <= 0) { 1220 return; 1221 } 1222 1223 ch = name; 1224 1225 // selected char is visible 1226 if (select_visible_glyph (ch)) { 1227 return; 1228 } 1229 1230 // scroll to char 1231 if (all_available) { 1232 1233 // don't search for glyphs in huge CJK fonts 1234 if (font.length () > 500) { 1235 r = 0; 1236 } else { 1237 // FIXME: too slow 1238 for (r = 0; r < font.length (); r += items_per_row) { 1239 for (i = 0; i < items_per_row && i < font.length (); i++) { 1240 glyphs = font.get_glyph_collection_index ((uint32) r + i); 1241 return_if_fail (glyphs != null); 1242 glyph = ((!) glyphs).get_current (); 1243 1244 if (glyph.name == ch) { 1245 index = i; 1246 } 1247 } 1248 1249 if (index > -1) { 1250 break; 1251 } 1252 } 1253 } 1254 } else { 1255 1256 if (ch.char_count () > 1) { 1257 warning ("Can't scroll to ligature in this view"); 1258 return; 1259 } 1260 1261 for (r = 0; r < gr.length (); r += items_per_row) { 1262 for (i = 0; i < items_per_row; i++) { 1263 if (gr.get_char (r + i) == ch) { 1264 index = i; 1265 } 1266 } 1267 1268 if (index > -1) { 1269 break; 1270 } 1271 } 1272 } 1273 1274 if (index > -1) { 1275 first_visible = r; 1276 process_item_list_update (); 1277 update_item_list (); 1278 select_visible_glyph (ch); 1279 } 1280 } 1281 1282 public override void double_click (uint button, double ex, double ey) 1283 requires (!is_null (visible_items) && !is_null (allocation)) { 1284 1285 return_if_fail (!is_null (this)); 1286 1287 foreach (OverViewItem i in visible_items) { 1288 if (i.double_click (button, ex, ey)) { 1289 open_overview_item (i); 1290 } 1291 } 1292 1293 GlyphCanvas.redraw (); 1294 } 1295 1296 public void open_overview_item (OverViewItem i) { 1297 return_if_fail (!is_null (i)); 1298 1299 if (i.glyphs != null) { 1300 open_glyph_signal ((!) i.glyphs); 1301 GlyphCollection gc = (!) i.glyphs; 1302 gc.get_current ().close_path (); 1303 } else { 1304 open_new_glyph_signal (i.character); 1305 } 1306 } 1307 1308 public void set_character_info (CharacterInfo i) { 1309 character_info = i; 1310 } 1311 1312 public int get_selected_index () { 1313 GlyphCollection gc; 1314 int index = 0; 1315 1316 if (selected_items.size == 0) { 1317 return 0; 1318 } 1319 1320 gc = selected_items.get (0); 1321 1322 foreach (OverViewItem i in visible_items) { 1323 if (i.glyphs != null && gc == ((!) i.glyphs)) { 1324 break; 1325 } 1326 1327 index++; 1328 } 1329 1330 return index; 1331 } 1332 1333 public void hide_menu () { 1334 foreach (OverViewItem i in visible_items) { 1335 i.hide_menu (); 1336 } 1337 } 1338 1339 public override void button_press (uint button, double x, double y) { 1340 OverViewItem i; 1341 int index = 0; 1342 int selected_index = -1; 1343 bool update = false; 1344 1345 if (character_info != null) { 1346 character_info = null; 1347 GlyphCanvas.redraw (); 1348 return; 1349 } 1350 1351 if (!KeyBindings.has_shift ()) { 1352 selected_items.clear (); 1353 } 1354 1355 for (int j = 0; j < visible_items.size; j++) { 1356 i = visible_items.get (j); 1357 1358 if (i.click (button, x, y)) { 1359 selected = index; 1360 selected_item = get_selected_item (); 1361 1362 if (KeyBindings.has_shift ()) { 1363 if (selected_item.glyphs != null) { 1364 1365 selected_index = selected_items.index_of ((!) selected_item.glyphs); 1366 if (selected_index == -1) { 1367 selected_items.add ((!) selected_item.glyphs); 1368 } else { 1369 return_if_fail (0 <= selected_index < selected_items.size); 1370 selected_items.remove_at (selected_index); 1371 selected = get_selected_index (); 1372 selected_item = get_selected_item (); 1373 } 1374 } 1375 } else { 1376 selected_items.clear (); 1377 if (selected_item.glyphs != null) { 1378 selected_items.add ((!) selected_item.glyphs); 1379 } 1380 } 1381 1382 if (!is_null (i.version_menu)) { 1383 update = !((!)i).version_menu.menu_visible; 1384 } else { 1385 update = true; 1386 } 1387 } 1388 index++; 1389 } 1390 1391 if (update) { 1392 update_item_list (); 1393 } 1394 1395 GlyphCanvas.redraw (); 1396 } 1397 1398 /** Returns true if overview shows the last character. */ 1399 private bool at_bottom () { 1400 Font f; 1401 double t = rows * items_per_row + first_visible; 1402 1403 if (all_available) { 1404 f = BirdFont.get_current_font (); 1405 return t >= f.length (); 1406 } 1407 1408 return t >= glyph_range.length (); 1409 } 1410 1411 public void set_current_glyph_range (GlyphRange range) { 1412 GlyphRange? current = glyph_range; 1413 string c; 1414 1415 if (current != null) { 1416 c = glyph_range.get_char (selected); 1417 } 1418 1419 all_available = false; 1420 1421 glyph_range = range; 1422 scroll_top (); 1423 1424 // TODO: scroll down to c 1425 update_item_list (); 1426 selected_item = get_selected_item (); 1427 1428 GlyphCanvas.redraw (); 1429 } 1430 1431 public void select_next_glyph () { 1432 key_right (); 1433 } 1434 1435 public void open_current_glyph () { 1436 // keep this object even if open_glyph_signal closes the display 1437 this.ref (); 1438 1439 selected_item = get_selected_item (); 1440 if (selected_item.glyphs != null) { 1441 open_glyph_signal ((!) selected_item.glyphs); 1442 GlyphCollection? gc2 = selected_item.glyphs; 1443 GlyphCollection gc = (!) selected_item.glyphs; 1444 gc.get_current ().close_path (); 1445 } else { 1446 open_new_glyph_signal (selected_item.character); 1447 } 1448 1449 this.unref (); 1450 } 1451 1452 public override void update_scrollbar () { 1453 Font f; 1454 double nrows = 0; 1455 double pos = 0; 1456 double size; 1457 double visible_rows; 1458 1459 if (rows == 0) { 1460 MainWindow.set_scrollbar_size (0); 1461 MainWindow.set_scrollbar_position (0); 1462 } else { 1463 if (all_available) { 1464 f = BirdFont.get_current_font (); 1465 nrows = Math.floor ((f.length ()) / rows); 1466 size = f.length (); 1467 } else { 1468 nrows = Math.floor ((glyph_range.length ()) / rows); 1469 size = glyph_range.length (); 1470 } 1471 1472 if (nrows <= 0) { 1473 nrows = 1; 1474 } 1475 1476 visible_rows = allocation.height / OverViewItem.height; 1477 scroll_size = visible_rows / nrows; 1478 MainWindow.set_scrollbar_size (scroll_size); 1479 pos = first_visible / (nrows * items_per_row - visible_rows * items_per_row); 1480 MainWindow.set_scrollbar_position (pos); 1481 } 1482 } 1483 1484 /** Display one entry from the Unicode Character Database. */ 1485 void draw_character_info (Context cr) 1486 requires (character_info != null) { 1487 double x, y, w, h; 1488 int i; 1489 string unicode_value, unicode_description; 1490 string[] column; 1491 string entry; 1492 int len = 0; 1493 int length = 0; 1494 bool see_also = false; 1495 WidgetAllocation allocation = MainWindow.get_overview ().allocation; 1496 string name; 1497 string[] lines; 1498 double character_start; 1499 double character_height; 1500 1501 entry = ((!)character_info).get_entry (); 1502 1503 lines = entry.split ("\n"); 1504 1505 foreach (string line in entry.split ("\n")) { 1506 len = line.char_count (); 1507 if (len > length) { 1508 length = len; 1509 } 1510 } 1511 1512 x = allocation.width * 0.1; 1513 y = allocation.height * 0.1; 1514 w = allocation.width * 0.9 - x; 1515 h = allocation.height * 0.9 - y; 1516 1517 if (w < 8 * length) { 1518 w = 8 * length; 1519 x = (allocation.width - w) / 2.0; 1520 } 1521 1522 if (x < 0) { 1523 x = 2; 1524 } 1525 1526 // background 1527 cr.save (); 1528 Theme.color_opacity (cr, "Background 1", 0.98); 1529 cr.rectangle (x, y, w, h); 1530 cr.fill (); 1531 cr.restore (); 1532 1533 cr.save (); 1534 Theme.color_opacity (cr, "Foreground 1", 0.98); 1535 cr.set_line_width (2); 1536 cr.rectangle (x, y, w, h); 1537 cr.stroke (); 1538 cr.restore (); 1539 1540 // database entry 1541 1542 if (((!)character_info).is_ligature ()) { 1543 name = ((!)character_info).get_name (); 1544 draw_info_line (name, cr, x, y, 0); 1545 } else { 1546 i = 0; 1547 foreach (string line in lines) { 1548 if (i == 0) { 1549 column = line.split ("\t"); 1550 return_if_fail (column.length == 2); 1551 unicode_value = "U+" + column[0]; 1552 unicode_description = column[1]; 1553 1554 draw_info_line (unicode_description, cr, x, y, i); 1555 i++; 1556 1557 draw_info_line (unicode_value, cr, x, y, i); 1558 i++; 1559 } else { 1560 1561 if (line.has_prefix ("\t*")) { 1562 draw_info_line (line.replace ("\t*", "•"), cr, x, y, i); 1563 i++; 1564 } else if (line.has_prefix ("\tx (")) { 1565 if (!see_also) { 1566 i++; 1567 draw_info_line (t_("See also:"), cr, x, y, i); 1568 i++; 1569 see_also = true; 1570 } 1571 1572 draw_info_line (line.replace ("\tx (", "•").replace (")", ""), cr, x, y, i); 1573 i++; 1574 } else { 1575 i++; 1576 } 1577 } 1578 } 1579 1580 character_start = y + 10 + i * UCD_LINE_HEIGHT; 1581 character_height = h - character_start; 1582 1583 draw_fallback_character (cr, x, character_start, character_height); 1584 } 1585 } 1586 1587 /** Fallback character in UCD info. */ 1588 void draw_fallback_character (Context cr, double x, double y, double height) 1589 requires (character_info != null) { 1590 unichar c = ((!)character_info).unicode; 1591 1592 if (height < 0) { 1593 return; 1594 } 1595 1596 cr.save (); 1597 Text character = new Text (); 1598 character.set_use_cache (false); 1599 Theme.text_color (character, "Foreground 1"); 1600 character.set_text ((!) c.to_string ()); 1601 character.set_font_size (height); 1602 character.draw_at_top (cr, x + 10, y); 1603 cr.restore (); 1604 } 1605 1606 void draw_info_line (string line, Context cr, double x, double y, int row) { 1607 Text ucd_entry = new Text (line); 1608 cr.save (); 1609 Theme.text_color (ucd_entry, "Foreground 1"); 1610 ucd_entry.widget_x = 10 + x; 1611 ucd_entry.widget_y = 10 + y + row * UCD_LINE_HEIGHT; 1612 ucd_entry.draw (cr); 1613 cr.restore (); 1614 } 1615 1616 public void paste () { 1617 GlyphCollection gc; 1618 GlyphCollection? c; 1619 Glyph glyph; 1620 uint32 index; 1621 int i; 1622 int skip = 0; 1623 int s; 1624 string character_string; 1625 Gee.ArrayList<GlyphCollection> glyps; 1626 Font f; 1627 OverViewUndoItem undo_item; 1628 1629 f = BirdFont.get_current_font (); 1630 gc = new GlyphCollection ('\0', ""); 1631 glyps = new Gee.ArrayList<GlyphCollection> (); 1632 1633 copied_glyphs.sort ((a, b) => { 1634 return (int) ((GlyphCollection) a).get_unicode_character () 1635 - (int) ((GlyphCollection) b).get_unicode_character (); 1636 }); 1637 1638 index = (uint32) first_visible + selected; 1639 for (i = 0; i < copied_glyphs.size; i++) { 1640 if (all_available) { 1641 if (f.length () == 0) { 1642 c = add_empty_character_to_font (copied_glyphs.get (i).get_unicode_character (), 1643 copied_glyphs.get (i).is_unassigned (), 1644 copied_glyphs.get (i).get_name ()); 1645 } else if (index >= f.length ()) { 1646 // FIXME: duplicated unicodes? 1647 c = add_empty_character_to_font (copied_glyphs.get (i).get_unicode_character (), 1648 copied_glyphs.get (i).is_unassigned (), 1649 copied_glyphs.get (i).get_name ()); 1650 } else { 1651 c = f.get_glyph_collection_index ((uint32) index); 1652 } 1653 1654 if (c == null) { 1655 c = add_empty_character_to_font (copied_glyphs.get (i).get_unicode_character (), 1656 copied_glyphs.get (i).is_unassigned (), 1657 copied_glyphs.get (i).get_name ()); 1658 } 1659 1660 return_if_fail (c != null); 1661 gc = (!) c; 1662 } else { 1663 if (i != 0) { 1664 s = (int) copied_glyphs.get (i).get_unicode_character (); 1665 s -= (int) copied_glyphs.get (i - 1).get_unicode_character (); 1666 s -= 1; 1667 skip += s; 1668 } 1669 1670 character_string = glyph_range.get_char ((uint32) (index + skip)); 1671 c = f.get_glyph_collection_by_name (character_string); 1672 1673 if (c == null) { 1674 gc = add_empty_character_to_font (character_string.get_char (), 1675 copied_glyphs.get (i).is_unassigned (), 1676 copied_glyphs.get (i).get_name ()); 1677 } else { 1678 gc = (!) c; 1679 } 1680 } 1681 1682 glyps.add (gc); 1683 index++; 1684 } 1685 1686 undo_item = new OverViewUndoItem (); 1687 undo_item.alternate_sets = f.alternates.copy (); 1688 foreach (GlyphCollection g in glyps) { 1689 undo_item.glyphs.add (g.copy ()); 1690 } 1691 store_undo_items (undo_item); 1692 1693 if (glyps.size != copied_glyphs.size) { 1694 warning ("glyps.size != copied_glyphs.size"); 1695 return; 1696 } 1697 1698 if (copied_glyphs.size < i) { 1699 warning ("Array index out of bounds."); 1700 return; 1701 } 1702 1703 i = 0; 1704 foreach (GlyphCollection g in glyps) { 1705 glyph = copied_glyphs.get (i).get_current ().copy (); 1706 glyph.version_id = (glyph.version_id == -1 || g.length () == 0) ? 1 : g.get_last_id () + 1; 1707 glyph.unichar_code = g.get_unicode_character (); 1708 1709 if (!g.is_unassigned ()) { 1710 glyph.name = (!) glyph.unichar_code.to_string (); 1711 } else { 1712 glyph.name = g.get_name (); 1713 } 1714 1715 g.insert_glyph (glyph, true); 1716 i++; 1717 } 1718 1719 f.touch (); 1720 1721 update_item_list (); 1722 GlyphCanvas.redraw (); 1723 } 1724 1725 public override bool needs_modifier () { 1726 return true; 1727 } 1728 1729 public class OverViewUndoItem { 1730 public AlternateSets alternate_sets = new AlternateSets (); 1731 public Gee.ArrayList<GlyphCollection> glyphs = new Gee.ArrayList<GlyphCollection> (); 1732 } 1733 } 1734 1735 } 1736