Commit 8202ce2
Customizable key bindings
Changed files (12)
modifiedlibbirdfont/Expander.valamodifiedlibbirdfont/KeyBindings.valamodifiedlibbirdfont/Menu.valamodifiedlibbirdfont/MenuItem.valamodifiedlibbirdfont/Renderer/Text.valamodifiedlibbirdfont/SettingsDisplay.valaaddedlibbirdfont/SettingsItem.valamodifiedlibbirdfont/TabContent.valamodifiedlibbirdfont/Tool.valaaddedlibbirdfont/ToolItem.valamodifiedlibbirdfont/Toolbox.valamodifiedlibbirdxml/Xml.vala
Diff
@@ -81,7 +81,7 @@ public class Expander : GLib.Object { unique = u; } - private void update_tool_position () {+ public void update_tool_position () { double scale = Toolbox.get_scale (); double margin_small = 5 * scale; double xt = x;@@ -103,7 +103,7 @@ public class KeyBindings { require_modifier = t; } - private static uint get_mod_from_key (uint keyval) {+ public static uint get_mod_from_key (uint keyval) { uint mod = 0; mod |= (keyval == Key.CTRL_RIGHT || keyval == Key.CTRL_LEFT) ? CTRL : 0; mod |= (keyval == Key.SHIFT_RIGHT || keyval == Key.SHIFT_LEFT) ? SHIFT : 0;@@ -50,6 +50,7 @@ public class Menu : GLib.Object { double height = 25 * MainWindow.units; public Gee.HashMap<string, MenuItem> menu_items = new Gee.HashMap<string, MenuItem> ();+ public Gee.ArrayList<MenuItem> sorted_menu_items = new Gee.ArrayList<MenuItem> (); public Menu () { SubMenu menu = new SubMenu ();@@ -420,7 +421,6 @@ public class Menu : GLib.Object { add_tool_key_bindings (); load_key_bindings ();- write_key_bindings (); } void load_key_bindings () {@@ -443,12 +443,7 @@ public class Menu : GLib.Object { try { FileUtils.get_contents((!) f.get_path (), out xml_data); parser = new XmlParser (xml_data);- - foreach (Tag tag in parser) {- if (tag.get_name () == "bindings") {- parse_bindings (tag);- }- }+ parse_bindings (parser.get_root_tag ()); } catch (GLib.Error e) { warning (e.message); }@@ -456,8 +451,8 @@ public class Menu : GLib.Object { void parse_bindings (Tag tag) { foreach (Tag t in tag) {- if (tag.get_name () == "action") {- parse_binding (tag.get_attributes ());+ if (t.get_name () == "action") {+ parse_binding (t.get_attributes ()); } } }@@ -496,7 +491,9 @@ public class Menu : GLib.Object { } ma = menu_items.get (action);- if (ma != null) {+ if (ma == null) {+ warning (@"No action for $action");+ } else { menu_action = (!) ma; menu_action.modifiers = modifier; menu_action.key = key;@@ -508,6 +505,7 @@ public class Menu : GLib.Object { if (description != "") { menu_items.set (description, i);+ sorted_menu_items.add (i); } return i;@@ -540,6 +538,7 @@ public class Menu : GLib.Object { tool_item = new ToolItem (t); if (tool_item.identifier != "") { menu_items.set (tool_item.identifier, tool_item);+ sorted_menu_items.add (tool_item); } } }@@ -635,19 +634,6 @@ public class Menu : GLib.Object { items = new Gee.ArrayList<MenuItem> (); } }- - public class ToolItem : MenuItem {- public ToolItem (Tool tool) {- base (tool.tip, tool.name);- - modifiers = tool.modifier_flag;- key = tool.key;- - action.connect (() => {- tool.select_action (tool);- });- }- } } }@@ -19,6 +19,8 @@ public class MenuItem : GLib.Object { public signal void action (); public Text label; public string identifier;++ public double y; // key bindings public uint modifiers = NONE;@@ -28,8 +30,37 @@ public class MenuItem : GLib.Object { this.label = new Text (); this.label.set_text (label); this.identifier = identifier;+ y = 0;+ }++ public string get_key_bindings () {+ string key_binding = "";+ + if (key != '\0') {+ key_binding += "(";+ + if ((modifiers & CTRL) > 0) {+ key_binding += "Ctrl+";+ }+ + if ((modifiers & ALT) > 0) {+ key_binding += "Alt+";+ }+ + if ((modifiers & LOGO) > 0) {+ key_binding += "Command+";+ }+ + if ((modifiers & SHIFT) > 0) {+ key_binding += "Shift+";+ }+ + key_binding += (!) key.to_string ();+ key_binding += ")";+ }+ + return key_binding; }- } }@@ -38,7 +38,7 @@ public class Text { FontCache font_cache; Font? current_font;- string text;+ public string text; GlyphSequence glyph_sequence; public delegate void Iterator (Glyph glyph, double kerning, bool last); @@ -25,13 +25,18 @@ public class SettingsDisplay : FontDisplay { Gee.ArrayList<SettingsItem> tools; public static SpinButton precision;- + + SettingsItem new_key_bindings = new SettingsItem.head_line ("");+ bool update_key_bindings = false;+ public SettingsDisplay () { allocation = new WidgetAllocation (); tools = new Gee.ArrayList<SettingsItem> (); content_height = 200; // setting items+ tools.add (new SettingsItem.head_line (t_("Settings")));+ ColorTool stroke_color = new ColorTool (); stroke_color.color_updated.connect (() => { Path.line_color_r = stroke_color.color_r;@@ -210,7 +215,12 @@ public class SettingsDisplay : FontDisplay { freehand_samples.new_value_action.connect ((self) => { DrawingTools.pen_tool.set_simplification_threshold (simplification_threshold.get_value ()); });-+ + tools.add (new SettingsItem.head_line (t_("Key Bindings")));+ + foreach (MenuItem menu_item in MainWindow.get_menu ().sorted_menu_items) {+ tools.add (new SettingsItem.key_binding (menu_item));+ } } public override void draw (WidgetAllocation allocation, Context cr) {@@ -228,40 +238,78 @@ public class SettingsDisplay : FontDisplay { cr.fill (); cr.stroke (); cr.restore ();-- // headline background- cr.save ();- cr.set_source_rgba (101 / 255.0, 108 / 255.0, 116 / 255.0, 1);- cr.rectangle (0, -scroll, allocation.width, 40 * MainWindow.units);- cr.fill ();- cr.restore ();- - cr.save ();- headline = new Text ();- headline.set_text (t_("Settings"));- cr.set_source_rgba (1, 1, 1, 1);- headline.draw (cr, 21 * MainWindow.units, 25 * MainWindow.units - scroll, 20 * MainWindow.units);- cr.restore (); foreach (SettingsItem s in tools) {- s.draw (allocation, cr);+ if (-20 * MainWindow.units <= s.y <= allocation.height + 20 * MainWindow.units) {+ s.draw (allocation, cr);+ } } } void layout () {- double y = 50 * MainWindow.units - scroll;+ double y = -scroll;+ bool first = true; foreach (SettingsItem s in tools) {+ + if (!first && s.headline) {+ y += 30 * MainWindow.units;+ }+ s.y = y;- y += 40 * MainWindow.units;+ + if (s.button != null) {+ ((!) s.button).y = y;+ ((!) s.button).x = 20 * MainWindow.units;+ }+ + if (s.headline) {+ y += 50 * MainWindow.units;+ } else {+ y += 40 * MainWindow.units;+ }+ + first = false; }+ content_height = y + scroll; } - public override void button_press (uint button, double x, double y) {+ void set_key_bindings (SettingsItem item) { + if (new_key_bindings.active) {+ new_key_bindings.active = false;+ update_key_bindings = false;+ } else { + new_key_bindings.active = false;+ new_key_bindings = item;+ update_key_bindings = true;+ new_key_bindings.active = true;+ }+ }++ public override void key_release (uint keyval) {+ if (update_key_bindings) {+ if (KeyBindings.get_mod_from_key (keyval) == 0) {+ new_key_bindings.menu_item.modifiers = KeyBindings.modifier;+ new_key_bindings.menu_item.key = (unichar) keyval;+ update_key_bindings = false;+ new_key_bindings.active = false;+ MainWindow.get_menu ().write_key_bindings ();+ GlyphCanvas.redraw ();+ }+ }+ }++ public override void button_press (uint button, double x, double y) { foreach (SettingsItem s in tools) {- if (s.button.is_over (x, y)) {- s.button.panel_press_action (s.button, button, x, y);- s.button.select_action (s.button);+ if (s.handle_events && s.button != null) {+ if (((!) s.button).is_over (x, y)) {+ ((!) s.button).panel_press_action ((!) s.button, button, x, y);+ ((!) s.button).set_selected (! ((!) s.button).selected);+ + if (((!) s.button).selected) {+ ((!) s.button).select_action ((!) s.button);+ }+ } } } GlyphCanvas.redraw ();@@ -269,8 +317,14 @@ public class SettingsDisplay : FontDisplay { public override void button_release (int button, double x, double y) { foreach (SettingsItem s in tools) {- if (s.button.is_over (x, y) || s.button.is_active ()) {- s.button.panel_release_action (s.button, button, x, y);+ if (s.handle_events && s.button != null) {+ if (((!) s.button).is_over (x, y) || ((!) s.button).is_active ()) {+ ((!) s.button).panel_release_action ((!) s.button, button, x, y);+ }+ }+ + if (s.key_bindings && s.y <= y < s.y + 40 * MainWindow.units && button == 1) {+ set_key_bindings (s); } } GlyphCanvas.redraw ();@@ -280,8 +334,10 @@ public class SettingsDisplay : FontDisplay { bool consumed = false; foreach (SettingsItem s in tools) {- if (s.button.panel_move_action (s.button, x, y)) {- consumed = true;+ if (s.handle_events && s.button != null) {+ if (((!) s.button).panel_move_action ((!) s.button, x, y)) {+ consumed = true;+ } } } @@ -305,13 +361,15 @@ public class SettingsDisplay : FontDisplay { public override void scroll_wheel_down (double x, double y) { foreach (SettingsItem s in tools) {- if (s.button.is_over (x, y)) {- s.button.scroll_wheel_down_action (s.button);- return;+ if (s.handle_events && s.button != null) {+ if (((!) s.button).is_over (x, y)) {+ ((!) s.button).scroll_wheel_down_action ((!) s.button);+ return;+ } } } - scroll += 15 * MainWindow.units;+ scroll += 25 * MainWindow.units; if (scroll + allocation.height >= content_height) { scroll = content_height - allocation.height;@@ -323,13 +381,15 @@ public class SettingsDisplay : FontDisplay { public override void scroll_wheel_up (double x, double y) { foreach (SettingsItem s in tools) {- if (s.button.is_over (x, y)) {- s.button.scroll_wheel_up_action (s.button);- return;+ if (s.handle_events && s.button != null) {+ if (((!) s.button).is_over (x, y)) {+ ((!) s.button).scroll_wheel_up_action ((!) s.button);+ return;+ } } } - scroll -= 15 * MainWindow.units;;+ scroll -= 25 * MainWindow.units; if (scroll < 0) { scroll = 0;@@ -340,6 +400,7 @@ public class SettingsDisplay : FontDisplay { } public override void selected_canvas () {+ MainWindow.get_toolbox ().set_default_tool_size (); update_scrollbar (); GlyphCanvas.redraw (); }@@ -355,32 +416,6 @@ public class SettingsDisplay : FontDisplay { scroll = percent * h; GlyphCanvas.redraw (); }- - class SettingsItem : GLib.Object {- - public double y;- public Tool button;- - Text label;- - public SettingsItem (Tool tool, string description) {- button = tool;- label = new Text ();- label.set_text (description);- y = 0;- }- - public void draw (WidgetAllocation allocation, Context cr) {- button.y = y;- button.x = 20 * MainWindow.units;- button.draw (cr);- - cr.save ();- cr.set_source_rgba (101 / 255.0, 108 / 255.0, 116 / 255.0, 1);- label.draw (cr, 60 * MainWindow.units, y + 20 * MainWindow.units, 17 * MainWindow.units);- cr.restore ();- }- } } }new file mode 100644@@ -0,0 +1,107 @@+/*+ Copyright (C) 2014 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 + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version.++ This library 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 + Lesser General Public License for more details.+*/++using Cairo;+using Math;++namespace BirdFont {++class SettingsItem : GLib.Object { + public bool handle_events;+ public bool key_bindings = false;+ public double y = 0;+ public Tool? button = null;+ public bool headline = false;+ public MenuItem menu_item = new MenuItem ("");+ public bool active = false;+ + Text label;+ + public SettingsItem (Tool tool, string description) {+ button = tool;+ label = new Text ();+ label.set_text (description);+ handle_events = true;+ }+ + public SettingsItem.key_binding (MenuItem item) {+ if (item is ToolItem) {+ button = ((ToolItem) item).tool;+ }+ + label = item.label;+ handle_events = false;+ key_bindings = true;+ menu_item = item;+ }+ + public SettingsItem.head_line (string label) {+ this.label = new Text ();+ this.label.set_text (label);+ + handle_events = false;+ headline = true;+ }+ + public void draw (WidgetAllocation allocation, Context cr) {+ Tool t;+ double label_x;+ + if (headline) {+ cr.save ();+ cr.set_source_rgba (101 / 255.0, 108 / 255.0, 116 / 255.0, 1);+ cr.rectangle (0, y, allocation.width, 40 * MainWindow.units);+ cr.fill ();+ cr.restore ();+ + cr.save ();+ cr.set_source_rgba (1, 1, 1, 1);+ label.draw (cr, 21 * MainWindow.units, y + 25 * MainWindow.units, 20 * MainWindow.units);+ cr.restore ();+ } else {+ if (active) {+ cr.save ();+ cr.set_source_rgba (38 / 255.0, 39 / 255.0, 43 / 255.0, 1);+ cr.rectangle (0, y - 5 * MainWindow.units, allocation.width, 40 * MainWindow.units);+ cr.fill ();+ cr.restore ();+ }+ + label_x = button != null ? 70 : 20;+ label_x *= MainWindow.units;+ + if (button != null) {+ t = (!) button;+ t.draw (cr);+ }+ + cr.save ();+ cr.set_source_rgba (101 / 255.0, 108 / 255.0, 116 / 255.0, 1);+ label.draw (cr, label_x, y + 20 * MainWindow.units, 17 * MainWindow.units);+ cr.restore ();+ + if (key_bindings) {+ Text key_binding_text = new Text ();+ key_binding_text.set_text (menu_item.get_key_bindings ());+ cr.save ();+ cr.set_source_rgba (101 / 255.0, 108 / 255.0, 116 / 255.0, 1);+ label_x += label.get_extent (17 * MainWindow.units) + 20 * MainWindow.units;+ key_binding_text.draw (cr, label_x, y + 20 * MainWindow.units, 17 * MainWindow.units);+ cr.restore ();+ } + }+ }+}++}@@ -97,10 +97,8 @@ public class TabContent : GLib.Object { return; } - if (GlyphCanvas.current_display is Glyph) {- GlyphCanvas.current_display.key_release (keyval);- }- + GlyphCanvas.current_display.key_release (keyval);+ KeyBindings.remove_modifier_from_keyval (keyval); } @@ -23,8 +23,8 @@ public class Tool : GLib.Object { public double w = 33 * Toolbox.get_scale (); public double h = (33 / 1.11) * Toolbox.get_scale (); - protected bool active = false;- protected bool selected = false;+ public bool active = false;+ public bool selected = false; ImageSurface? icon = null; @@ -250,6 +250,12 @@ public class Tool : GLib.Object { cr.save (); scale = w / 111.0; // scale to 320 dpi+ + if (unlikely (scale == 0)) {+ warning ("Scale is zero.");+ scale = 33 / 111.0;+ }+ cr.scale (scale, scale); bgx = xt / scale;new file mode 100644@@ -0,0 +1,35 @@+/*+ Copyright (C) 2014 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 + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version.++ This library 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 + Lesser General Public License for more details.+*/++namespace BirdFont {++public class ToolItem : MenuItem {++ public Tool tool;++ public ToolItem (Tool tool) {+ base (tool.tip, tool.tip); // FIXME: untranslated tip.+ + this.tool = tool;+ + modifiers = tool.modifier_flag;+ key = tool.key;+ + action.connect (() => {+ tool.select_action (tool);+ });+ }+}++}@@ -393,6 +393,14 @@ public class Toolbox : GLib.Object { return Toolbox.allocation_width / 160.0; } + public void set_default_tool_size () {+ foreach (ToolCollection t in tool_sets) {+ foreach (Expander e in t.get_expanders ()) {+ e.update_tool_position ();+ }+ }+ }+ public void update_expanders () { double pos; @@ -148,10 +148,6 @@ public class XmlParser { return root; } - public Tag.Iterator iterator () {- return get_root_tag ().iterator ();- }- /** * Reset the parser and start from the beginning of the XML document. */