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