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 // keyboard bindings 71 public uint modifier_flag; 72 public unichar key; 73 74 public bool persistent = false; 75 public bool editor_events = false; 76 77 bool waiting_for_tooltip = false; 78 bool showing_this_tooltip = false; 79 static Tool active_tooltip = new Tool (); 80 81 public bool visible = true; 82 public bool is_tool_modifier = false; 83 84 public string icon_color = ""; 85 86 public signal void redraw_tool (); 87 88 /** Create tool with a certain name and load icon "name".png */ 89 public Tool (string? name = null, string tip = "") { 90 this.tip = tip; 91 92 icon_font = new Text (); 93 94 scale = MainWindow.units; 95 w = 33 * Toolbox.get_scale (); 96 h = (33 / 1.11) * Toolbox.get_scale (); 97 98 if (name != null) { 99 set_icon ((!) name); 100 this.name = (!) name; 101 } 102 103 id = next_id; 104 next_id++; 105 106 panel_press_action.connect ((self, button, x, y) => { 107 if (is_active ()) { 108 redraw (); 109 } 110 }); 111 112 select_action.connect ((self) => { 113 redraw (); 114 }); 115 116 deselect_action.connect ((self) => { 117 redraw (); 118 }); 119 120 move_out_action.connect ((self) => { 121 MainWindow.get_toolbox ().hide_tooltip (); 122 active_tooltip.showing_this_tooltip = false; 123 redraw (); 124 }); 125 126 panel_move_action.connect ((self, x, y) => { 127 if (is_active ()) { 128 wait_for_tooltip (); 129 redraw (); 130 } 131 return false; 132 }); 133 } 134 135 public override void draw (Context cr) { 136 draw_tool (cr, 0, 0); 137 } 138 139 public void redraw () { 140 redraw_tool (); 141 Toolbox.redraw_tool_box (); 142 } 143 144 public override double get_height () { 145 return 33 * scale; 146 } 147 148 public override double get_width () { 149 return 33 * scale; 150 } 151 152 public void set_tool_visibility (bool v) { 153 visible = v; 154 } 155 156 public bool tool_is_visible () { 157 return visible; 158 } 159 160 void wait_for_tooltip () { 161 TimeoutSource timer_show; 162 int timeout_interval = 1500; 163 164 if (active_tooltip != this) { 165 if (active_tooltip.showing_this_tooltip) { 166 timeout_interval = 1; 167 } 168 169 active_tooltip.showing_this_tooltip = false; 170 showing_this_tooltip = false; 171 active_tooltip = this; 172 173 if (!waiting_for_tooltip) { 174 waiting_for_tooltip = true; 175 timer_show = new TimeoutSource (timeout_interval); 176 timer_show.set_callback (() => { 177 if (tip != "" && active_tooltip.is_active () && !active_tooltip.showing_this_tooltip) { 178 show_tooltip (); 179 } 180 waiting_for_tooltip = false; 181 return waiting_for_tooltip; 182 }); 183 timer_show.attach (null); 184 } 185 } 186 } 187 188 public static void show_tooltip () { 189 TimeoutSource timer_hide; 190 Toolbox toolbox; 191 192 toolbox = MainWindow.get_toolbox (); 193 194 // hide tooltip label later 195 if (!active_tooltip.showing_this_tooltip) { 196 timer_hide = new TimeoutSource (1500); 197 timer_hide.set_callback (() => { 198 if (!active_tooltip.is_active ()) { 199 toolbox.hide_tooltip (); 200 active_tooltip.showing_this_tooltip = false; 201 active_tooltip = new Tool (); 202 } 203 return active_tooltip.showing_this_tooltip; 204 }); 205 timer_hide.attach (null); 206 } 207 208 active_tooltip.showing_this_tooltip = true; 209 210 toolbox.hide_tooltip (); 211 toolbox.show_tooltip (active_tooltip.tip, (int) active_tooltip.x, (int) active_tooltip.y); 212 } 213 214 public void set_icon (string name) { 215 bool found; 216 string icon_file; 217 218 icon_file = Theme.get_icon_file (); 219 icon_font = new Text ((!) name); 220 found = icon_font.load_font (icon_file); 221 icon_font.use_cache (true); 222 icon_font.set_font_size (40 * Toolbox.get_scale ()); 223 224 if (!found) { 225 warning (@"Icon font for toolbox was not found. ($(icon_file))"); 226 } 227 } 228 229 public bool is_active () { 230 return active; 231 } 232 233 public void set_show_background (bool bg) { 234 show_bg = bg; 235 } 236 237 public int get_id () { 238 return id; 239 } 240 241 public string get_name () { 242 return name; 243 } 244 245 public bool is_selected () { 246 return selected; 247 } 248 249 public string get_tip () { 250 return tip; 251 } 252 253 public new bool is_over (double xp, double yp) { 254 bool r = (x <= xp <= x + w && y <= yp <= y + h); 255 return r; 256 } 257 258 public bool set_selected (bool a) { 259 new_selection = true; 260 selected = a; 261 set_active (a); 262 263 if (!a) { 264 deselect_action (this); 265 } 266 267 return true; 268 } 269 270 /** @return true if this tool changes state, */ 271 public bool set_active (bool ac) { 272 bool ret = (active != ac); 273 active = ac; 274 return ret; 275 } 276 277 public virtual void draw_tool (Context cr, double px, double py) { 278 double xt = x - px; 279 double yt = y - py; 280 281 double bgx, bgy; 282 double iconx, icony; 283 284 string border = "Button Border 3"; 285 string background = "Button Border 3"; 286 287 double scale = Toolbox.get_scale (); 288 289 cr.save (); 290 291 bgx = xt; 292 bgy = yt; 293 294 // Button in four states 295 if (selected) { 296 border = "Button Border 1"; 297 background = "Button Background 1"; 298 } 299 300 if (selected && active) { 301 border = "Button Border 2"; 302 background = "Button Background 2"; 303 } 304 305 if (!selected) { 306 border = "Button Border 3"; 307 background = "Button Background 3"; 308 } 309 310 if (!selected && active) { 311 border = "Button Border 4"; 312 background = "Button Background 4"; 313 } 314 315 Theme.color (cr, background); 316 draw_rounded_rectangle (cr, bgx, bgy, 34 * scale, 28 * scale, 4 * scale); 317 cr.fill (); 318 319 cr.set_line_width (1); 320 Theme.color (cr, border); 321 draw_rounded_rectangle (cr, bgx, bgy, 34 * scale, 28 * scale, 4 * scale); 322 cr.stroke (); 323 324 iconx = bgx + 1 + (w - 1) / 2 - icon_font.get_sidebearing_extent () / 2; 325 icony = bgy - 1 + (h - 1) / 2 - icon_font.get_height () / 2; 326 327 if (icon_color == "") { 328 if (!selected) { 329 Theme.text_color (icon_font, "Tool Foreground"); 330 } else { 331 Theme.text_color (icon_font, "Selected Tool Foreground"); 332 } 333 } else { 334 Theme.text_color (icon_font, icon_color); 335 } 336 337 icon_font.widget_x = iconx; 338 icon_font.widget_y = icony; 339 340 icon_font.draw (cr); 341 342 cr.restore (); 343 } 344 345 /** Run pending events in main loop before continuing. */ 346 public static void @yield () { 347 int t = 0; 348 TimeoutSource time = new TimeoutSource (500); 349 bool timeout; 350 unowned MainContext context; 351 bool acquired; 352 353 if (TestBirdFont.is_slow_test ()) { 354 timeout = false; 355 356 time.set_callback (() => { 357 timeout = true; 358 return false; 359 }); 360 361 time.attach (null); 362 } else { 363 timeout = true; 364 } 365 366 context = MainContext.default (); 367 acquired = context.acquire (); 368 369 if (unlikely (!acquired)) { 370 warning ("Failed to acquire main loop.\n"); 371 return; 372 } 373 374 while (context.pending () || TestBirdFont.is_slow_test ()) { 375 context.iteration (true); 376 t++; 377 378 if (!context.pending () && TestBirdFont.is_slow_test ()) { 379 if (timeout) break; 380 } 381 } 382 383 context.release (); 384 } 385 386 public void set_persistent (bool p) { 387 persistent = p; 388 } 389 390 public virtual void before_undo () { 391 } 392 393 public virtual void after_undo () { 394 } 395 396 } 397 398 } 399