The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

AbstractMenu.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/AbstractMenu.vala.
Show key bindings in tool tip
1 /* 2 Copyright (C) 2014 2015 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 using B; 17 18 namespace BirdFont { 19 20 /** Interface for events from native window to the current tab. */ 21 public class AbstractMenu : GLib.Object { 22 23 public bool show_menu { 24 get { 25 return menu_visibility; 26 } 27 28 set { 29 string tab_name; 30 31 menu_visibility = value; 32 current_menu = top_menu; 33 34 if (menu_visibility) { 35 tab_name = MainWindow.get_tab_bar ().get_selected_tab ().get_display ().get_name (); 36 if (tab_name == "Preview") { 37 MenuTab.select_overview (); 38 } 39 } 40 } 41 } 42 43 public bool menu_visibility = false; 44 public SubMenu top_menu; 45 46 SubMenu current_menu; 47 WidgetAllocation allocation = new WidgetAllocation (); 48 49 double width = 250 * MainWindow.units; 50 double height = 25 * MainWindow.units; 51 52 public Gee.HashMap<string, MenuItem> menu_items = new Gee.HashMap<string, MenuItem> (); 53 public Gee.ArrayList<MenuItem> sorted_menu_items = new Gee.ArrayList<MenuItem> (); 54 55 public AbstractMenu () { 56 } 57 58 public ToolItem? get_item_for_tool (Tool t) { 59 ToolItem tm; 60 61 foreach (MenuItem item in sorted_menu_items) { 62 if (item is ToolItem) { 63 tm = (ToolItem) item; 64 65 if (tm.tool == t) { 66 return tm; 67 } 68 } 69 } 70 71 return null; 72 } 73 74 public void process_key_binding_events (uint keyval) { 75 string display; 76 FontDisplay current_display = MainWindow.get_current_display (); 77 ToolItem tm; 78 79 foreach (MenuItem item in sorted_menu_items) { 80 if (item.key == (unichar) keyval && item.modifiers == KeyBindings.modifier) { 81 82 display = current_display.get_name (); 83 84 if (current_display is Glyph) { 85 display = "Glyph"; 86 } 87 88 if (!current_display.needs_modifier () || item.modifiers != NONE) { 89 if (!SettingsDisplay.update_key_bindings 90 && item.in_display (display) 91 && !(item is ToolItem)) { 92 item.action (); 93 return; 94 } 95 96 if (item is ToolItem) { 97 tm = (ToolItem) item; 98 99 if (tm.in_display (display)) { 100 if (tm.tool.editor_events) { 101 MainWindow.get_toolbox ().set_current_tool (tm.tool); 102 tm.tool.select_action (tm.tool); 103 return; 104 } else { 105 tm.tool.select_action (tm.tool); 106 return; 107 } 108 } 109 } 110 } 111 } 112 } 113 } 114 115 public void load_key_bindings () { 116 File default_key_bindings = SearchPaths.find_file (null, "key_bindings.xml"); 117 File user_key_bindings = get_child (BirdFont.get_settings_directory (), "key_bindings.xml"); 118 119 if (default_key_bindings.query_exists ()) { 120 parse_key_bindings (default_key_bindings); 121 } 122 123 if (user_key_bindings.query_exists ()) { 124 parse_key_bindings (user_key_bindings); 125 } 126 } 127 128 public void parse_key_bindings (File f) { 129 string xml_data; 130 XmlParser parser; 131 132 try { 133 FileUtils.get_contents((!) f.get_path (), out xml_data); 134 parser = new XmlParser (xml_data); 135 parse_bindings (parser.get_root_tag ()); 136 } catch (GLib.Error e) { 137 warning (e.message); 138 } 139 } 140 141 public void parse_bindings (Tag tag) { 142 foreach (Tag t in tag) { 143 if (t.get_name () == "action") { 144 parse_binding (t.get_attributes ()); 145 } 146 } 147 } 148 149 public void parse_binding (Attributes attr) { 150 uint modifier = NONE; 151 unichar key = '\0'; 152 string action = ""; 153 MenuItem menu_action; 154 MenuItem? ma; 155 156 foreach (Attribute a in attr) { 157 if (a.get_name () == "key") { 158 key = a.get_content ().get_char (0); 159 } 160 161 if (a.get_name () == "ctrl" && a.get_content () == "true") { 162 modifier |= CTRL; 163 } 164 165 if (a.get_name () == "alt" && a.get_content () == "true") { 166 modifier |= ALT; 167 } 168 169 if (a.get_name () == "command" && a.get_content () == "true") { 170 modifier |= LOGO; 171 } 172 173 if (a.get_name () == "shift" && a.get_content () == "true") { 174 modifier |= SHIFT; 175 } 176 177 if (a.get_name () == "action") { 178 action = a.get_content (); 179 } 180 } 181 182 ma = menu_items.get (action); 183 if (ma != null) { 184 menu_action = (!) ma; 185 menu_action.modifiers = modifier; 186 menu_action.key = key; 187 } 188 } 189 190 public MenuItem add_menu_item (string label, string description = "", string display = "") { 191 MenuItem i = new MenuItem (label, description); 192 193 if (description != "") { 194 menu_items.set (description, i); 195 sorted_menu_items.add (i); 196 } 197 198 if (display != "") { 199 i.add_display (display); 200 } 201 202 return i; 203 } 204 205 public void button_release (int button, double ex, double ey) { 206 double y = 0; 207 double x = allocation.width - width; 208 209 if (button == 1) { 210 foreach (MenuItem item in current_menu.items) { 211 if (x <= ex < allocation.width && y <= ey <= y + height) { 212 item.action (); 213 GlyphCanvas.redraw (); 214 return; 215 } 216 217 y += height; 218 } 219 220 menu_visibility = false; 221 current_menu = (!) top_menu; 222 GlyphCanvas.redraw (); 223 } 224 } 225 226 public void add_tool_key_bindings () { 227 ToolItem tool_item; 228 foreach (ToolCollection tool_set in MainWindow.get_toolbox ().tool_sets) { 229 foreach (Expander e in tool_set.get_expanders ()) { 230 foreach (Tool t in e.tool) { 231 tool_item = new ToolItem (t); 232 if (tool_item.identifier != "" && !has_menu_item (tool_item.identifier)) { 233 menu_items.set (tool_item.identifier, tool_item); 234 sorted_menu_items.add (tool_item); 235 } 236 237 foreach (string d in tool_set.get_displays ()) { 238 tool_item.add_display (d); 239 } 240 } 241 } 242 } 243 } 244 245 public bool has_menu_item (string identifier) { 246 foreach (MenuItem mi in sorted_menu_items) { 247 if (mi.identifier == identifier) { 248 return true; 249 } 250 } 251 252 return false; 253 } 254 255 public void set_menu (SubMenu m) { 256 current_menu = m; 257 GlyphCanvas.redraw (); 258 } 259 260 public double layout_width () { 261 Text key_binding = new Text (); 262 double font_size = 17 * MainWindow.units;; 263 double w; 264 265 width = 0; 266 foreach (MenuItem item in current_menu.items) { 267 key_binding.set_text (item.get_key_bindings ()); 268 269 item.label.set_font_size (font_size); 270 key_binding.set_font_size (font_size); 271 272 w = item.label.get_extent (); 273 w += key_binding.get_extent (); 274 w += 3 * height * MainWindow.units; 275 276 if (w > width) { 277 width = w; 278 } 279 } 280 281 return width; 282 } 283 284 public void draw (WidgetAllocation allocation, Context cr) { 285 double y; 286 double x; 287 double label_x; 288 double label_y; 289 double font_size; 290 Text key_binding; 291 double binding_extent; 292 293 width = layout_width (); 294 295 key_binding = new Text (); 296 297 x = allocation.width - width; 298 y = 0; 299 font_size = 17 * MainWindow.units; 300 this.allocation = allocation; 301 302 foreach (MenuItem item in current_menu.items) { 303 cr.save (); 304 Theme.color (cr, "Menu Background"); 305 cr.rectangle (x, y, width, height); 306 cr.fill (); 307 cr.restore (); 308 309 cr.save (); 310 label_x = allocation.width - width + 0.7 * height * MainWindow.units; 311 label_y = y + font_size - 1 * MainWindow.units; 312 Theme.text_color (item.label, "Menu Foreground"); 313 item.label.draw_at_baseline (cr, label_x, label_y); 314 315 key_binding.set_text (item.get_key_bindings ()); 316 key_binding.set_font_size (font_size); 317 binding_extent = key_binding.get_extent (); 318 label_x = x + width - binding_extent - 0.6 * height * MainWindow.units; 319 key_binding.set_font_size (font_size); 320 Theme.text_color (key_binding, "Menu Foreground"); 321 key_binding.draw_at_baseline (cr, label_x, label_y); 322 323 y += height; 324 } 325 } 326 327 public void write_key_bindings () { 328 DataOutputStream os; 329 File file; 330 bool has_ctrl, has_alt, has_command, has_shift; 331 332 file = get_child (BirdFont.get_settings_directory (), "key_bindings.xml"); 333 334 try { 335 if (file.query_exists ()) { 336 file.delete (); 337 } 338 } catch (GLib.Error e) { 339 warning (e.message); 340 } 341 342 try { 343 os = new DataOutputStream (file.create (FileCreateFlags.REPLACE_DESTINATION)); 344 os.put_string ("""<?xml version="1.0" encoding="utf-8" standalone="yes"?>"""); 345 os.put_string ("\n"); 346 347 os.put_string ("<bindings>\n"); 348 349 foreach (MenuItem item in sorted_menu_items) { 350 os.put_string ("\t<action "); 351 352 os.put_string (@"key=\"$((!)item.key.to_string ())\" "); 353 354 has_ctrl = (item.modifiers & CTRL) > 0; 355 os.put_string (@"ctrl=\"$(has_ctrl.to_string ())\" "); 356 357 has_alt = (item.modifiers & ALT) > 0; 358 os.put_string (@"alt=\"$(has_alt.to_string ())\" "); 359 360 has_command = (item.modifiers & LOGO) > 0; 361 os.put_string (@"command=\"$(has_command.to_string ())\" "); 362 363 has_shift = (item.modifiers & SHIFT) > 0; 364 os.put_string (@"shift=\"$(has_shift.to_string ())\" "); 365 366 os.put_string (@"action=\"$(item.identifier)\" "); 367 368 os.put_string ("/>\n"); 369 } 370 os.put_string ("</bindings>\n"); 371 372 os.close (); 373 } catch (GLib.Error e) { 374 warning (e.message); 375 } 376 } 377 378 public void set_current_menu (SubMenu menu) { 379 current_menu = menu; 380 } 381 } 382 383 } 384