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