Commit 77aaf39
Get descriptions from the Unicode Character Database
Changed files (6)
modifiedicons/next_tab.pngmodifiedlibbirdfont/CharDatabase.valaaddedlibbirdfont/CharacterInfo.valamodifiedlibbirdfont/GlyphCollection.valamodifiedlibbirdfont/GlyphRange.valamodifiedlibbirdfont/OverView.vala
Diff
Binary files a/icons/next_tab.png and b/icons/next_tab.png differ@@ -58,6 +58,169 @@ class CharDatabase { return false; } + public static string get_unicode_database_entry (unichar c) {+ FileInputStream fin;+ DataInputStream din;+ string? line;+ string data;+ string hex_char;+ string description = "";+ File file;+ + file = (!) File.new_for_path ("/usr/share/unicode/NamesList.txt"); // FIXME+ hex_char = Font.to_hex (c).replace ("U+", "");+ + if (hex_char.char_count () == 2) {+ hex_char = "00" + hex_char;+ }+ + if (hex_char.char_count () == 6 && hex_char.has_prefix ("0")) {+ hex_char = hex_char.substring (1);+ }+ + hex_char += "\t";+ hex_char = hex_char.up ();+ + try {+ fin = file.read ();+ din = new DataInputStream (fin);+ + while ((line = din.read_line (null)) != null) {+ data = (!) line;+ if (data.has_prefix (hex_char)) {+ description = data;+ + while ((line = din.read_line (null)) != null) {+ data = (!) line;+ if (data.has_prefix ("\t")) {+ description += "\n";+ description += data;+ } else {+ break;+ }+ }+ + break;+ }+ }+ + if (description == "") {+ warning ("no description found");+ }+ + fin.close ();+ din.close ();+ } catch (GLib.Error e) {+ warning (e.message);+ }+ + return description; + }+ + public static void get_full_unicode (GlyphRange glyph_range) {+ File file;+ FileInputStream fin;+ DataInputStream din;+ DataOutputStream os;+ string? line;+ string data;+ string[] range;+ + try { + file = BirdFont.get_settings_directory ().get_child ("full_unicode_range");+ + if (file.query_exists ()) {+ // read cached glyph ranges+ fin = file.read ();+ din = new DataInputStream (fin);+ while ((line = din.read_line (null)) != null) {+ data = (!) line;+ + if (data == "") {+ break;+ }+ + range = data.split (" - ");+ return_if_fail (range.length == 2);+ + glyph_range.add_range (Font.to_unichar ("U+" + range[0]), Font.to_unichar ("U+" + range[1]));+ }+ fin.close ();+ din.close (); + } else {+ parse_full_unicode_database (glyph_range);+ + // write cache+ os = new DataOutputStream(file.create (FileCreateFlags.REPLACE_DESTINATION));+ os.put_string (glyph_range.get_all_ranges ());+ os.close ();+ }+ } catch (GLib.Error e) {+ warning (e.message);+ }+ }+ + /** Obtain full unicode range from unicode database. */+ public static void parse_full_unicode_database (GlyphRange glyph_range) {+ FileInputStream fin;+ DataInputStream din;+ string? line;+ string data;+ string hex_char;+ File file;+ unichar ch;+ + file = get_unicode_database ();+ + if (!file.query_exists ()) {+ warning ("Can not find unicode database.");+ return;+ }++ try {+ fin = file.read ();+ din = new DataInputStream (fin);+ + while ((line = din.read_line (null)) != null) {+ data = (!) line;+ + if (data.has_prefix ("\t") || data.has_prefix (";") || data.has_prefix ("@")) {+ continue;+ }+ + if (data.index_of ("<not a character>") != -1) {+ continue;+ }+ + hex_char = "U+" + data.substring (0, data.index_of ("\t")).down ();+ + ch = Font.to_unichar (hex_char);+ glyph_range.add_single (ch);+ }+ + fin.close ();+ din.close ();+ } catch (GLib.Error e) {+ warning (e.message);+ } + }+ + static File get_unicode_database () {+ File f;++ f = (!) File.new_for_path (PREFIX + "/share/unicode/NamesList.txt");+ if (f.query_exists ()) {+ return f;+ }+ + f = (!) File.new_for_path (".\\NamesList.txt");+ if (f.query_exists ()) {+ return f;+ }+ + f = (!) File.new_for_path ("/usr/share/unicode/NamesList.txt");+ return f;+ } } }new file mode 100644@@ -0,0 +1,66 @@+/*+ Copyright (C) 2013 Johan Mattsson++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.+*/++using Cairo;++namespace BirdFont {++/** Display functions for a unicode character database entry. */+public class CharacterInfo : GLib.Object {++ static ImageSurface? info_icon = null;+ double x = 0;+ double y = 0;+ unichar unicode;+ + public CharacterInfo (unichar c) {+ unicode = c;+ + if (info_icon == null) {+ info_icon = Icons.get_icon ("info_icon.png");+ }+ }+ + public string get_entry () {+ return CharDatabase.get_unicode_database_entry (unicode);+ }+ + public void set_position (double x, double y) {+ this.x = x;+ this.y = y;+ }+ + public bool is_over_icon (double px, double py) {+ return (x <= px <= x + 12) && (y <= py <= y + 12);+ }+ + public void draw_icon (Context cr) { + ImageSurface i = (!) info_icon;+ + // info icon + if (likely (info_icon != null && i.status () == Cairo.Status.SUCCESS)) {+ cr.save ();+ cr.set_source_surface (i, x, y);+ cr.paint ();+ cr.restore ();+ } else {+ warning ("Failed to load icon.");+ } + }+}++}@@ -22,11 +22,11 @@ namespace BirdFont { public class GlyphCollection : GLib.Object { VersionList versions;- + public GlyphCollection (Glyph? current = null) { versions = new VersionList (current); }- + public VersionList get_version_list () { return versions; }@@ -175,16 +175,18 @@ public class GlyphRange { } public void use_full_unicode_range () {- add_range ('\0', (unichar) 0xFFF8);+ CharDatabase.get_full_unicode (this);+ + if (len == 0) {+ add_range ('\0', (unichar) 0xFFF8);+ } } // Todo: complete localized alphabetical sort åäö is the right order for example. public void sort () { ranges.sort ((a, b) => { bool r = a.start > b.start;- return_val_if_fail (a.start != b.start, 0);- return (r) ? 1 : -1; }); }@@ -240,9 +242,9 @@ public class GlyphRange { private void append_range (unichar start, unichar stop) { UniRange r;- StringBuilder s = new StringBuilder (); StringBuilder e = new StringBuilder ();+ s.append_unichar (start); e.append_unichar (stop); @@ -345,17 +347,19 @@ public class GlyphRange { } public void print_all () {- StringBuilder s;- stdout.printf ("Ranges:\n");+ stdout.printf (get_all_ranges ());+ }+ + public string get_all_ranges () {+ StringBuilder s = new StringBuilder (); foreach (UniRange u in ranges) {- s = new StringBuilder ();- s.append_unichar (u.start);+ s.append (Font.to_hex_code (u.start)); s.append (" - ");- s.append_unichar (u.stop);+ s.append (Font.to_hex_code (u.stop)); s.append ("\n");- stdout.printf (s.str); }+ return s.str; } } @@ -48,12 +48,16 @@ public class OverView : FontDisplay { int zoom_list_index = 0; List<GlyphCollection> deleted_glyphs = new List<GlyphCollection> ();+ List<CharacterInfo> unicode_database_info = new List<CharacterInfo> (); bool all_available = true; + /** Show unicode database info. */+ CharacterInfo? character_info = null;+ public OverView (GlyphRange? range = null) { GlyphRange gr;- + if (range == null) { gr = new GlyphRange (); set_glyph_range (gr);@@ -92,6 +96,8 @@ public class OverView : FontDisplay { g.close_path (); g.default_zoom (); z.store_current_view ();+ + print (@"CHARDB: $(CharDatabase.get_unicode_database_entry (new_char))\n"); } }); @@ -330,11 +336,12 @@ public class OverView : FontDisplay { cr.set_line_join (LineJoin.ROUND); cr.set_line_width(12); - cr.rectangle (x, y + nail_height - 20, nail_width - 30, 10); + cr.rectangle (x, y + nail_height - 20, nail_width - 20, 10); cr.stroke (); cr.restore (); draw_menu (cr, character_string, x, y);+ draw_character_info_icon (cr, character_string, x, y); caption_y = y + 10 + nail_height - 20; @@ -348,9 +355,27 @@ public class OverView : FontDisplay { cr.stroke(); }+ + private void draw_character_info_icon (Context cr, string character_string, double x, double y) {+ double px = x + nail_width - 40;+ double py = y + nail_height - 21;+ CharacterInfo info;+ unichar c = character_string.get_char ();+ + if (character_string.char_count () > 1) {+ warning ("Ligature - not a character");+ c = '\0';+ } + info = new CharacterInfo (c);+ unicode_database_info.append (info);+ info.set_position (px, py);+ info.draw_icon (cr);+ }+ private void draw_menu (Context cr, string name, double x, double y) {- GlyphCollection? gl = BirdFont.get_current_font ().get_glyph_collection (name);+ Font font = BirdFont.get_current_font ();+ GlyphCollection? gl = font.get_glyph_collection (name); GlyphCollection g; DropMenu menu; @@ -361,7 +386,7 @@ public class OverView : FontDisplay { g = (!) gl; menu = g.get_version_list ();- menu.set_position (x + nail_width - 40, y + nail_height - 21);+ menu.set_position (x + nail_width - 55, y + nail_height - 21); menu.draw_icon (cr); menu.draw_menu (cr); @@ -421,7 +446,11 @@ public class OverView : FontDisplay { int i; int n_items; Font font = BirdFont.get_current_font ();- + + while (unicode_database_info.length () > 0) {+ unicode_database_info.remove_link (unicode_database_info.first ());+ }+ while (visible_characters.length () > 9) { visible_characters.remove_link (visible_characters.first ()); }@@ -438,8 +467,8 @@ public class OverView : FontDisplay { draw_empty_canvas (allocation, cr); } - n_items = ((allocation.width - 40) / nail_width);- rows = (allocation.height / nail_height);+ n_items = allocation.width / nail_width;+ rows = allocation.height / nail_height; if (items_per_row != n_items) { if (items_per_row == 0) {@@ -454,10 +483,10 @@ public class OverView : FontDisplay { } } - width = nail_width * items_per_row;+ width = (nail_width - 5) * items_per_row; view_offset_x = (allocation.width - width) / 2.0; - cr.translate(view_offset_x, view_offset_y);+ cr.translate (view_offset_x, view_offset_y); y = 0; t = first_visible;@@ -470,8 +499,104 @@ public class OverView : FontDisplay { i++; } + cr.restore (); // restore translation+ + if (character_info != null) {+ draw_character_info (allocation, cr, (!) character_info);+ } } + void draw_character_info (Allocation allocation, Context cr, CharacterInfo info) {+ double x, y, w, h;+ int i;+ string unicode_value, unicode_description;+ string[] column;+ string entry = info.get_entry ();+ int len = 0;+ int length = 0;+ bool see_also = false;+ + foreach (string line in entry.split ("\n")) {+ len = line.char_count ();+ if (len > length) {+ length = len;+ }+ }+ + x = allocation.width * 0.1 - view_offset_x;+ y = allocation.height * 0.1 - view_offset_y;+ w = allocation.width * 0.9 - x - view_offset_x; + h = allocation.height * 0.9 - y - view_offset_y;+ + if (w < 8 * length) {+ w = 8 * length;+ if (w > allocation.width - view_offset_x) {+ x = -view_offset_x;+ } else {+ x = (allocation.width - view_offset_x- w) / 2.0;+ }+ }+ + // background + cr.save ();+ cr.set_source_rgba (1, 1, 1, 0.7);+ cr.rectangle (x, y, w, h);+ cr.fill ();+ cr.restore ();++ cr.save ();+ cr.set_source_rgba (0, 0, 0, 0.7);+ cr.set_line_width (2);+ cr.rectangle (x, y, w, h);+ cr.stroke ();+ cr.restore ();++ // database entry+ i = 0;+ foreach (string line in entry.split ("\n")) {+ if (i == 0) {+ column = line.split ("\t");+ return_if_fail (column.length == 2);+ unicode_value = "U+" + column[0];+ unicode_description = column[1];++ draw_line (unicode_description, cr, x, y, i);+ i++;++ draw_line (unicode_value, cr, x, y, i);+ i++; + } else {+ + if (line.has_prefix ("\t*")) {+ draw_line (line.replace ("\t*", "•"), cr, x, y, i);+ i++; + } else if (line.has_prefix ("\tx (")) {+ if (!see_also) {+ i++;+ draw_line (_("See also:"), cr, x, y, i);+ i++;+ see_also = true;+ }+ + draw_line (line.replace ("\tx (", "•").replace (")", ""), cr, x, y, i);+ i++;+ } else {++ i++;+ }+ }+ }+ }+ + void draw_line (string line, Context cr, double x, double y, int row) {+ cr.save ();+ cr.set_font_size (12);+ cr.set_source_rgba (0, 0, 0, 1);+ cr.move_to (x + 10, y + 28 + row * 18 * 1.2);+ cr.show_text (line);+ cr.restore (); + }+ void draw_empty_canvas (Allocation allocation, Context cr) { cr.save (); cr.set_source_rgba (156/255.0, 156/255.0, 156/255.0, 1);@@ -594,7 +719,10 @@ public class OverView : FontDisplay { private int selected_offset_y (unichar item) { int64 di; int64 a, b;- if (unlikely (items_per_row == 0)) return 0;+ + if (unlikely (items_per_row == 0)) {+ return 0;+ } a = (int64) item; b = (int64) first_visible;@@ -848,7 +976,8 @@ public class OverView : FontDisplay { private void selection_click (uint button, double ex, double ey) { double x = view_offset_x; double y = view_offset_y;-+ double px, py;+ // click in margin int n_items = (allocation.width - 40 / nail_width); double m = (allocation.width - 40 - (n_items * nail_width)) / 2.0;@@ -867,21 +996,30 @@ public class OverView : FontDisplay { len = glyph_range.length (); } + px = ex - view_offset_x;+ py = ey - view_offset_y; foreach (GlyphCollection g in get_visible_glyphs ()) { bool a;-- a = g.get_version_list ().menu_item_action (ex - view_offset_x, ey - view_offset_y); // select one item on the menu+ + a = g.get_version_list ().menu_item_action (px, py); // select one item on the menu if (a) { return; } - a = g.get_version_list ().menu_icon_action (ex - view_offset_x, ey - view_offset_y); // open menu+ a = g.get_version_list ().menu_icon_action (px, py); // open menu if (a) { menu_action = true; } }++ character_info = null;+ foreach (CharacterInfo info in unicode_database_info) {+ if (info.is_over_icon (px, py)) {+ character_info = info;+ }+ } if (ex < m) { ex = m + 1;