The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

Tool.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/Tool.vala.
Show key bindings in tool tip
1 /* 2 Copyright (C) 2012, 2014 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 17 namespace BirdFont { 18 19 public class Tool : Widget { 20 21 public double x = 0; 22 public double y = 0; 23 public double w; 24 public double h; 25 26 double scale; 27 28 public bool active = false; 29 public bool selected = false; 30 31 public Text icon_font; 32 33 public signal void select_action (Tool selected); 34 public signal void deselect_action (Tool selected); 35 36 public signal void press_action (Tool selected, int button, int x, int y); 37 public signal void double_click_action (Tool selected, int button, int x, int y); 38 public signal void move_action (Tool selected, int x, int y); 39 public signal void move_out_action (Tool selected); 40 public signal void release_action (Tool selected, int button, int x, int y); 41 42 /** Returns true if tool is listening for scroll wheel actions. */ 43 public signal bool scroll_wheel_up_action (Tool selected); 44 public signal bool scroll_wheel_down_action (Tool selected); 45 46 public signal void key_press_action (Tool selected, uint32 keyval); 47 public signal void key_release_action (Tool selected, uint32 keyval); 48 49 public signal void panel_press_action (Tool selected, uint button, double x, double y); 50 public signal void panel_release_action (Tool selected, uint button, double x, double y); 51 public signal void panel_double_click_action (Tool selected, uint button, double x, double y); 52 53 /** @return true is event is consumed. */ 54 public signal bool panel_move_action (Tool selected, double x, double y); 55 56 public signal void draw_action (Tool selected, Context cr, Glyph glyph); 57 58 public string name = ""; 59 60 static int next_id = 1; 61 62 int id; 63 64 public bool new_selection = false; 65 66 bool show_bg = true; 67 68 public string tip = ""; 69 70 public bool persistent = false; 71 public bool editor_events = false; 72 73 bool waiting_for_tooltip = false; 74 bool showing_this_tooltip = false; 75 static Tool active_tooltip = new Tool (); 76 77 public bool visible = true; 78 public bool is_tool_modifier = false; 79 80 public string icon_color = ""; 81 82 public signal void redraw_tool (); 83 84 /** Create tool with a certain name and load icon "name".png */ 85 public Tool (string? name = null, string tip = "") { 86 this.tip = tip; 87 88 icon_font = new Text (); 89 90 scale = MainWindow.units; 91 w = 33 * Toolbox.get_scale (); 92 h = (33 / 1.11) * Toolbox.get_scale (); 93 94 if (name != null) { 95 set_icon ((!) name); 96 this.name = (!) name; 97 } 98 99 id = next_id; 100 next_id++; 101 102 panel_press_action.connect ((self, button, x, y) => { 103 if (is_active ()) { 104 redraw (); 105 } 106 }); 107 108 select_action.connect ((self) => { 109 redraw (); 110 }); 111 112 deselect_action.connect ((self) => { 113 redraw (); 114 }); 115 116 move_out_action.connect ((self) => { 117 MainWindow.get_toolbox ().hide_tooltip (); 118 active_tooltip.showing_this_tooltip = false; 119 redraw (); 120 }); 121 122 panel_move_action.connect ((self, x, y) => { 123 if (is_active ()) { 124 wait_for_tooltip (); 125 redraw (); 126 } 127 return false; 128 }); 129 } 130 131 public override void draw (Context cr) { 132 draw_tool (cr, 0, 0); 133 } 134 135 public void redraw () { 136 redraw_tool (); 137 Toolbox.redraw_tool_box (); 138 } 139 140 public override double get_height () { 141 return 33 * scale; 142 } 143 144 public override double get_width () { 145 return 33 * scale; 146 } 147 148 public void set_tool_visibility (bool v) { 149 visible = v; 150 } 151 152 public bool tool_is_visible () { 153 return visible; 154 } 155 156 void wait_for_tooltip () { 157 TimeoutSource timer_show; 158 int timeout_interval = 1500; 159 160 if (active_tooltip != this) { 161 if (active_tooltip.showing_this_tooltip) { 162 timeout_interval = 1; 163 } 164 165 active_tooltip.showing_this_tooltip = false; 166 showing_this_tooltip = false; 167 active_tooltip = this; 168 169 if (!waiting_for_tooltip) { 170 waiting_for_tooltip = true; 171 timer_show = new TimeoutSource (timeout_interval); 172 timer_show.set_callback (() => { 173 if (tip != "" && active_tooltip.is_active () && !active_tooltip.showing_this_tooltip) { 174 show_tooltip (); 175 } 176 waiting_for_tooltip = false; 177 return waiting_for_tooltip; 178 }); 179 timer_show.attach (null); 180 } 181 } 182 } 183 184 public static void show_tooltip () { 185 TimeoutSource timer_hide; 186 Toolbox toolbox; 187 string tip; 188 string key_binding; 189 190 toolbox = MainWindow.get_toolbox (); 191 192 // hide tooltip label later 193 if (!active_tooltip.showing_this_tooltip) { 194 timer_hide = new TimeoutSource (1500); 195 timer_hide.set_callback (() => { 196 if (!active_tooltip.is_active ()) { 197 toolbox.hide_tooltip (); 198 active_tooltip.showing_this_tooltip = false; 199 active_tooltip = new Tool (); 200 } 201 return active_tooltip.showing_this_tooltip; 202 }); 203 timer_hide.attach (null); 204 } 205 206 active_tooltip.showing_this_tooltip = true; 207 208 tip = @"$(active_tooltip.tip)"; 209 key_binding = active_tooltip.get_key_binding (); 210 211 if (key_binding != "") { 212 tip += " (" + key_binding + ")"; 213 } 214 215 toolbox.hide_tooltip (); 216 toolbox.show_tooltip (tip, (int) active_tooltip.x, (int) active_tooltip.y); 217 } 218 219 public string get_key_binding () { 220 StringBuilder sb = new StringBuilder (); 221 ToolItem? ti = MainWindow.get_menu ().get_item_for_tool (this); 222 ToolItem t; 223 224 if (ti == null) { 225 return ""; 226 } 227 228 t = (!) ti; 229 230 if (t.key == '\0') { 231 return ""; 232 } 233 234 if ((t.modifiers & CTRL) > 0) { 235 sb.append ("Ctrl"); 236 sb.append ("+"); 237 } 238 239 if ((t.modifiers & SHIFT) > 0) { 240 sb.append (t_("Shift")); 241 sb.append ("+"); 242 } 243 244 if ((t.modifiers & ALT) > 0) { 245 sb.append ("Alt"); 246 sb.append ("+"); 247 } 248 249 if ((t.modifiers & LOGO) > 0) { 250 sb.append ("Super"); 251 sb.append ("+"); 252 } 253 254 sb.append_unichar (t.key); 255 256 return sb.str; 257 } 258 259 public void set_icon (string name) { 260 bool found; 261 string icon_file; 262 263 icon_file = Theme.get_icon_file (); 264 icon_font = new Text ((!) name); 265 found = icon_font.load_font (icon_file); 266 icon_font.use_cache (true); 267 icon_font.set_font_size (40 * Toolbox.get_scale ()); 268 269 if (!found) { 270 warning (@"Icon font for toolbox was not found. ($(icon_file))"); 271 } 272 } 273 274 public bool is_active () { 275 return active; 276 } 277 278 public void set_show_background (bool bg) { 279 show_bg = bg; 280 } 281 282 public int get_id () { 283 return id; 284 } 285 286 public string get_name () { 287 return name; 288 } 289 290 public bool is_selected () { 291 return selected; 292 } 293 294 public string get_tip () { 295 return tip; 296 } 297 298 public new bool is_over (double xp, double yp) { 299 bool r = (x <= xp <= x + w && y <= yp <= y + h); 300 return r; 301 } 302 303 public bool set_selected (bool a) { 304 new_selection = true; 305 selected = a; 306 set_active (a); 307 308 if (!a) { 309 deselect_action (this); 310 } 311 312 return true; 313 } 314 315 /** @return true if this tool changes state, */ 316 public bool set_active (bool ac) { 317 bool ret = (active != ac); 318 active = ac; 319 return ret; 320 } 321 322 public virtual void draw_tool (Context cr, double px, double py) { 323 double xt = x - px; 324 double yt = y - py; 325 326 double bgx, bgy; 327 double iconx, icony; 328 329 string border = "Button Border 3"; 330 string background = "Button Border 3"; 331 332 double scale = Toolbox.get_scale (); 333 334 cr.save (); 335 336 bgx = xt; 337 bgy = yt; 338 339 // Button in four states 340 if (selected) { 341 border = "Button Border 1"; 342 background = "Button Background 1"; 343 } 344 345 if (selected && active) { 346 border = "Button Border 2"; 347 background = "Button Background 2"; 348 } 349 350 if (!selected) { 351 border = "Button Border 3"; 352 background = "Button Background 3"; 353 } 354 355 if (!selected && active) { 356 border = "Button Border 4"; 357 background = "Button Background 4"; 358 } 359 360 Theme.color (cr, background); 361 draw_rounded_rectangle (cr, bgx, bgy, 34 * scale, 28 * scale, 4 * scale); 362 cr.fill (); 363 364 cr.set_line_width (1); 365 Theme.color (cr, border); 366 draw_rounded_rectangle (cr, bgx, bgy, 34 * scale, 28 * scale, 4 * scale); 367 cr.stroke (); 368 369 iconx = bgx + 1 + (w - 1) / 2 - icon_font.get_sidebearing_extent () / 2; 370 icony = bgy - 1 + (h - 1) / 2 - icon_font.get_height () / 2; 371 372 if (icon_color == "") { 373 if (!selected) { 374 Theme.text_color (icon_font, "Tool Foreground"); 375 } else { 376 Theme.text_color (icon_font, "Selected Tool Foreground"); 377 } 378 } else { 379 Theme.text_color (icon_font, icon_color); 380 } 381 382 icon_font.widget_x = iconx; 383 icon_font.widget_y = icony; 384 385 icon_font.draw (cr); 386 387 cr.restore (); 388 } 389 390 /** Run pending events in main loop before continuing. */ 391 public static void @yield () { 392 int t = 0; 393 TimeoutSource time = new TimeoutSource (500); 394 bool timeout; 395 unowned MainContext context; 396 bool acquired; 397 398 if (TestBirdFont.is_slow_test ()) { 399 timeout = false; 400 401 time.set_callback (() => { 402 timeout = true; 403 return false; 404 }); 405 406 time.attach (null); 407 } else { 408 timeout = true; 409 } 410 411 context = MainContext.default (); 412 acquired = context.acquire (); 413 414 if (unlikely (!acquired)) { 415 warning ("Failed to acquire main loop.\n"); 416 return; 417 } 418 419 while (context.pending () || TestBirdFont.is_slow_test ()) { 420 context.iteration (true); 421 t++; 422 423 if (!context.pending () && TestBirdFont.is_slow_test ()) { 424 if (timeout) break; 425 } 426 } 427 428 context.release (); 429 } 430 431 public void set_persistent (bool p) { 432 persistent = p; 433 } 434 435 public virtual void before_undo () { 436 } 437 438 public virtual void after_undo () { 439 } 440 441 } 442 443 } 444