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