Commit 8061186
Merge branch 'master' of github.com:johanmattssonm/birdfont
Changed files (7)
modifiedlibbirdfont/BirdFont.valamodifiedlibbirdfont/FileDialogTab.valamodifiedlibbirdfont/GlyphRange.valamodifiedlibbirdfont/LabelTool.valamodifiedlibbirdfont/MainWindow.valamodifiedlibbirdfont/OverView.valamodifiedlibbirdfont/OverViewItem.vala
Diff
@@ -259,7 +259,7 @@ public class BirdFont { if (has_argument ("--codepages")) { codepage_bits = new CodePageBits (); codepage_bits.generate_codepage_database ();- }+ } } public static bool has_logging () {@@ -225,7 +225,12 @@ public class FileDialogTab : Table { if (selected_filename == "") { action.cancel (); } else {- f = get_child (current_dir, selected_filename);+ if (selected_filename.index_of (":\\") != -1) {+ f = File.new_for_path (selected_filename);+ } else {+ f = get_child (current_dir, selected_filename);+ }+ action.file_selected ((!)f.get_path ()); } });@@ -1,5 +1,5 @@ /*- Copyright (C) 2012 2014 Johan Mattsson+ Copyright (C) 2012 2014 2015 Johan Mattsson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -26,6 +26,9 @@ public class GlyphRange { uint32 len = 0; bool range_is_class = false;+ uint32* range_index = null;+ int index_size = 0;+ int index_hint = 0; public GlyphRange () { ranges = new Gee.ArrayList<UniRange> ();@@ -33,6 +36,30 @@ public class GlyphRange { name = "No name"; } + ~GlyphRange () {+ if (range_index != null) {+ delete range_index;+ }+ }+ + private void generate_unirange_index () {+ if (range_index != null) {+ delete range_index;+ }+ + index_size = ranges.size;+ range_index = new uint32[index_size];+ + int i = 0;+ uint32 next_index = 0;+ + foreach (UniRange range in ranges) {+ range_index[i] = next_index;+ next_index += (uint32) range.length ();+ i++;+ }+ }+ public void add_unassigned (string glyph_name) { unassigned.add (glyph_name); }@@ -53,13 +80,14 @@ public class GlyphRange { unassigned.clear (); ranges.clear (); len = 0;+ generate_unirange_index (); } public unowned Gee.ArrayList<UniRange> get_ranges () { return ranges; } - // TODO: complete localized alphabetical sort åäö is not the right order for example.+ // sort by unicode value public void sort () { ranges.sort ((a, b) => { UniRange first, next;@@ -73,6 +101,8 @@ public class GlyphRange { return (r) ? 1 : -1; });+ + generate_unirange_index (); } public void add_single (unichar c) {@@ -122,6 +152,8 @@ public class GlyphRange { } } }+ + generate_unirange_index (); } /** Parse ranges on the form a-z. Single characters can be added as well as @@ -131,6 +163,7 @@ public class GlyphRange { */ public void parse_ranges (string ranges) throws MarkupError { parse_range_string (ranges);+ generate_unirange_index (); } private void parse_range_string (string ranges) throws MarkupError {@@ -200,11 +233,11 @@ public class GlyphRange { first = false; }+ return s.str; } public static string serialize (string s) {- if (s == "space") { return s; }@@ -351,7 +384,7 @@ public class GlyphRange { private void append_range (unichar start, unichar stop) { UniRange r; r = insert_range (start, stop); // insert a unique range- merge_range (r); // join connecting ranges+ merge_range (r); } private void merge_range (UniRange r) {@@ -393,50 +426,105 @@ public class GlyphRange { merge_range (r); } }+ + /** Find a range which containd index. */+ private void get_unirange_index (uint32 index, out UniRange? range, out uint32 range_start_index) {+ int lower = 0;+ int upper = index_size - 1;+ int i;+ int end = index_size - 1;+ + if (index_hint >= 0 && index_hint < index_size) {+ i = index_hint;+ } else {+ i = (lower + upper) / 2;+ }+ + range_start_index = -1;+ range = null;+ + if (unlikely (ranges.size != index_size)) {+ warning (@"Range size does not match index size: $(ranges.size) != $index_size");+ }+ + while (true) {+ if (i == end) {+ range_start_index = range_index[i];+ range = ranges.get (i);+ index_hint = i;+ break;+ } else if (range_index[i] <= index && range_index[i + 1] > index) {+ range_start_index = range_index[i];+ range = ranges.get (i);+ index_hint = i;+ break;+ }+ + if (lower >= upper) {+ break;+ } + if (range_index[i] < index) {+ lower = i + 1;+ } else {+ upper = i - 1;+ }+ + i = (lower + upper) / 2;+ }+ }+ public string get_char (uint32 index) {+ StringBuilder sb;+ + sb = new StringBuilder ();+ sb.append_unichar (get_character (index));+ + return sb.str;+ }+ + public unichar get_character (uint32 index) { int64 ti; string chr; UniRange r;- StringBuilder sb; unichar c; + UniRange? range;+ uint32 range_start_index; - if (index > len + unassigned.size) {- return "\0".dup();+ if (unlikely (index > len + unassigned.size)) {+ return '\0'; } if (index >= len) {- if (index - len >= unassigned.size) {- return "\0".dup();+ if (unlikely (index - len >= unassigned.size)) {+ return '\0'; } chr = unassigned.get ((int) (index - len));- return chr;+ return chr.get_char (); }-- r = ranges.get (0);- ti = index;-- foreach (UniRange u in ranges) {- ti -= u.length ();- - if (ti < 0) {- r = u;- break;- }+ + get_unirange_index (index, out range, out range_start_index);+ + if (unlikely (range == null)) {+ warning (@"No range found for index $index");+ return '\0';+ } + + if (unlikely (range_start_index > index || range_start_index == -1)) {+ warning ("Index out of bounds in glyph range.");+ return '\0'; }- - sb = new StringBuilder ();- c = r.get_char ((unichar) (ti + r.length ()));+ + r = (!) range;+ c = r.get_char ((unichar) (index - range_start_index)); if (unlikely (!c.validate ())) { warning ("Not a valid unicode character.");- return "";+ return '\0'; } - sb.append_unichar (c);- - return sb.str;+ return c; } public uint32 length () {@@ -24,11 +24,24 @@ public class LabelTool : Tool { } set {+ clear_cache (); label_text.set_text (value); } } - public string number { get; set; }+ public string number {+ get {+ return counter_number;+ }+ + set {+ clear_cache ();+ counter_number = value;+ } + }+ + string counter_number = "";+ public bool has_counter { get; set; } public bool has_delete_button { get; set; } public signal void delete_action (LabelTool self);@@ -39,6 +52,9 @@ public class LabelTool : Tool { Text label_text; + Surface? selected_cache = null;+ Surface? deselected_cache = null;+ public LabelTool (string label) { double text_height; @@ -62,18 +78,58 @@ public class LabelTool : Tool { } }); }++ void clear_cache () {+ selected_cache = null;+ deselected_cache = null;+ } public override void draw_tool (Context cr, double px, double py) {+ double x = this.x - px;+ double y = this.y - py;+ + if (is_selected ()) {+ + if (selected_cache == null) {+ selected_cache = Screen.create_background_surface ((int) w, (int) h + 2);+ Context c = new Context ((!) selected_cache);+ c.scale (1 / Screen.get_scale (), 1 / Screen.get_scale ());+ draw_tool_surface (c, x, 2, true);+ }+ + cr.save ();+ cr.set_antialias (Cairo.Antialias.NONE);+ cr.set_source_surface ((!) selected_cache, 0, (int) y - 2);+ cr.paint ();+ cr.restore ();+ } else {+ + if (deselected_cache == null) {+ deselected_cache = Screen.create_background_surface ((int) w, (int) h + 2);+ Context c = new Context ((!) deselected_cache);+ c.scale (1 / Screen.get_scale (), 1 / Screen.get_scale ());+ draw_tool_surface (c, x, 2, false);+ }+ + cr.save ();+ cr.set_antialias (Cairo.Antialias.NONE);+ cr.set_source_surface ((!) deselected_cache, 0, (int) y - 2);+ cr.paint ();+ cr.restore ();+ }+ }+ + public void draw_tool_surface (Context cr, double px, double py, bool selected) { Text glyph_count; double bgx, bgy; double center_x, center_y;- double x = this.x - px;- double y = this.y - py; double text_height; double text_width;+ double x = px;+ double y = py; // background- if (is_selected ()) {+ if (selected) { cr.save (); Theme.color (cr, "Menu Background"); cr.rectangle (0, y - 2 * Toolbox.get_scale (), w, h); // labels overlap with 2 pixels@@ -84,11 +140,7 @@ public class LabelTool : Tool { // tab label cr.save (); - if (is_selected ()) {- Theme.text_color (label_text, "Text Tool Box");- } else {- Theme.text_color (label_text, "Text Tool Box");- }+ Theme.text_color (label_text, "Text Tool Box"); text_width = Toolbox.allocation_width; @@ -101,7 +153,6 @@ public class LabelTool : Tool { } label_text.truncate (text_width);- label_text.draw_at_top (cr, x, y); cr.restore (); @@ -170,6 +170,7 @@ public class MainWindow : GLib.Object { public void set_native (NativeWindow nw) { native_window = nw; + OverViewItem.start_thumbnail_processing (); } public static FontDisplay get_current_display () { @@ -20,7 +20,7 @@ namespace BirdFont { public class OverView : FontDisplay { public WidgetAllocation allocation = new WidgetAllocation (); - public OverViewItem selected_item = new OverViewItem (null, '\0', 0, 0);+ public OverViewItem selected_item = new OverViewItem (); public Gee.ArrayList<GlyphCollection> copied_glyphs = new Gee.ArrayList<GlyphCollection> (); public Gee.ArrayList<GlyphCollection> selected_items = new Gee.ArrayList<GlyphCollection> (); @@ -76,6 +76,8 @@ public class OverView : FontDisplay { double scroll_size = 1; const double UCD_LINE_HEIGHT = 17 * 1.3; + private bool update_scheduled = true;+ public OverView (GlyphRange? range = null, bool open_selected = true, bool default_character_set = true) { @@ -488,7 +490,7 @@ public class OverView : FontDisplay { OverViewItem get_selected_item () { if (visible_items.size == 0) {- return new OverViewItem (null, '\0', 0, 0);+ return new OverViewItem (); } if (!(0 <= selected < visible_items.size)) { @@ -512,7 +514,11 @@ public class OverView : FontDisplay { return i - 1; } - public void update_item_list (int item_list_length = -1) {+ public void update_item_list () {+ update_scheduled = true;+ }+ + public void process_item_list_update () { string character_string; Font f = BirdFont.get_current_font (); GlyphCollection? glyphs = null;@@ -522,80 +528,132 @@ public class OverView : FontDisplay { unichar character; Glyph glyph; double tab_with;+ int item_list_length;+ int visible_size;+ + Test test = new Test.time("update_item_list"); - tab_with = allocation.width - 30; // scrollbar+ tab_with = allocation.width - 30; // scrollbar items_per_row = get_items_per_row (); rows = (int) (allocation.height / OverViewItem.full_height ()) + 2; - if (item_list_length == -1) {- item_list_length = items_per_row * rows;+ item_list_length = items_per_row * rows;++ foreach (OverViewItem overview_item in visible_items) {+ overview_item.cancel_thumbnail_rendering (); } visible_items.clear ();- visible_items = new Gee.ArrayList<OverViewItem> ();- - // update item list+ Test test3 = new Test.time("two conditions");+ index = (uint32) first_visible; x = OverViewItem.margin; y = OverViewItem.margin;- for (int i = 0; i < item_list_length; i++) {- if (all_available) {- if (! (0 <= index < f.length ())) {- break;- }- + + if (all_available) {+ uint font_length = f.length ();+ + for (int i = 0; i < item_list_length && index < font_length; i++) { glyphs = f.get_glyph_collection_index ((uint32) index); return_if_fail (glyphs != null); glyph = ((!) glyphs).get_current (); character_string = glyph.name; character = glyph.unichar_code;- } else {- if (!(0 <= index < glyph_range.get_length ())) {- break;- } - character_string = glyph_range.get_char ((uint32) index);- glyphs = f.get_glyph_collection_by_name (character_string);- character = character_string.get_char (0);+ item = new OverViewItem ();+ item.set_glyphs (glyphs);+ item.set_character (character);+ item.x = x;+ item.y = y;+ visible_items.add (item);+ index++; }+ } else {++ Test test_mk = new Test.time("mk items");+ uint32 glyph_range_size = glyph_range.get_length (); - item = new OverViewItem (glyphs, character, x, y);- item.adjust_scale ();- - x += OverViewItem.full_width ();+ for (int i = 0; i < item_list_length && index < glyph_range_size; i++) { + item = new OverViewItem ();+ visible_items.add (item);+ }+ warning (test_mk.get_test_time ()); - if (x + OverViewItem.full_width () >= tab_with) {- x = OverViewItem.margin;- y += OverViewItem.full_height ();+ Test test_gl = new Test.time("get_glyph");+ visible_size = visible_items.size;+ for (int i = 0; i < visible_size; i++) {+ item = visible_items.get (i);+ glyphs = f.get_glyph_collection_by_name ((!) item.character.to_string ());+ item.set_glyphs (glyphs); }+ warning (test_gl.get_test_time ());++ Test test_a = new Test.time("get_char"); - item.selected = (i == selected);+ visible_size = visible_items.size;+ for (int i = 0; i < visible_size; i++) {+ item = visible_items.get (i);+ character = glyph_range.get_character ((uint32) index);+ item.set_character (character);+ index++;+ }+ warning (test_a.get_test_time ());+ }+ + Test test_b = new Test.time("adjust pos");+ x = OverViewItem.margin;+ y = OverViewItem.margin;+ + visible_size = visible_items.size;+ int selected_index;+ bool selected_item;+ double full_width = OverViewItem.full_width ();+ + for (int i = 0; i < visible_size; i++) {+ item = visible_items.get (i);++ selected_item = false; if (glyphs != null) {- item.selected |= selected_items.index_of ((!) glyphs) != -1;+ selected_index = selected_items.index_of ((!) glyphs);+ selected_item = (selected_index != -1); } - visible_items.add (item);- index++;+ item.adjust_scale ();+ + selected_item |= (i == selected);+ item.selected = selected_item;+ + item.x = x + view_offset_y;+ item.y = y + view_offset_x;+ + x += full_width;+ + if (x + full_width >= tab_with) {+ x = OverViewItem.margin;+ y += OverViewItem.full_height ();+ } }- - foreach (OverViewItem i in visible_items) {- i.y += view_offset_y;- i.x += view_offset_x;- } + + warning (test_b.get_test_time ());+ + warning (test3.get_test_time ());+ warning (test.get_test_time ());+ update_scheduled = false; } public override void draw (WidgetAllocation allocation, Context cr) {- - if (this.allocation.width != allocation.width+ if (update_scheduled+ || this.allocation.width != allocation.width || this.allocation.height != allocation.height || this.allocation.width == 0) { this.allocation = allocation;- update_item_list ();+ process_item_list_update (); } + Test test = new Test.time("Overview.draw"); this.allocation = allocation; // clear canvas@@ -616,6 +674,8 @@ public class OverView : FontDisplay { if (unlikely (character_info != null)) { draw_character_info (cr); }+ + warning (test.get_test_time ()); } void draw_empty_canvas (WidgetAllocation allocation, Context cr) {@@ -38,22 +38,41 @@ public class OverViewItem : GLib.Object { public VersionList version_menu; Text label; + private Surface? cache = null;+ public static Surface? label_background = null; public static Surface? selected_label_background = null; public static Surface? label_background_no_menu = null; public static Surface? selected_label_background_no_menu = null; - public OverViewItem (GlyphCollection? glyphs, unichar character, double x, double y) { - this.x = x;- this.y = y;- this.character = character;- this.glyphs = glyphs;- this.info = new CharacterInfo (character, glyphs); + private static Task thumbnail_task;+ private static Gee.PriorityQueue<OverViewItem> thumbnail_queue;+ private static Cond has_thumnail_task = new Cond ();+ private static Mutex thumbnail_mutex = new Mutex ();+ + private bool cancel_thumbnail = false;+ + public OverViewItem () { + } - label = new Text ((!) character.to_string (), 17); - truncate_label ();- - if (glyphs != null) {+ public void set_character (unichar character) {+ this.character = character;+ info = new CharacterInfo (character, glyphs);+ + if (glyphs == null) {+ label = new Text ();+ } else {+ label = new Text ((!) character.to_string (), 17); + truncate_label ();+ }+ + draw_background ();+ }+ + public void set_glyphs (GlyphCollection? gc) {+ glyphs = gc;+ + if (glyphs != null) { version_menu = new VersionList ((!) glyphs); version_menu.add_glyph_item.connect ((glyph) => { ((!) glyphs).insert_glyph (glyph, true);@@ -65,8 +84,144 @@ public class OverViewItem : GLib.Object { v.update_item_list (); GlyphCanvas.redraw (); });+ } ++/*+ thumbnail_mutex.lock ();+ if (!is_null (thumbnail_queue)) {+ thumbnail_queue.offer (this);+ has_thumnail_task.signal ();+ }+ thumbnail_mutex.unlock ();+*/+ }++ public static void start_thumbnail_processing () {+ //thumbnail_task = new Task (process_thumbnails, true);+ thumbnail_queue = new Gee.PriorityQueue<OverViewItem> (); + //MainWindow.native_window.run_non_blocking_background_thread (thumbnail_task);+ }++ public void cancel_thumbnail_rendering () {+ thumbnail_mutex.lock ();+ cancel_thumbnail = true;+ thumbnail_mutex.unlock ();+ }++ private static void process_thumbnails () {+ bool cancel = false;+ + while (!thumbnail_task.is_cancelled ()) {+ OverViewItem item;+ + thumbnail_mutex.lock ();+ item = thumbnail_queue.poll ();+ thumbnail_mutex.unlock ();+ + if (!is_null (item)) {+ thumbnail_mutex.lock ();+ cancel = item.cancel_thumbnail;+ thumbnail_mutex.unlock ();+ + if (!cancel) {+ item.draw_background ();+ }+ } else {+ thumbnail_mutex.lock ();+ has_thumnail_task.wait (thumbnail_mutex);+ thumbnail_mutex.unlock ();+ }+ }+ }++ public void draw_glyph_from_font () {+ if (glyphs == null) {+ return;+ }++ Glyph g;+ Font font;+ double gx, gy;+ double x1, x2, y1, y2;+ double scale_box;+ double w, h;+ double glyph_width, glyph_height;+ Surface s;+ Context c;+ Color color = Color.black ();+ + w = width;+ h = height;+ + scale_box = width / DEFAULT_WIDTH;++ s = Screen.create_background_surface ((int) width, (int) height - 20);+ c = new Context (s);+ + g = ((!) glyphs).get_current ();+ + c.save ();+ g.boundaries (out x1, out y1, out x2, out y2);+ + glyph_width = x2 - x1;+ glyph_height = y2 - y1;+ + c.save ();+ c.scale (glyph_scale * Screen.get_scale (), glyph_scale * Screen.get_scale ());++ g.add_help_lines ();+ + gx = ((w / glyph_scale) - glyph_width) / 2 - g.get_left_side_bearing ();+ gy = (h / glyph_scale) - 25 / glyph_scale;+ + c.translate (gx - Glyph.xc () - g.get_lsb (), g.get_baseline () + gy - Glyph.yc ());+ + g.draw_paths (c, color);+ c.restore ();+ + cache = s;+ GlyphCanvas.redraw ();+ }++ public void draw_background () {+ Glyph g;+ Font font;+ double gx, gy;+ double x1, x2, y1, y2;+ double scale_box;+ double w, h;+ double glyph_width, glyph_height;+ Surface s;+ Context c;+ Color color = Color.black ();+ + w = width;+ h = height;+ + scale_box = width / DEFAULT_WIDTH;++ s = Screen.create_background_surface ((int) width, (int) height - 20);+ c = new Context (s);+ + if (glyphs != null) { // FIXME: lock+ draw_glyph_from_font (); } else {- version_menu = new VersionList (new GlyphCollection (character, (!) character.to_string ()));+ c.scale (Screen.get_scale (), Screen.get_scale ());+ + c.save ();+ Text fallback = new Text ();+ fallback.set_use_cache (false);+ Theme.text_color (fallback, "Overview Glyph");+ fallback.set_text ((!) character.to_string ());+ double font_size = height * 0.8;+ fallback.set_font_size (font_size);+ gx = (width - fallback.get_extent ()) / 2.0;+ gy = height - 30;+ fallback.draw_at_baseline (c, gx, gy);+ c.restore ();+ + cache = s;+ GlyphCanvas.redraw (); } } @@ -143,7 +298,7 @@ public class OverViewItem : GLib.Object { if (!is_on_screen (allocation)) { return; }- + cr.save (); Theme.color (cr, "Background 1"); cr.rectangle (x, y, width, height);@@ -157,9 +312,10 @@ public class OverViewItem : GLib.Object { cr.stroke (); cr.restore (); - draw_thumbnail (cr, glyphs, x, y + height); draw_caption (cr); draw_menu (cr);+ + draw_thumbnail (cr, x, y + height); } public void adjust_scale () {@@ -189,72 +345,15 @@ public class OverViewItem : GLib.Object { } } - private void draw_thumbnail (Context cr, GlyphCollection? gl, double x, double y) {- Glyph g;- Font font;- double gx, gy;- double x1, x2, y1, y2;- double scale_box;- double w, h;- double glyph_width, glyph_height;- Surface s;- Context c;- Color color = Color.black ();- - w = width;- h = height;- - scale_box = width / DEFAULT_WIDTH;-- s = Screen.create_background_surface ((int) width, (int) height - 20);- c = new Context (s);- - if (gl != null) {- font = BirdFont.get_current_font ();- g = ((!) gl).get_interpolated_fast (OverviewTools.current_master_size);-- c.save ();- g.boundaries (out x1, out y1, out x2, out y2);- - glyph_width = x2 - x1;- glyph_height = y2 - y1;- - c.save ();- c.scale (glyph_scale * Screen.get_scale (), glyph_scale * Screen.get_scale ());-- g.add_help_lines ();- - gx = ((w / glyph_scale) - glyph_width) / 2 - g.get_left_side_bearing ();- gy = (h / glyph_scale) - 25 / glyph_scale;- - c.translate (gx - Glyph.xc () - g.get_lsb (), g.get_baseline () + gy - Glyph.yc ());- - g.draw_paths (c, color);- c.restore ();- } else {- c.scale (Screen.get_scale (), Screen.get_scale ());- - c.save ();- Text fallback = new Text ();- fallback.set_use_cache (false);- Theme.text_color (fallback, "Overview Glyph");- fallback.set_text ((!) character.to_string ());- double font_size = height * 0.8;- fallback.set_font_size (font_size);-- gx = (width - fallback.get_extent ()) / 2.0;- gy = height - 30;- fallback.set_font_size (font_size);- fallback.draw_at_baseline (c, gx, gy);- c.restore ();+ private void draw_thumbnail (Context cr, double x, double y) { + if (cache != null) {+ cr.save ();+ cr.set_antialias (Cairo.Antialias.NONE);+ cr.scale (1 / Screen.get_scale (), 1 / Screen.get_scale ()); + cr.set_source_surface ((!) cache, (int) (x * Screen.get_scale ()), (int) ((y - height)) * Screen.get_scale ());+ cr.paint ();+ cr.restore (); }- - cr.save ();- cr.set_antialias (Cairo.Antialias.NONE);- cr.scale (1 / Screen.get_scale (), 1 / Screen.get_scale ()); - cr.set_source_surface (s, (int) (x * Screen.get_scale ()), (int) ((y - h)) * Screen.get_scale ());- cr.paint ();- cr.restore (); } public bool has_icons () {@@ -321,7 +420,7 @@ public class OverViewItem : GLib.Object { selected_label_background = (!) cache; - // unselected item without menu icon+ // deselected item without menu icon cache = Screen.create_background_surface ((int) width, 20); cc = new Context (cache); cc.scale(Screen.get_scale(), Screen.get_scale());