The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

Toolbox.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/Toolbox.vala.
Fix zero length handles
1 /* 2 Copyright (C) 2012 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 Math; 17 18 namespace BirdFont { 19 20 public class Toolbox : GLib.Object { 21 public static ToolCollection current_set; 22 23 public static HiddenTools hidden_tools; 24 public static DrawingTools drawing_tools; 25 public static KerningTools kerning_tools; 26 public static PreviewTools preview_tools; 27 public static OverviewTools overview_tools; 28 public static BackgroundTools background_tools; 29 public static SpacingTools spacing_tools; 30 public static FileTools file_tools; 31 public static ThemeTools theme_tools; 32 33 Tool current_tool; 34 35 public Tool press_tool; 36 37 public signal void redraw (int x, int y, int w, int h); 38 39 public static int allocation_width = 0; 40 public static int allocation_height = 0; 41 42 /** Scrolling with scroll wheel */ 43 bool scrolling_toolbox = false; 44 45 /** Scroll with touch pad. */ 46 bool scrolling_touch = false; 47 double scroll_y = 0; 48 49 public Gee.ArrayList<ToolCollection> tool_sets; 50 51 string? tool_tip = null; 52 double tool_tip_x = 0; 53 double tool_tip_y = 0; 54 55 public signal void new_tool_set (Tab? tab); 56 bool suppress_event = false; 57 58 public Toolbox (GlyphCanvas glyph_canvas, TabBar tab_bar) { 59 tool_sets = new Gee.ArrayList<ToolCollection> (); 60 current_tool = new Tool ("no_icon"); 61 press_tool = new Tool (null); 62 63 hidden_tools = new HiddenTools (); 64 drawing_tools = new DrawingTools (glyph_canvas); 65 kerning_tools = new KerningTools (); 66 preview_tools = new PreviewTools (); 67 overview_tools = new OverviewTools (); 68 background_tools = new BackgroundTools (); 69 spacing_tools = new SpacingTools (); 70 file_tools = new FileTools (); 71 theme_tools = new ThemeTools (); 72 73 tool_sets.add (theme_tools); 74 tool_sets.add (file_tools); 75 tool_sets.add (hidden_tools); 76 tool_sets.add (drawing_tools); 77 tool_sets.add (kerning_tools); 78 tool_sets.add (preview_tools); 79 tool_sets.add (overview_tools); 80 tool_sets.add (background_tools); 81 // the menu has all the file_tools commands, it will not be added here 82 tool_sets.add (hidden_tools); // tools without a button 83 84 current_set = file_tools; 85 current_set.selected (); 86 87 tab_bar.signal_tab_selected.connect ((tab) => { 88 string tab_name = tab.get_display ().get_name (); 89 set_toolbox_from_tab (tab_name, tab); 90 new_tool_set (tab); 91 }); 92 93 update_expanders (); 94 } 95 96 public void set_suppress_event (bool e) { 97 suppress_event = e; 98 } 99 100 public static DrawingTools get_drawing_tools () { 101 return drawing_tools; 102 } 103 104 public void update_all_expanders () { 105 foreach (ToolCollection tc in tool_sets) { 106 tc.redraw (); 107 } 108 } 109 110 public static void set_toolbox_from_tab (string tab_name, Tab? t = null) { 111 if (tab_name == "Spacing") { 112 current_set = (ToolCollection) spacing_tools; 113 } else if (tab_name == "Kerning") { 114 current_set = (ToolCollection) kerning_tools; 115 } else if (tab_name == "Preview") { 116 current_set = (ToolCollection) preview_tools; 117 } else if (tab_name == "Overview") { 118 current_set = (ToolCollection) overview_tools; 119 } else if (tab_name == "Backgrounds") { 120 current_set = (ToolCollection) background_tools; 121 } else if (tab_name == "Themes") { 122 current_set = (ToolCollection) theme_tools; 123 } else if (t != null && ((!) t).get_display () is Glyph) { 124 current_set = (ToolCollection) drawing_tools; 125 } else { 126 current_set = (ToolCollection) file_tools; 127 } 128 129 current_set.selected (); 130 MainWindow.get_toolbox ().update_expanders (); 131 redraw_tool_box (); 132 } 133 134 public static Tool get_move_tool () { 135 return DrawingTools.move_tool; 136 } 137 138 public static void set_object_stroke (double width) { 139 DrawingTools.object_stroke.set_value_round (width); 140 redraw_tool_box (); 141 } 142 143 public static void set_allocation (int width, int height) { 144 if (width != allocation_width || allocation_height != height) { 145 allocation_width = width; 146 allocation_height = height; 147 Toolbox.redraw_tool_box (); 148 } 149 } 150 151 public void press (uint button, double x, double y) { 152 if (MenuTab.has_suppress_event () || suppress_event) { 153 warn_if_test ("Event suppressed"); 154 return; 155 } 156 157 y -= current_set.scroll; 158 159 foreach (Expander exp in current_set.get_expanders ()) { 160 if (exp.visible) { 161 foreach (Tool t in exp.tool) { 162 if (t.tool_is_visible () && t.is_over (x, y)) { 163 t.panel_press_action (t, button, x, y); 164 press_tool = t; 165 } 166 } 167 } 168 } 169 170 scrolling_touch = true; 171 scroll_y = y; 172 } 173 174 public void release (uint button, double x, double y) { 175 bool active; 176 177 y -= current_set.scroll; 178 179 if (MenuTab.has_suppress_event () || suppress_event) { 180 warn_if_test ("Event suppressed"); 181 return; 182 } 183 184 foreach (Expander exp in current_set.get_expanders ()) { 185 if (exp.visible) { 186 foreach (Tool t in exp.tool) { 187 if (t.tool_is_visible ()) { 188 active = t.is_over (x, y); 189 190 if (active) { 191 if (press_tool == t) { 192 select_tool (t); 193 } 194 } 195 196 t.panel_release_action (t, button, x, y); 197 } 198 } 199 } 200 } 201 202 scrolling_touch = false; 203 } 204 205 public void double_click (uint button, double x, double y) { 206 if (MenuTab.has_suppress_event () || suppress_event) { 207 warn_if_test ("Event suppressed"); 208 return; 209 } 210 211 y -= current_set.scroll; 212 213 foreach (Expander e in current_set.get_expanders ()) { 214 if (e.visible) { 215 foreach (Tool t in e.tool) { 216 t.panel_double_click_action (t, button, x, y); 217 } 218 } 219 } 220 } 221 222 public void scroll_wheel (double x, double y, double dx, double dy) { 223 bool action = false; 224 225 y -= current_set.scroll; 226 227 if (MenuTab.has_suppress_event () || suppress_event) { 228 warn_if_test ("Event suppressed"); 229 return; 230 } 231 232 if (!scrolling_toolbox) { 233 foreach (Expander exp in current_set.get_expanders ()) { 234 if (exp.visible) { 235 foreach (Tool t in exp.tool) { 236 if (t.tool_is_visible () && t.is_over (x, y)) { 237 if (dy < 0) { 238 action = t.scroll_wheel_up_action (t); 239 } else { 240 action = t.scroll_wheel_down_action (t); 241 } 242 press_tool = t; 243 } 244 } 245 } 246 } 247 } 248 249 if (!action) { 250 scroll_current_set (dy); 251 } 252 253 redraw_tool_box (); 254 } 255 256 void scroll_current_set (double d) { 257 current_set.scroll += d; 258 259 if (current_set.scroll > 0) { 260 current_set.scroll = 0; 261 } 262 263 if (current_set.content_height < allocation_height) { 264 current_set.scroll = 0; 265 } else if (current_set.content_height + current_set.scroll < allocation_height) { 266 current_set.scroll = allocation_height - current_set.content_height; 267 } 268 269 update_expanders (); 270 suppress_scroll (); 271 } 272 273 public void scroll_up (double x, double y) { 274 scroll_wheel (x, y, 0, 20); 275 } 276 277 public void scroll_down (double x, double y) { 278 scroll_wheel (x, y, 0, -20); 279 } 280 281 void suppress_scroll () { 282 scrolling_toolbox = true; 283 284 Timeout.add (2000, () => { 285 scrolling_toolbox = false; 286 return false; 287 }); 288 } 289 290 public void move (double x, double y) { 291 bool update; 292 bool a; 293 bool consumed = false; 294 bool active; 295 296 y -= current_set.scroll; 297 298 MainWindow.set_cursor (NativeWindow.VISIBLE); 299 300 foreach (Expander exp in current_set.get_expanders ()) { 301 if (exp.visible) { 302 a = exp.is_over (x, y); 303 update = exp.set_active (a); 304 305 if (update) { 306 redraw ((int) exp.x - 10, (int) exp.y - 10, (int) (exp.x + exp.w + 20), (int) (exp.y + exp.h + 20)); 307 } 308 309 foreach (Tool t in exp.tool) { 310 if (t.tool_is_visible ()) { 311 active = t.is_over (x, y); 312 313 if (!active && t.is_active ()) { 314 t.move_out_action (t); 315 } 316 317 update = t.set_active (active); 318 319 if (update) { 320 redraw (0, 0, allocation_width, allocation_height); 321 } 322 323 if (t.panel_move_action (t, x, y)) { 324 consumed = true; 325 } 326 } 327 } 328 } 329 } 330 331 if (scrolling_touch && !consumed && BirdFont.android) { 332 scroll_current_set (y - scroll_y); 333 scroll_y = y; 334 redraw_tool_box (); 335 } 336 } 337 338 public static void redraw_tool_box () { 339 if (MenuTab.has_suppress_event ()) { 340 warn_if_test ("Don't redraw toolbox when background thread is running."); 341 return; 342 } 343 344 Toolbox t = MainWindow.get_toolbox (); 345 if (!is_null (t)) { 346 t.redraw (0, 0, allocation_width, allocation_height); 347 } 348 } 349 350 public void reset_active_tool () { 351 foreach (Expander exp in current_set.get_expanders ()) { 352 foreach (Tool t in exp.tool) { 353 t.set_active (false); 354 } 355 } 356 } 357 358 public Tool? get_active_tool () { 359 foreach (Expander exp in current_set.get_expanders ()) { 360 foreach (Tool t in exp.tool) { 361 if (t.is_active ()) { 362 return t; 363 } 364 } 365 } 366 367 return null; 368 } 369 370 public void set_current_tool (Tool tool) { 371 if (tool.editor_events) { 372 current_tool = tool; 373 } 374 } 375 376 public Tool get_current_tool () { 377 return current_tool; 378 } 379 380 public void select_tool (Tool tool) { 381 bool update; 382 int offset_y; 383 foreach (Expander exp in current_set.get_expanders ()) { 384 if (exp.visible) { 385 foreach (Tool t in exp.tool) { 386 if (tool.get_id () == t.get_id ()) { 387 if (!t.tool_is_visible ()) { 388 warning ("Tool is hidden"); 389 } else { 390 update = false; 391 392 update = tool.set_selected (true); 393 if (tool.persistent) { 394 update = tool.set_active (true); 395 } 396 397 tool.select_action (tool); 398 399 if (update) { 400 offset_y = (int) (exp.y - scroll_y); 401 redraw ((int) exp.x - 10, (int) offset_y - 10, allocation_width, (int) (allocation_height - offset_y + 10)); 402 } 403 404 set_current_tool (tool); 405 } 406 } 407 } 408 } 409 } 410 } 411 412 public Tool get_tool (string name) { 413 foreach (ToolCollection tc in tool_sets) { 414 foreach (Expander e in tc.get_expanders ()) { 415 foreach (Tool t in e.tool) { 416 if (t.get_name () == name) { 417 return t; 418 } 419 } 420 } 421 } 422 423 warning ("No tool found for name \"%s\".\n", name); 424 425 return new Tool ("no_icon"); 426 } 427 428 public static void set_tool_visible (string name, bool visible) { 429 Toolbox tb = MainWindow.get_toolbox (); 430 Tool t = tb.get_tool (name); 431 t.set_tool_visibility (visible); 432 tb.update_expanders (); 433 Toolbox.redraw_tool_box (); 434 } 435 436 public static void select_tool_by_name (string name) { 437 Toolbox b = MainWindow.get_toolbox (); 438 439 if (is_null (b)) { 440 return; 441 } 442 443 b.select_tool (b.get_tool (name)); 444 } 445 446 public static double get_scale () { 447 return MainWindow.units; 448 } 449 450 public void set_default_tool_size () { 451 foreach (ToolCollection t in tool_sets) { 452 foreach (Expander e in t.get_expanders ()) { 453 e.update_tool_position (); 454 } 455 } 456 } 457 458 public void update_expanders () { 459 double pos; 460 461 foreach (Expander e in current_set.get_expanders ()) { 462 e.set_scroll (current_set.scroll); 463 } 464 465 pos = 4 * get_scale (); 466 foreach (Expander e in current_set.get_expanders ()) { 467 if (e.visible) { 468 e.set_offset (pos); 469 pos += e.get_content_height () + 4 * get_scale (); 470 current_set.content_height = pos; 471 472 if (BirdFont.android) { 473 current_set.content_height *= 1.15; 474 } 475 } 476 } 477 478 foreach (Expander e in current_set.get_expanders ()) { 479 e.set_active (false); 480 } 481 } 482 483 private void draw_expanders (int w, int h, Context cr) { 484 foreach (Expander e in current_set.get_expanders ()) { 485 if (e.visible) { 486 e.draw (cr); 487 } 488 } 489 } 490 491 public void draw (int w, int h, Context cr) { 492 cr.save (); 493 494 Theme.color (cr, "Default Background"); 495 496 cr.rectangle (0, 0, w, h); 497 cr.set_line_width (0); 498 cr.fill (); 499 500 draw_expanders (w, h, cr); 501 502 cr.restore (); 503 504 draw_tool_tip (cr); 505 } 506 507 private void draw_tool_tip (Context cr) { 508 TextArea t; 509 510 if (tool_tip != null && tool_tip != "") { 511 t = new TextArea (17 * get_scale ()); 512 t.allocation = new WidgetAllocation.for_area (0, 0, allocation_width, allocation_height); 513 t.set_editable (false); 514 t.set_text ((!) tool_tip); 515 t.width = allocation_width - 20 * get_scale (); 516 t.min_height = 17 * get_scale (); 517 t.height = 17 * get_scale (); 518 519 t.layout (); 520 521 t.widget_x = 10 * get_scale (); 522 t.widget_y = tool_tip_y - t.height - 5 * get_scale (); 523 524 if (t.widget_y < 5) { 525 t.widget_y = 5; 526 } 527 528 t.draw (cr); 529 } 530 } 531 532 public void hide_tooltip () { 533 if (tool_tip != null) { 534 tool_tip = null; 535 redraw_tool_box (); 536 } 537 } 538 539 public void show_tooltip (string tool_tip, double x, double y) { 540 if (tool_tip != "") { 541 this.tool_tip = tool_tip; 542 this.tool_tip_x = x; 543 this.tool_tip_y = y; 544 545 redraw_tool_box (); 546 } 547 } 548 549 public void set_current_tool_set (ToolCollection ts) { 550 current_set = ts; 551 } 552 553 public class EmptySet : ToolCollection { 554 Gee.ArrayList<Expander> expanders; 555 556 public EmptySet () { 557 expanders = new Gee.ArrayList<Expander> (); 558 } 559 560 public override Gee.ArrayList<Expander> get_expanders () { 561 return expanders; 562 } 563 } 564 } 565 566 } 567