The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

DrawingTools.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/DrawingTools.vala.
Use other types of graphical objects
1 /* 2 Copyright (C) 2012 2013 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 DrawingTools : ToolCollection { 21 GlyphCanvas glyph_canvas; 22 23 public Gee.ArrayList<Expander> expanders = new Gee.ArrayList<Expander> (); 24 25 public static Expander draw_tools { get; set; } 26 public static Expander grid_expander { get; set; } 27 public static Expander shape_tools { get; set; } 28 public static Expander draw_tool_modifiers { get; set; } 29 public static Expander layer_tools { get; set; } 30 public static Expander layer_settings { get; set; } 31 public static Expander stroke_expander { get; set; } 32 public static Expander zoombar_tool { get; set; } 33 public static Expander guideline_tools { get; set; } 34 35 public static Expander font_name { get; set; } 36 public static Expander key_tools { get; set; } 37 public static Expander test_tools { get; set; } 38 public static Expander grid { get; set; } 39 40 public static PointType point_type = PointType.DOUBLE_CURVE; 41 42 public static Tool add_stroke { get; set; } 43 public static SpinButton object_stroke; 44 Tool outline; 45 46 public static MoveTool move_tool { get; set; } 47 public static PenTool pen_tool; 48 49 public static BezierTool bezier_tool; 50 PointTool point_tool; 51 public static ZoomTool zoom_tool; 52 public static ResizeTool resize_tool; 53 public static TrackTool track_tool; 54 public static BackgroundTool move_background; 55 public static Tool move_canvas; 56 public static Tool add_layer; 57 public static Tool show_layers; 58 59 static Tool quadratic_points; 60 static Tool cubic_points; 61 static Tool double_points; 62 static Tool convert_points; 63 64 public static CutBackgroundTool cut_background; 65 Tool show_bg; 66 Tool bg_selection; 67 public static SpinButton background_threshold; 68 public static SpinButton background_scale; 69 Tool high_contrast_background; 70 public static SpinButton auto_trace_resolution; 71 Tool auto_trace; 72 public static SpinButton auto_trace_simplify; 73 Tool delete_background; 74 75 Tool rectangle; 76 Tool circle; 77 78 public static Tool help_lines { get; set; } 79 public static Tool xheight_help_lines { get; set; } 80 public static Tool background_help_lines { get; set; } 81 public static GridTool show_grid { get; set; } 82 public static Tool lock_grid { get; set; } 83 84 SpinButton x_coordinate; 85 SpinButton y_coordinate; 86 SpinButton rotation; 87 SpinButton width; 88 SpinButton height; 89 90 Tool tie_handles; 91 Tool reflect_handle; 92 Tool create_line; 93 Tool close_path_tool; 94 95 Tool delete_button; 96 public Tool insert_point_on_path_tool; 97 Tool undo_tool; 98 Tool select_all_button; 99 100 OrientationTool reverse_path_tool; 101 Tool move_layer; 102 Tool flip_vertical; 103 Tool flip_horizontal; 104 Tool full_height_tool; 105 106 public ZoomBar zoom_bar; 107 108 static Tool line_cap_butt; 109 static Tool line_cap_round; 110 static Tool line_cap_square; 111 112 private Text backgrounds_headline = new Text (t_("Background Tools")); 113 private Text control_points_headline = new Text (t_("Control Points")); 114 private Text object_tools_headline = new Text (t_("Object Tools")); 115 116 public DrawingTools (GlyphCanvas main_glyph_canvas) { 117 bool selected_line; 118 119 glyph_canvas = main_glyph_canvas; 120 121 background_scale = new SpinButton (); 122 123 draw_tools = new Expander (t_("Drawing Tools")); 124 draw_tool_modifiers = new Expander (t_("Control Point")); 125 layer_tools = new Expander (); 126 layer_settings = new Expander (t_("Layers")); 127 stroke_expander = new Expander (t_("Stroke")); 128 shape_tools = new Expander (t_("Geometrical Shapes")); 129 zoombar_tool = new Expander (t_("Zoom")); 130 guideline_tools = new Expander (t_("Guidelines & Grid")); 131 132 font_name = new Expander (); 133 key_tools = new Expander (); // tools on android 134 test_tools = new Expander (); 135 grid = new Expander (t_("Grid Size")); 136 137 grid_expander = grid; 138 139 // font name 140 font_name.add_tool (new FontName ()); 141 142 // Draw tools 143 bezier_tool = new BezierTool ("bezier_tool"); 144 bezier_tool.select_action.connect ((self) => { 145 update_drawing_and_background_tools (self); 146 }); 147 draw_tools.add_tool (bezier_tool); 148 149 pen_tool = new PenTool ("pen_tool"); 150 pen_tool.select_action.connect ((self) => { 151 update_drawing_and_background_tools (self); 152 }); 153 draw_tools.add_tool (pen_tool); 154 155 point_tool = new PointTool ("point_tool"); 156 point_tool.select_action.connect ((self) => { 157 update_drawing_and_background_tools (self); 158 }); 159 draw_tools.add_tool (point_tool); 160 161 zoom_tool = new ZoomTool ("zoom_tool"); 162 zoom_tool.select_action.connect ((self) => { 163 update_drawing_and_background_tools (self); 164 }); 165 #if ANDROID 166 Toolbox.hidden_tools.hidden_expander.add_tool (zoom_tool); 167 #else 168 draw_tools.add_tool (zoom_tool); 169 #endif 170 move_tool = new MoveTool ("move"); 171 move_tool.select_action.connect ((self) => { 172 update_drawing_and_background_tools (self); 173 }); 174 draw_tools.add_tool (move_tool); 175 176 resize_tool = new ResizeTool ("resize"); 177 resize_tool.select_action.connect ((self) => { 178 update_drawing_and_background_tools (self); 179 }); 180 draw_tools.add_tool (resize_tool); 181 182 track_tool = new TrackTool ("track"); // draw outline on freehand 183 track_tool.select_action.connect ((self) => { 184 update_drawing_and_background_tools (self); 185 }); 186 draw_tools.add_tool (track_tool); 187 188 move_background = new BackgroundTool ("move_background"); 189 move_background.select_action.connect ((self) => { 190 update_drawing_and_background_tools (self); 191 }); 192 draw_tools.add_tool (move_background); 193 194 move_canvas = new Tool ("move_canvas", t_("Move canvas")); 195 move_canvas.select_action.connect ((self) => { 196 update_drawing_and_background_tools (self); 197 }); 198 draw_tools.add_tool (move_canvas); 199 200 // Tools on android 201 // Delete key 202 delete_button = new Tool ("delete_button", t_("Delete")); 203 delete_button.select_action.connect ((self) => { 204 TabContent.key_press (Key.DEL); 205 }); 206 key_tools.add_tool (delete_button); 207 208 // Select all points or paths 209 select_all_button = new Tool ("select_all", t_("Select all points or paths")); 210 select_all_button.select_action.connect ((self) => { 211 Glyph g = MainWindow.get_current_glyph (); 212 213 if (point_tool.is_selected () 214 || pen_tool.is_selected () 215 || track_tool.is_selected ()) { 216 pen_tool.select_all_points (); 217 g.open_path (); 218 } else { 219 DrawingTools.move_tool.select_all_paths (); 220 } 221 }); 222 key_tools.add_tool (select_all_button); 223 224 // Undo 225 undo_tool = new Tool ("undo_tool", t_("Undo")); 226 undo_tool.select_action.connect ((self) => { 227 TabContent.undo (); 228 }); 229 key_tools.add_tool (undo_tool); 230 231 bool insert_points = false; 232 insert_point_on_path_tool = new Tool ("new_point_on_path", t_("Insert new points on path")); 233 insert_point_on_path_tool.select_action.connect ((self) => { 234 insert_points = !insert_points; 235 insert_point_on_path_tool.set_selected (insert_points); 236 }); 237 insert_point_on_path_tool.set_persistent (true); 238 key_tools.add_tool (insert_point_on_path_tool); 239 240 // quadratic Bézier points 241 quadratic_points = new Tool ("quadratic_points", t_("Create quadratic Bézier curves")); 242 quadratic_points.select_action.connect ((self) => { 243 point_type = PointType.QUADRATIC; 244 Preferences.set ("point_type", "quadratic_points"); 245 update_type_selection (); 246 }); 247 draw_tool_modifiers.add_tool (quadratic_points); 248 249 // cubic Bézier points 250 cubic_points = new Tool ("cubic_points", t_("Create cubic Bézier curves")); 251 cubic_points.select_action.connect ((self) => { 252 point_type = PointType.CUBIC; 253 Preferences.set ("point_type", "cubic_points"); 254 update_type_selection (); 255 }); 256 draw_tool_modifiers.add_tool (cubic_points); 257 258 // two quadratic points off curve points for each quadratic control point 259 double_points = new Tool ("double_points", t_("Quadratic path with two line handles")); 260 double_points.select_action.connect ((self) => { 261 point_type = PointType.DOUBLE_CURVE; 262 Preferences.set ("point_type", "double_points"); 263 update_type_selection (); 264 }); 265 draw_tool_modifiers.add_tool (double_points); 266 267 // convert point 268 convert_points = new Tool ("convert_point", t_("Convert selected points")); 269 convert_points.select_action.connect ((self) => { 270 PenTool.convert_point_types (); 271 GlyphCanvas.redraw (); 272 update_type_selection (); 273 PenTool.reset_stroke (); 274 }); 275 convert_points.set_persistent (false); 276 draw_tool_modifiers.add_tool (convert_points); 277 278 // x coordinate 279 x_coordinate = new SpinButton ("x_coordinate", t_("X coordinate")); 280 x_coordinate.set_big_number (true); 281 x_coordinate.set_int_value ("0.000"); 282 x_coordinate.set_int_step (0.1); 283 x_coordinate.set_min (-999.99); 284 x_coordinate.set_max (999.99); 285 x_coordinate.show_icon (true); 286 x_coordinate.set_persistent (false); 287 x_coordinate.new_value_action.connect((self) => { 288 Glyph glyph = MainWindow.get_current_glyph (); 289 double x, y, w, h; 290 double delta; 291 292 glyph.selection_boundaries (out x, out y, out w, out h); 293 delta = x_coordinate.get_value () - x + glyph.left_limit; 294 295 foreach (Object path in glyph.active_paths) { 296 path.move (delta, 0); 297 } 298 299 GlyphCanvas.redraw (); 300 }); 301 draw_tool_modifiers.add_tool (x_coordinate); 302 303 move_tool.objects_moved.connect (() => { 304 Glyph glyph = MainWindow.get_current_glyph (); 305 x_coordinate.set_value_round (MoveTool.selection_box_center_x 306 - (MoveTool.selection_box_width / 2) 307 - glyph.left_limit, true, false); 308 }); 309 310 move_tool.selection_changed.connect (() => { 311 Glyph glyph = MainWindow.get_current_glyph (); 312 x_coordinate.set_value_round (MoveTool.selection_box_center_x 313 - (MoveTool.selection_box_width / 2) 314 - glyph.left_limit, true, false); 315 }); 316 317 move_tool.objects_deselected.connect (() => { 318 x_coordinate.set_value_round (0, true, false); 319 x_coordinate.hide_value (); 320 }); 321 322 // y coordinate 323 y_coordinate = new SpinButton ("y_coordinate", t_("Y coordinate")); 324 y_coordinate.set_big_number (true); 325 y_coordinate.set_int_value ("0.000"); 326 y_coordinate.set_int_step (0.1); 327 y_coordinate.set_min (-999.99); 328 y_coordinate.set_max (999.99); 329 y_coordinate.show_icon (true); 330 y_coordinate.set_persistent (false); 331 y_coordinate.new_value_action.connect((self) => { 332 double x, y, w, h; 333 Glyph glyph = MainWindow.get_current_glyph (); 334 Font font = BirdFont.get_current_font (); 335 336 glyph.selection_boundaries (out x, out y, out w, out h); 337 338 foreach (Path path in glyph.get_active_paths ()) { 339 path.move (0, y_coordinate.get_value () - (y - h) - font.base_line); 340 } 341 342 GlyphCanvas.redraw (); 343 }); 344 draw_tool_modifiers.add_tool (y_coordinate); 345 346 move_tool.objects_moved.connect (() => { 347 Font font = BirdFont.get_current_font (); 348 y_coordinate.set_value_round (MoveTool.selection_box_center_y 349 - (MoveTool.selection_box_height / 2) 350 + font.base_line, true, false); 351 }); 352 353 move_tool.selection_changed.connect (() => { 354 Font font = BirdFont.get_current_font (); 355 y_coordinate.set_value_round (MoveTool.selection_box_center_y 356 - (MoveTool.selection_box_height / 2) 357 + font.base_line, true, false); 358 }); 359 360 move_tool.objects_deselected.connect (() => { 361 y_coordinate.set_value_round (0, true, false); 362 y_coordinate.hide_value (); 363 }); 364 365 // rotation 366 rotation = new SpinButton ("rotation", t_("Rotation")); 367 rotation.set_big_number (true); 368 rotation.set_int_value ("0.000"); 369 rotation.set_int_step (0.1); 370 rotation.set_min (-360); 371 rotation.set_max (360); 372 rotation.show_icon (true); 373 rotation.set_persistent (false); 374 rotation.new_value_action.connect ((self) => { 375 double x, y, w, h; 376 Glyph glyph = MainWindow.get_current_glyph (); 377 double angle = (self.get_value () / 360) * 2 * PI; 378 Object last_path; 379 glyph.selection_boundaries (out x, out y, out w, out h); 380 381 x += w / 2; 382 y -= h / 2; 383 384 if (glyph.active_paths.size > 0) { 385 last_path = glyph.active_paths.get (glyph.active_paths.size - 1); 386 resize_tool.rotate_selected_paths (angle - last_path.rotation, x, y); 387 } 388 389 GlyphCanvas.redraw (); 390 }); 391 392 resize_tool.objects_rotated.connect ((angle) => { 393 rotation.set_value_round (angle, true, false); 394 PenTool.reset_stroke (); 395 }); 396 397 move_tool.objects_deselected.connect (() => { 398 rotation.set_value_round (0, true, false); 399 rotation.hide_value (); 400 }); 401 402 draw_tool_modifiers.add_tool (rotation); 403 404 // width 405 width = new SpinButton ("width", t_("Width")); 406 width.set_big_number (true); 407 width.set_int_value ("0.0000"); 408 width.set_int_step (0.01); 409 width.show_icon (true); 410 width.set_persistent (false); 411 width.new_value_action.connect ((self) => { 412 double x, y, w, h; 413 Glyph glyph; 414 double new_size; 415 416 glyph = MainWindow.get_current_glyph (); 417 glyph.selection_boundaries (out x, out y, out w, out h); 418 419 new_size = self.get_value () / w; 420 421 if (self.get_value () > 0 && new_size != 1) { 422 resize_tool.resize_selected_paths (new_size, new_size); 423 } 424 425 GlyphCanvas.redraw (); 426 }); 427 draw_tool_modifiers.add_tool (width); 428 429 // height 430 height = new SpinButton ("height", t_("Height")); 431 height.set_big_number (true); 432 height.set_int_value ("0.0000"); 433 height.set_int_step (0.01); 434 height.show_icon (true); 435 height.set_persistent (false); 436 height.new_value_action.connect ((self) => { 437 double x, y, w, h; 438 Glyph glyph; 439 double new_size; 440 441 glyph = MainWindow.get_current_glyph (); 442 glyph.selection_boundaries (out x, out y, out w, out h); 443 444 new_size = self.get_value () / h; 445 446 if (self.get_value () > 0 && new_size != 1) { 447 resize_tool.resize_selected_paths (new_size, new_size); 448 } 449 450 GlyphCanvas.redraw (); 451 }); 452 draw_tool_modifiers.add_tool (height); 453 454 resize_tool.objects_resized.connect ((w, h) => { 455 height.set_value_round (h, true, false); 456 width.set_value_round (w, true, false); 457 }); 458 459 move_tool.objects_deselected.connect (() => { 460 width.set_value_round (0, true, false); 461 width.hide_value (); 462 463 height.set_value_round (0, true, false); 464 height.hide_value (); 465 }); 466 467 move_tool.objects_moved.connect (() => { 468 width.set_value_round (MoveTool.selection_box_width, true, false); 469 height.set_value_round (MoveTool.selection_box_height, true, false); 470 }); 471 472 // tie edit point handles 473 tie_handles = new Tool ("tie_point", t_("Tie curve handles for the selected edit point")); 474 tie_handles.select_action.connect ((self) => { 475 bool tie, end_point; 476 EditPoint p; 477 478 if (PenTool.move_selected_handle) { 479 p = PenTool.active_handle.parent; 480 tie = !p.tie_handles; 481 482 // don't tie end points 483 foreach (Path path in MainWindow.get_current_glyph ().get_active_paths ()) { 484 if (path.is_open ()) { 485 if (p == path.get_first_point () || p == path.get_last_point ()) { 486 tie = false; 487 } 488 } 489 } 490 491 if (tie) { 492 p.process_tied_handle (); 493 p.set_reflective_handles (false); 494 } 495 496 p.set_tie_handle (tie); 497 498 PenTool.handle_selection.path.update_region_boundaries (); 499 } else { 500 foreach (PointSelection ep in PenTool.selected_points) { 501 tie = !ep.point.tie_handles; 502 503 end_point = ep.point == ep.path.get_first_point () 504 || ep.point == ep.path.get_last_point (); 505 506 if (!ep.path.is_open () || !end_point) { 507 if (tie) { 508 ep.point.process_tied_handle (); 509 ep.point.set_reflective_handles (false); 510 } 511 512 ep.point.set_tie_handle (tie); 513 ep.path.update_region_boundaries (); 514 } 515 } 516 } 517 518 MainWindow.get_current_glyph ().update_view (); 519 PenTool.reset_stroke (); 520 }); 521 draw_tool_modifiers.add_tool (tie_handles); 522 523 // symmetrical handles 524 reflect_handle = new Tool ("symmetric", t_("Symmetrical handles")); 525 reflect_handle.select_action.connect ((self) => { 526 bool symmetrical, end_point; 527 PointSelection ep; 528 if (PenTool.selected_points.size > 0) { 529 ep = PenTool.selected_points.get (0); 530 symmetrical = ep.point.reflective_point; 531 532 foreach (PointSelection p in PenTool.selected_points) { 533 end_point = p.point == p.path.get_first_point () 534 || p.point == p.path.get_last_point (); 535 536 if (!p.path.is_open () || !end_point) { 537 p.point.set_reflective_handles (!symmetrical); 538 p.point.process_symmetrical_handles (); 539 540 if (symmetrical) { 541 ep.point.set_tie_handle (false); 542 } 543 544 p.path.update_region_boundaries (); 545 } 546 } 547 MainWindow.get_current_glyph ().update_view (); 548 } 549 550 PenTool.reset_stroke (); 551 }); 552 draw_tool_modifiers.add_tool (reflect_handle); 553 554 create_line = new Tool ("create_line", t_("Convert segment to line.")); 555 create_line.select_action.connect ((self) => { 556 PenTool.convert_segment_to_line (); 557 MainWindow.get_current_glyph ().update_view (); 558 PenTool.reset_stroke (); 559 }); 560 draw_tool_modifiers.add_tool (create_line); 561 562 reverse_path_tool = new OrientationTool ("reverse_path", t_("Create counter from outline")); 563 draw_tool_modifiers.add_tool (reverse_path_tool); 564 565 full_height_tool = new Tool ("full_height", t_("Scale object to font top/baseline")); 566 full_height_tool.select_action.connect ((self) => { 567 resize_tool.full_height (); 568 GlyphCanvas.redraw (); 569 }); 570 571 draw_tool_modifiers.add_tool (full_height_tool); 572 573 // close path 574 close_path_tool = new Tool ("close_path", t_("Close path")); 575 close_path_tool.select_action.connect ((self) => { 576 Tool current; 577 Glyph g; 578 579 current = MainWindow.get_toolbox ().get_current_tool (); 580 581 if (current is BezierTool) { 582 ((BezierTool) current).stop_drawing (); 583 } 584 585 PenTool.reset_stroke (); 586 587 g = MainWindow.get_current_glyph (); 588 g.close_path (); 589 g.clear_active_paths (); 590 591 self.set_selected (false); 592 GlyphCanvas.redraw (); 593 }); 594 draw_tool_modifiers.add_tool (close_path_tool); 595 596 move_layer = new Tool ("move_layer", t_("Move to path to the bottom of the layer")); 597 move_layer.select_action.connect ((self) => { 598 Glyph g = MainWindow.get_current_glyph (); 599 Layer layer = g.get_current_layer (); 600 601 foreach (Object p in g.active_paths) { 602 layer.remove (p); 603 layer.objects.objects.insert (0, p); 604 } 605 606 GlyphCanvas.redraw (); 607 }); 608 draw_tool_modifiers.add_tool (move_layer); 609 610 flip_vertical = new Tool ("flip_vertical", t_("Flip path vertically")); 611 flip_vertical.select_action.connect ((self) => { 612 MoveTool.flip_vertical (); 613 MainWindow.get_current_glyph ().update_view (); 614 PenTool.reset_stroke (); 615 }); 616 draw_tool_modifiers.add_tool (flip_vertical); 617 618 flip_horizontal = new Tool ("flip_horizontal", t_("Flip path horizontally")); 619 flip_horizontal.select_action.connect ((self) => { 620 MoveTool.flip_horizontal (); 621 MainWindow.get_current_glyph ().update_view (); 622 PenTool.reset_stroke (); 623 }); 624 draw_tool_modifiers.add_tool (flip_horizontal); 625 626 // background tools 627 background_scale = new SpinButton ("scale_background", t_("Set size for background image")); 628 background_scale.show_icon (true); 629 background_scale.set_int_value ("1.000"); 630 631 background_scale.new_value_action.connect((self) => { 632 background_scale.select_action (self); 633 }); 634 635 background_scale.select_action.connect((self) => { 636 SpinButton sb = (SpinButton) self; 637 Glyph g = MainWindow.get_current_glyph (); 638 BackgroundImage? img = g.get_background_image (); 639 double s = sb.get_value (); 640 BackgroundImage i; 641 double xc, yc; 642 643 if (img != null) { 644 i = (!) img; 645 xc = i.img_middle_x; 646 yc = i.img_middle_y; 647 648 i.set_img_scale (s, s); 649 650 i.img_middle_x = xc; 651 i.img_middle_y = yc; 652 } 653 654 GlyphCanvas.redraw (); 655 }); 656 657 draw_tool_modifiers.add_tool (background_scale); 658 659 cut_background = new CutBackgroundTool ("cut_background"); 660 cut_background.select_action.connect ((self) => { 661 update_drawing_and_background_tools (self); 662 }); 663 draw_tool_modifiers.add_tool (cut_background); 664 665 show_bg = new Tool ("show_background", t_("Show/hide background image")); 666 show_bg.select_action.connect ((self) => { 667 update_drawing_and_background_tools (self); 668 }); 669 show_bg.select_action.connect ((self) => { 670 Glyph g = MainWindow.get_current_glyph (); 671 g.set_background_visible (!g.get_background_visible ()); 672 GlyphCanvas.redraw (); 673 }); 674 draw_tool_modifiers.add_tool (show_bg); 675 676 bg_selection = new Tool ("insert_background", t_("Insert a new background image")); 677 bg_selection.select_action.connect ((self) => { 678 update_drawing_and_background_tools (self); 679 }); 680 681 bg_selection.select_action.connect((self) => { 682 if (MainWindow.get_current_display () is Glyph) { 683 BackgroundTool.import_background_image (); 684 } 685 }); 686 687 bg_selection.set_show_background (true); 688 draw_tool_modifiers.add_tool (bg_selection); 689 690 high_contrast_background = new Tool ("high_contrast_background", t_("High contrast")); 691 high_contrast_background.select_action.connect ((self) => { 692 Glyph g = MainWindow.get_current_glyph (); 693 BackgroundImage? bg = g.get_background_image (); 694 BackgroundImage b; 695 696 if (bg != null) { 697 b = (!) bg; 698 b.set_high_contrast (!b.high_contrast); 699 b.update_background (); 700 } 701 }); 702 draw_tool_modifiers.add_tool (high_contrast_background); 703 704 background_threshold = new SpinButton ("contrast_threshold", t_("Set background threshold")); 705 background_threshold.show_icon (true); 706 background_threshold.set_value_round (1); 707 708 background_threshold.new_value_action.connect ((self) => { 709 Glyph g = MainWindow.get_current_glyph (); 710 BackgroundImage? bg = g.get_background_image (); 711 BackgroundImage b; 712 713 if (bg != null) { 714 b = (!) bg; 715 b.update_background (); 716 } 717 718 BirdFont.get_current_font ().settings.set_setting ("autotrace_threshold", background_threshold.get_display_value ()); 719 }); 720 721 draw_tool_modifiers.add_tool (background_threshold); 722 723 auto_trace_resolution = new SpinButton ("auto_trace_resolution", t_("Amount of autotrace details")); 724 auto_trace_resolution.set_value_round (1); 725 auto_trace_resolution.show_icon (true); 726 727 auto_trace_resolution.new_value_action.connect ((self) => { 728 Glyph g = MainWindow.get_current_glyph (); 729 BackgroundImage? bg = g.get_background_image (); 730 BackgroundImage b; 731 732 if (bg != null) { 733 b = (!) bg; 734 b.update_background (); 735 } 736 737 BirdFont.get_current_font ().settings.set_setting ("autotrace_resolution", auto_trace_resolution.get_display_value ()); 738 }); 739 740 draw_tool_modifiers.add_tool (auto_trace_resolution); 741 742 auto_trace_simplify = new SpinButton ("auto_trace_simplify", t_("Autotrace simplification")); 743 auto_trace_simplify.set_value_round (0.5); 744 auto_trace_simplify.show_icon (true); 745 746 auto_trace_simplify.new_value_action.connect ((self) => { 747 BirdFont.get_current_font ().settings.set_setting ("autotrace_simplification", background_threshold.get_display_value ()); 748 }); 749 750 draw_tool_modifiers.add_tool (auto_trace_simplify); 751 752 auto_trace = new Tool ("autotrace", t_("Autotrace background image")); 753 auto_trace.select_action.connect ((self) => { 754 Task t = new Task (auto_trace_background); 755 MainWindow.run_blocking_task (t); 756 }); 757 758 draw_tool_modifiers.add_tool (auto_trace); 759 760 delete_background = new Tool ("delete_background", t_("Delete background image")); 761 delete_background.select_action.connect ((self) => { 762 MainWindow.get_current_glyph ().delete_background (); 763 }); 764 765 draw_tool_modifiers.add_tool (delete_background); 766 767 add_layer = new Tool ("add_layer", t_("Add layer")); 768 add_layer.select_action.connect ((self) => { 769 layer_tools.visible = true; 770 MainWindow.get_current_glyph ().add_new_layer (); 771 update_layers (); // FIXME: speed optimization 772 show_layers.selected = true; 773 add_layer.selected = false; 774 }); 775 layer_settings.add_tool (add_layer); 776 777 show_layers = new Tool ("show_layers", t_("Show layers")); 778 show_layers.select_action.connect ((self) => { 779 layer_tools.visible = !layer_tools.visible; 780 MainWindow.get_toolbox ().update_expanders (); 781 Toolbox.redraw_tool_box (); 782 show_layers.selected = layer_tools.visible; 783 }); 784 layer_settings.add_tool (show_layers); 785 786 // add stroke to path 787 add_stroke = new Tool ("apply_stroke", t_("Apply stroke")); 788 789 add_stroke.select_action.connect ((self) => { 790 Font f; 791 Glyph g = MainWindow.get_current_glyph (); 792 StrokeTool.add_stroke = !StrokeTool.add_stroke; 793 StrokeTool.stroke_width = object_stroke.get_value (); 794 795 add_stroke.selected = StrokeTool.add_stroke; 796 set_stroke_tool_visibility (); 797 GlyphCanvas.redraw (); 798 g.store_undo_state (); 799 800 if (StrokeTool.add_stroke) { 801 foreach (Object p in g.active_paths) { 802 p.stroke = StrokeTool.stroke_width; 803 p.line_cap = StrokeTool.line_cap; 804 } 805 } else { 806 foreach (Object p in g.active_paths) { 807 p.stroke = 0; 808 } 809 } 810 811 f = BirdFont.get_current_font (); 812 f.settings.set_setting ("apply_stroke", @"$(StrokeTool.add_stroke)"); 813 814 stroke_expander.redraw (); 815 MainWindow.get_toolbox ().update_expanders (); 816 }); 817 stroke_expander.add_tool (add_stroke); 818 add_stroke.selected = StrokeTool.add_stroke; 819 820 // edit stroke width 821 object_stroke = new SpinButton ("object_stroke", t_("Stroke width")); 822 object_stroke.set_big_number (true); 823 object_stroke.set_value_round (2); 824 object_stroke.set_max (0.01); 825 object_stroke.set_max (50); 826 827 object_stroke.new_value_action.connect((self) => { 828 Font f; 829 Glyph g = MainWindow.get_current_glyph (); 830 831 bool tool = resize_tool.is_selected () 832 || move_tool.is_selected () 833 || pen_tool.is_selected () 834 || track_tool.is_selected () 835 || point_tool.is_selected () 836 || bezier_tool.is_selected (); 837 838 StrokeTool.stroke_width = object_stroke.get_value (); 839 840 if (tool && StrokeTool.add_stroke) { 841 foreach (Object p in g.active_paths) { 842 p.stroke = StrokeTool.stroke_width; 843 844 if (p is FastPath) { 845 Path path = ((FastPath) p).get_path (); 846 path.reset_stroke (); 847 } 848 } 849 } 850 851 f = BirdFont.get_current_font (); 852 f.settings.set_setting ("stroke_width", object_stroke.get_display_value ()); 853 854 GlyphCanvas.redraw (); 855 }); 856 stroke_expander.add_tool (object_stroke); 857 858 move_tool.selection_changed.connect (() => { 859 update_stroke_settings (); 860 }); 861 862 move_tool.objects_moved.connect (() => { 863 update_stroke_settings (); 864 }); 865 866 // create outline from path 867 outline = new Tool ("stroke_to_outline", t_("Create outline form stroke")); 868 outline.select_action.connect ((self) => { 869 StrokeTool s = new StrokeTool (); 870 s.stroke_selected_paths (); 871 outline.set_selected (false); 872 }); 873 stroke_expander.add_tool (outline); 874 875 // set line cap 876 line_cap_butt = new Tool ("line_cap_butt", t_("Butt line cap")); 877 line_cap_butt.select_action.connect ((self) => { 878 Glyph g; 879 880 g = MainWindow.get_current_glyph (); 881 g.store_undo_state (); 882 883 foreach (Object p in g.active_paths) { 884 p.line_cap = LineCap.BUTT; 885 886 if (p is FastPath) { 887 ((FastPath) p).get_path ().reset_stroke (); 888 } 889 } 890 891 StrokeTool.line_cap = LineCap.BUTT; 892 Font f = BirdFont.get_current_font (); 893 f.settings.set_setting ("line_cap", @"butt"); 894 895 line_cap_butt.selected = true; 896 line_cap_round.selected = false; 897 line_cap_square.selected = false; 898 899 GlyphCanvas.redraw (); 900 }); 901 stroke_expander.add_tool (line_cap_butt); 902 903 line_cap_round = new Tool ("line_cap_round", t_("Round line cap")); 904 line_cap_round.select_action.connect ((self) => { 905 Glyph g; 906 907 g = MainWindow.get_current_glyph (); 908 g.store_undo_state (); 909 910 foreach (Object p in g.active_paths) { 911 p.line_cap = LineCap.ROUND; 912 913 if (p is FastPath) { 914 ((FastPath) p).get_path ().reset_stroke (); 915 } 916 } 917 918 StrokeTool.line_cap = LineCap.ROUND; 919 920 Font f = BirdFont.get_current_font (); 921 f.settings.set_setting ("line_cap", @"round"); 922 923 line_cap_butt.selected = false; 924 line_cap_round.selected = true; 925 line_cap_square.selected = false; 926 927 GlyphCanvas.redraw (); 928 }); 929 stroke_expander.add_tool (line_cap_round); 930 931 line_cap_square = new Tool ("line_cap_square", t_("Square line cap")); 932 line_cap_square.select_action.connect ((self) => { 933 Glyph g; 934 935 g = MainWindow.get_current_glyph (); 936 g.store_undo_state (); 937 938 foreach (Object p in g.active_paths) { 939 p.line_cap = LineCap.SQUARE; 940 941 if (p is FastPath) { 942 ((FastPath) p).get_path ().reset_stroke (); 943 } 944 } 945 946 StrokeTool.line_cap = LineCap.SQUARE; 947 948 Font f = BirdFont.get_current_font (); 949 f.settings.set_setting ("line_cap", @"square"); 950 951 line_cap_butt.selected = false; 952 line_cap_round.selected = false; 953 line_cap_square.selected = true; 954 955 GlyphCanvas.redraw (); 956 }); 957 stroke_expander.add_tool (line_cap_square); 958 959 // tests 960 if (BirdFont.has_argument ("--test")) { 961 Tool test_case = new Tool ("test_case"); 962 test_case.select_action.connect((self) => { 963 if (self.is_selected ()) { 964 if (TestBirdFont.is_running ()) { 965 TestBirdFont.pause (); 966 } else { 967 TestBirdFont.continue (); 968 } 969 } 970 }); 971 test_tools.add_tool (test_case); 972 973 Tool slow_test = new Tool ("slow_test"); 974 slow_test.select_action.connect((self) => { 975 bool s = TestBirdFont.is_slow_test (); 976 TestBirdFont.set_slow_test (!s); 977 s = TestBirdFont.is_slow_test (); 978 self.set_selected (s); 979 }); 980 981 test_tools.add_tool (slow_test); 982 983 // Run from commad line 984 string? st = BirdFont.get_argument ("--test"); 985 if (st != null && ((!)st).char_count () > 0) { 986 IdleSource idle = new IdleSource (); 987 988 idle.set_callback (() => { 989 MainWindow.get_toolbox ().select_tool (test_case); 990 return false; 991 }); 992 993 idle.attach (null); 994 } 995 996 if (BirdFont.has_argument ("--slow")) { 997 MainWindow.get_toolbox ().select_tool (slow_test); 998 } 999 1000 } 1001 1002 // guide lines, grid and other guidlines 1003 help_lines = new Tool ("help_lines", t_("Show guidelines")); 1004 help_lines.select_action.connect ((self) => { 1005 bool h; 1006 h = GlyphCanvas.get_current_glyph ().get_show_help_lines (); 1007 GlyphCanvas.get_current_glyph ().set_show_help_lines (!h); 1008 self.set_selected (!h); 1009 GlyphCanvas.get_current_glyph ().redraw_help_lines (); 1010 }); 1011 selected_line = GlyphCanvas.get_current_glyph ().get_show_help_lines (); 1012 help_lines.set_selected (selected_line); 1013 guideline_tools.add_tool (help_lines); 1014 1015 xheight_help_lines = new Tool ("show_xheight_helplines", t_("Show more guidelines")); 1016 xheight_help_lines.select_action.connect ((self) => { 1017 Glyph g = MainWindow.get_current_glyph (); 1018 bool v = !g.get_xheight_lines_visible (); 1019 g.set_xheight_lines_visible (v); 1020 self.set_selected (v); 1021 GlyphCanvas.redraw (); 1022 1023 if (v && !help_lines.is_selected ()) { 1024 MainWindow.get_toolbox ().select_tool (help_lines); 1025 } 1026 }); 1027 selected_line = GlyphCanvas.get_current_glyph ().get_xheight_lines_visible (); 1028 xheight_help_lines.set_selected (selected_line); 1029 guideline_tools.add_tool (xheight_help_lines); 1030 1031 background_help_lines = new Tool ("background_help_lines", t_("Show guidelines at top and bottom margin")); 1032 background_help_lines.select_action.connect ((self) => { 1033 Glyph g = MainWindow.get_current_glyph (); 1034 bool v = !g.get_margin_lines_visible (); 1035 g.set_margin_lines_visible (v); 1036 self.set_selected (v); 1037 GlyphCanvas.redraw (); 1038 1039 if (v && !help_lines.is_selected ()) { 1040 MainWindow.get_toolbox ().select_tool (help_lines); 1041 } 1042 }); 1043 selected_line = GlyphCanvas.get_current_glyph ().get_margin_lines_visible (); 1044 background_help_lines.set_selected (selected_line); 1045 guideline_tools.add_tool (background_help_lines); 1046 1047 show_grid = new GridTool ("show_grid"); 1048 show_grid.select_action.connect (() => { 1049 grid_expander.visible = show_grid.selected; 1050 MainWindow.get_toolbox ().update_expanders (); 1051 }); 1052 guideline_tools.add_tool (show_grid); 1053 grid_expander.visible = false; 1054 1055 lock_grid = new Tool ("lock_grid", t_("Lock guides and grid")); 1056 lock_grid.select_action.connect ((self) => { 1057 SpinButton sb; 1058 FontSettings fs; 1059 1060 GridTool.lock_grid = !GridTool.lock_grid; 1061 1062 foreach (Tool t in grid.tool) { 1063 if (t is SpinButton) { 1064 sb = (SpinButton) t; 1065 sb.locked = GridTool.lock_grid; 1066 } 1067 } 1068 1069 lock_grid.selected = GridTool.lock_grid; 1070 fs = BirdFont.get_current_font ().settings; 1071 fs.set_setting ("lock_grid", @"$(GridTool.lock_grid)"); 1072 }); 1073 guideline_tools.add_tool (lock_grid); 1074 1075 // Zoom tools 1076 zoom_bar = new ZoomBar (); 1077 zoom_bar.new_zoom.connect ((z) => { 1078 Glyph g = MainWindow.get_current_glyph (); 1079 double zoom = 20 * z + 1; 1080 double xc, yc, nxc, nyc; 1081 1082 xc = Glyph.path_coordinate_x (Glyph.xc ()); 1083 yc = Glyph.path_coordinate_y (Glyph.yc ()); 1084 1085 g.set_zoom (zoom); 1086 1087 nxc = Glyph.path_coordinate_x (Glyph.xc ()); 1088 nyc = Glyph.path_coordinate_y (Glyph.yc ()); 1089 1090 g.view_offset_x -= nxc - xc; 1091 g.view_offset_y += nyc - yc; 1092 1093 GlyphCanvas.redraw (); 1094 }); 1095 zoombar_tool.add_tool (zoom_bar); 1096 1097 Tool reset_zoom = new Tool ("zoom_1_1", t_("Zoom Out More")); 1098 reset_zoom.select_action.connect ((self) => { 1099 zoom_tool.store_current_view (); 1100 glyph_canvas.get_current_display ().reset_zoom (); 1101 glyph_canvas.redraw_area(0, 0, GlyphCanvas.allocation.width, GlyphCanvas.allocation.height); 1102 }); 1103 zoombar_tool.add_tool (reset_zoom); 1104 reset_zoom.set_tool_visibility (false); 1105 1106 Tool full_glyph = new Tool ("full_glyph", t_("Show full glyph")); 1107 full_glyph.select_action.connect((self) => { 1108 zoom_tool.store_current_view (); 1109 zoom_tool.zoom_full_glyph (); 1110 }); 1111 zoombar_tool.add_tool (full_glyph); 1112 1113 Tool zoom_boundaries = new Tool ("zoom_boundaries", t_("Fit in view")); 1114 zoom_boundaries.select_action.connect((self) => { 1115 zoom_tool.store_current_view (); 1116 glyph_canvas.get_current_display ().zoom_max (); 1117 }); 1118 zoombar_tool.add_tool (zoom_boundaries); 1119 1120 Tool zoom_bg = new Tool ("zoom_background_image", t_("Zoom in on background image")); 1121 zoom_bg.select_action.connect((self) => { 1122 if (MainWindow.get_current_glyph ().get_background_image () != null) { 1123 zoom_tool.store_current_view (); 1124 ZoomTool.zoom_full_background_image (); 1125 glyph_canvas.redraw_area(0, 0, GlyphCanvas.allocation.width, GlyphCanvas.allocation.height); 1126 } 1127 }); 1128 zoombar_tool.add_tool (zoom_bg); 1129 1130 Tool zoom_prev = new Tool ("prev", t_("Previous view")); 1131 zoom_prev.select_action.connect((self) => { 1132 zoom_tool.previous_view (); 1133 }); 1134 zoombar_tool.add_tool (zoom_prev); 1135 1136 Tool zoom_next = new Tool ("next", t_("Next view")); 1137 zoom_next.select_action.connect((self) => { 1138 zoom_tool.next_view (); 1139 }); 1140 zoombar_tool.add_tool (zoom_next); // view_tools 1141 zoom_next.set_tool_visibility (false); 1142 1143 // shape tools 1144 circle = new CircleTool ("circle"); 1145 circle.select_action.connect ((self) => { 1146 update_drawing_and_background_tools (self); 1147 }); 1148 shape_tools.add_tool (circle); 1149 1150 rectangle = new RectangleTool ("rectangle"); 1151 rectangle.select_action.connect ((self) => { 1152 update_drawing_and_background_tools (self); 1153 }); 1154 shape_tools.add_tool (rectangle); 1155 1156 add_expander (font_name); 1157 add_expander (draw_tools); 1158 1159 if (BirdFont.android) { 1160 add_expander (key_tools); 1161 } 1162 1163 add_expander (draw_tool_modifiers); 1164 add_expander (layer_settings); 1165 add_expander (layer_tools); 1166 add_expander (stroke_expander); 1167 add_expander (guideline_tools); 1168 add_expander (grid); 1169 add_expander (zoombar_tool); 1170 add_expander (shape_tools); 1171 1172 // Fixa: add_expander (trace); 1173 if (BirdFont.has_argument ("--test")) { 1174 add_expander (test_tools); 1175 } 1176 1177 layer_settings.set_persistent (true); 1178 layer_settings.set_unique (false); 1179 1180 draw_tools.set_persistent (true); 1181 draw_tools.set_unique (false); 1182 1183 stroke_expander.set_persistent (true); 1184 stroke_expander.set_unique (false); 1185 1186 key_tools.set_persistent (false); 1187 key_tools.set_unique (false); 1188 1189 draw_tool_modifiers.set_persistent (true); 1190 draw_tool_modifiers.set_unique (false); 1191 1192 test_tools.set_persistent (true); 1193 1194 guideline_tools.set_persistent (true); 1195 guideline_tools.set_unique (false); 1196 1197 grid.set_persistent (true); 1198 grid.set_unique (true); 1199 1200 shape_tools.set_persistent (true); 1201 shape_tools.set_unique (true); 1202 1203 // let these tools progagate events even when other tools are selected 1204 foreach (Tool t in draw_tools.tool) { 1205 t.editor_events = true; 1206 } 1207 1208 foreach (Tool t in shape_tools.tool) { 1209 t.editor_events = true; 1210 t.persistent = true; 1211 } 1212 1213 move_background.editor_events = true; 1214 cut_background.editor_events = true; 1215 move_canvas.editor_events = true; 1216 1217 move_background.persistent = true; 1218 cut_background.persistent = true; 1219 move_canvas.persistent = true; 1220 1221 // Default selection 1222 IdleSource idle = new IdleSource (); 1223 idle.set_callback (() => { 1224 Toolbox tb = MainWindow.get_toolbox (); 1225 1226 tb.reset_active_tool (); 1227 update_drawing_and_background_tools (point_tool); 1228 tb.select_tool (point_tool); 1229 tb.set_current_tool (point_tool); 1230 1231 set_point_type_from_preferences (); 1232 1233 if (GlyphCanvas.get_current_glyph ().get_show_help_lines ()) { 1234 help_lines.set_selected (true); 1235 help_lines.set_active (false); 1236 } 1237 1238 add_new_grid (1); 1239 add_new_grid (2); 1240 add_new_grid (4); 1241 1242 MainWindow.get_toolbox ().move (0, 0); 1243 set_stroke_tool_visibility (); 1244 1245 return false; 1246 }); 1247 idle.attach (null); 1248 1249 // update selelction when the user switches tab 1250 MainWindow.get_tab_bar ().signal_tab_selected.connect((tab) => { 1251 Glyph glyph; 1252 1253 if (tab.get_display () is Glyph) { 1254 glyph = (Glyph) tab.get_display (); 1255 show_bg.set_selected (glyph.get_background_visible ()); 1256 update_line_selection (glyph); 1257 } 1258 }); 1259 } 1260 1261 public static void update_stroke_settings () { 1262 bool stroke = false; 1263 Glyph g = MainWindow.get_current_glyph (); 1264 1265 foreach (Object p in g.active_paths) { 1266 if (p.stroke > 0) { 1267 stroke = true; 1268 } 1269 } 1270 1271 add_stroke.selected = stroke; 1272 StrokeTool.add_stroke = stroke; 1273 set_stroke_tool_visibility (); 1274 } 1275 1276 void auto_trace_background () { 1277 Glyph g = MainWindow.get_current_glyph (); 1278 BackgroundImage? bg = g.get_background_image (); 1279 BackgroundImage b; 1280 PathList pl; 1281 1282 if (bg != null) { 1283 b = (!) bg; 1284 pl = b.autotrace (); 1285 foreach (Path p in pl.paths) { 1286 g.add_path (p); 1287 } 1288 } 1289 } 1290 1291 void update_line_selection (Glyph glyph) { 1292 help_lines.set_selected (glyph.get_show_help_lines ()); 1293 xheight_help_lines.set_selected (glyph.get_xheight_lines_visible ()); 1294 background_help_lines.set_selected (glyph.get_margin_lines_visible ()); 1295 } 1296 1297 public static void set_point_type_from_preferences () { 1298 string type = Preferences.get ("point_type"); 1299 if (type == "double_points") { 1300 Toolbox.select_tool_by_name ("double_points"); 1301 } else if (type == "quadratic_points") { 1302 Toolbox.select_tool_by_name ("quadratic_points"); 1303 } if (type == "cubic_points") { 1304 Toolbox.select_tool_by_name ("cubic_points"); 1305 } 1306 } 1307 1308 void hide_all_modifiers () { 1309 x_coordinate.set_tool_visibility (false); 1310 y_coordinate.set_tool_visibility (false); 1311 rotation.set_tool_visibility (false); 1312 width.set_tool_visibility (false); 1313 height.set_tool_visibility (false); 1314 1315 reverse_path_tool.set_tool_visibility (false); 1316 full_height_tool.set_tool_visibility (false); 1317 move_layer.set_tool_visibility (false); 1318 flip_vertical.set_tool_visibility (false); 1319 flip_horizontal.set_tool_visibility (false); 1320 1321 tie_handles.set_tool_visibility (false); 1322 reflect_handle.set_tool_visibility (false); 1323 create_line.set_tool_visibility (false); 1324 close_path_tool.set_tool_visibility (false); 1325 1326 quadratic_points.set_tool_visibility (false); 1327 cubic_points.set_tool_visibility (false); 1328 double_points.set_tool_visibility (false); 1329 convert_points.set_tool_visibility (false); 1330 1331 cut_background.set_tool_visibility (false); 1332 show_bg.set_tool_visibility (false); 1333 bg_selection.set_tool_visibility (false); 1334 background_threshold.set_tool_visibility (false); 1335 background_scale.set_tool_visibility (false); 1336 high_contrast_background.set_tool_visibility (false); 1337 auto_trace_resolution.set_tool_visibility (false); 1338 auto_trace.set_tool_visibility (false); 1339 auto_trace_simplify.set_tool_visibility (false); 1340 delete_background.set_tool_visibility (false); 1341 } 1342 1343 void show_background_tool_modifiers () { 1344 draw_tool_modifiers.set_headline (backgrounds_headline); 1345 1346 cut_background.set_tool_visibility (true); 1347 show_bg.set_tool_visibility (true); 1348 bg_selection.set_tool_visibility (true); 1349 background_threshold.set_tool_visibility (true); 1350 background_scale.set_tool_visibility (true); 1351 high_contrast_background.set_tool_visibility (true); 1352 auto_trace_resolution.set_tool_visibility (true); 1353 auto_trace.set_tool_visibility (true); 1354 auto_trace_simplify.set_tool_visibility (true); 1355 delete_background.set_tool_visibility (true); 1356 } 1357 1358 void show_point_tool_modifiers () { 1359 draw_tool_modifiers.set_headline (control_points_headline); 1360 1361 tie_handles.set_tool_visibility (true); 1362 reflect_handle.set_tool_visibility (true); 1363 create_line.set_tool_visibility (true); 1364 close_path_tool.set_tool_visibility (true); 1365 1366 quadratic_points.set_tool_visibility (true); 1367 cubic_points.set_tool_visibility (true); 1368 double_points.set_tool_visibility (true); 1369 convert_points.set_tool_visibility (true); 1370 1371 reverse_path_tool.set_tool_visibility (true); 1372 } 1373 1374 void show_object_tool_modifiers () { 1375 draw_tool_modifiers.set_headline (object_tools_headline); 1376 1377 x_coordinate.set_tool_visibility (true); 1378 y_coordinate.set_tool_visibility (true); 1379 rotation.set_tool_visibility (true); 1380 width.set_tool_visibility (true); 1381 height.set_tool_visibility (true); 1382 1383 reverse_path_tool.set_tool_visibility (true); 1384 move_layer.set_tool_visibility (true); 1385 flip_vertical.set_tool_visibility (true); 1386 flip_horizontal.set_tool_visibility (true); 1387 1388 full_height_tool.set_tool_visibility (true); 1389 } 1390 1391 public override void reset_selection (Tool current_tool) { 1392 foreach (Tool t in draw_tools.tool) { 1393 if (t != current_tool) { 1394 t.set_selected (false); 1395 } 1396 } 1397 } 1398 1399 public void update_drawing_and_background_tools (Tool current_tool) { 1400 IdleSource idle = new IdleSource (); 1401 1402 idle.set_callback (() => { 1403 Glyph g = MainWindow.get_current_glyph (); 1404 1405 reset_selection (current_tool); 1406 FontDisplay display = MainWindow.get_current_display (); 1407 1408 if (display.get_name () == "Backgrounds") { 1409 return false; 1410 } 1411 1412 hide_all_modifiers (); 1413 cut_background.set_selected (false); 1414 1415 bezier_tool.set_selected (false); 1416 pen_tool.set_selected (false); 1417 point_tool.set_selected (false); 1418 zoom_tool.set_selected (false); 1419 move_tool.set_selected (false); 1420 resize_tool.set_selected (false); 1421 track_tool.set_selected (false); 1422 move_canvas.set_selected (false); 1423 delete_background.set_selected (false); 1424 1425 show_bg.set_selected (g.get_background_visible ()); 1426 show_bg.set_active (false); 1427 bg_selection.set_selected (false); 1428 background_scale.set_active (false); 1429 1430 rectangle.set_selected (false); 1431 circle.set_selected (false); 1432 1433 reverse_path_tool.set_selected (false); 1434 move_layer.set_selected (false); 1435 flip_vertical.set_selected (false); 1436 flip_horizontal.set_selected (false); 1437 1438 current_tool.set_selected (true); 1439 1440 if (resize_tool.is_selected () || move_tool.is_selected ()) { 1441 show_object_tool_modifiers (); 1442 } else if (bezier_tool.is_selected () 1443 || pen_tool.is_selected () 1444 || point_tool.is_selected () 1445 || track_tool.is_selected ()) { 1446 show_point_tool_modifiers (); 1447 } else if (move_background.is_selected () 1448 || cut_background.is_selected () 1449 || show_bg.is_selected () 1450 || high_contrast_background.is_selected () 1451 || auto_trace.is_selected ()) { 1452 show_background_tool_modifiers (); 1453 } else { 1454 show_point_tool_modifiers (); 1455 } 1456 1457 MainWindow.get_toolbox ().update_expanders (); 1458 draw_tool_modifiers.redraw (); 1459 1460 return false; 1461 }); 1462 1463 idle.attach (null); 1464 } 1465 1466 void update_type_selection () { 1467 IdleSource idle = new IdleSource (); 1468 1469 // Do this in idle, after the animation 1470 idle.set_callback (() => { 1471 Font f = BirdFont.get_current_font (); 1472 1473 quadratic_points.set_selected (false); 1474 cubic_points.set_selected (false); 1475 double_points.set_selected (false); 1476 1477 switch (point_type) { 1478 case PointType.QUADRATIC: 1479 quadratic_points.set_selected (true); 1480 f.settings.set_setting ("point_type", "quadratic"); 1481 break; 1482 case PointType.CUBIC: 1483 cubic_points.set_selected (true); 1484 f.settings.set_setting ("point_type", "cubic"); 1485 break; 1486 case PointType.DOUBLE_CURVE: 1487 double_points.set_selected (true); 1488 f.settings.set_setting ("point_type", "double_curve"); 1489 break; 1490 } 1491 1492 convert_points.set_selected (false); 1493 1494 Toolbox.redraw_tool_box (); 1495 return false; 1496 }); 1497 1498 idle.attach (null); 1499 } 1500 1501 public static void set_default_point_type (string type) { 1502 if (type == "quadratic") { 1503 quadratic_points.set_selected (true); 1504 point_type = PointType.QUADRATIC; 1505 } else if (type == "cubic") { 1506 cubic_points.set_selected (true); 1507 point_type = PointType.CUBIC; 1508 } else if (type == "double_curve") { 1509 double_points.set_selected (true); 1510 point_type = PointType.DOUBLE_CURVE; 1511 } 1512 } 1513 1514 public override Gee.ArrayList<Expander> get_expanders () { 1515 return expanders; 1516 } 1517 1518 /** Insert new points of this type. */ 1519 public static PointType get_selected_point_type () { 1520 return point_type; 1521 } 1522 1523 public void remove_all_grid_buttons () { 1524 grid_expander.tool.clear (); 1525 1526 GridTool.sizes.clear (); 1527 1528 MainWindow.get_toolbox ().update_expanders (); 1529 MainWindow.get_toolbox ().redraw (0, 0, Toolbox.allocation_width, Toolbox.allocation_height); 1530 } 1531 1532 public void parse_grid (string spin_button_value) { 1533 SpinButton sb = add_new_grid (double.parse (spin_button_value), false); 1534 MainWindow.get_toolbox ().select_tool (sb); 1535 } 1536 1537 public static SpinButton add_new_grid (double size = 2, bool update_settings_in_font = true) { 1538 SpinButton grid_width = new SpinButton ("grid_width", t_("Set size for grid")); 1539 Toolbox tb = MainWindow.get_toolbox (); 1540 1541 grid_width.set_value_round (size); 1542 1543 grid_width.new_value_action.connect((self) => { 1544 Font font = BirdFont.get_current_font (); 1545 SpinButton w; 1546 1547 grid_width.select_action (grid_width); 1548 font.grid_width.clear (); 1549 1550 foreach (Tool t in grid_expander.tool) { 1551 return_if_fail (t is SpinButton); 1552 w = (SpinButton) t; 1553 font.grid_width.add (w.get_display_value ()); 1554 } 1555 }); 1556 1557 grid_width.select_action.connect((self) => { 1558 return_if_fail (self is SpinButton); 1559 SpinButton sb = (SpinButton) self; 1560 GridTool.set_grid_width (sb.get_value ()); 1561 GlyphCanvas.redraw (); 1562 }); 1563 1564 grid_expander.add_tool (grid_width); 1565 1566 tb.update_expanders (); 1567 1568 tb.redraw (0, 0, Toolbox.allocation_width, Toolbox.allocation_height); 1569 1570 tb.select_tool (grid_width); 1571 grid_width.set_active (false); 1572 1573 if (update_settings_in_font) { 1574 GridTool.sizes.add (grid_width); 1575 1576 foreach (Tool t in grid_expander.tool) { 1577 SpinButton sb = (SpinButton) t; 1578 BirdFont.get_current_font ().grid_width.add (sb.get_display_value ()); 1579 } 1580 } 1581 1582 return grid_width; 1583 } 1584 1585 public void remove_current_grid () { 1586 Tool grid_width; 1587 Toolbox tb = MainWindow.get_toolbox (); 1588 1589 foreach (Tool t in grid_expander.tool) { 1590 if (t.is_selected () && t is SpinButton) { 1591 GridTool.sizes.remove ((SpinButton)t); 1592 grid_expander.tool.remove (t); 1593 break; 1594 } 1595 } 1596 1597 if (grid_expander.tool.size > 0) { 1598 grid_width = grid_expander.tool.get (grid_expander.tool.size - 1); 1599 tb.select_tool (grid_width); 1600 grid_width.set_active (false); 1601 } 1602 1603 MainWindow.get_toolbox ().update_expanders (); 1604 tb.redraw (0, 0, Toolbox.allocation_width, Toolbox.allocation_height); 1605 } 1606 1607 private void add_expander (Expander e) { 1608 expanders.add (e); 1609 } 1610 1611 public override Gee.ArrayList<string> get_displays () { 1612 Gee.ArrayList<string> d = new Gee.ArrayList<string> (); 1613 d.add ("Glyph"); 1614 return d; 1615 } 1616 1617 public static void update_layers () 1618 requires (!is_null (layer_tools)) { 1619 Glyph g = MainWindow.get_current_glyph (); 1620 int i = 0; 1621 1622 layer_tools.tool.clear (); 1623 foreach (Layer layer in g.layers.subgroups) { 1624 LayerLabel label = new LayerLabel (layer); 1625 layer_tools.add_tool (label, 0); 1626 1627 if (i == g.current_layer) { 1628 label.select_layer (); 1629 } 1630 1631 i++; 1632 } 1633 1634 MainWindow.get_toolbox ().update_expanders (); 1635 layer_tools.clear_cache (); 1636 layer_tools.redraw (); 1637 Toolbox.redraw_tool_box (); 1638 } 1639 1640 public static void deselect_layers () 1641 requires (!is_null (layer_tools)) { 1642 LayerLabel l; 1643 1644 foreach (Tool t in layer_tools.tool) { 1645 if (t is LayerLabel) { 1646 l = (LayerLabel) t; 1647 l.selected_layer = false; 1648 } 1649 } 1650 } 1651 1652 public static void set_stroke_tool_visibility () { 1653 object_stroke.visible = StrokeTool.add_stroke; 1654 line_cap_butt.visible = StrokeTool.add_stroke; 1655 line_cap_round.visible = StrokeTool.add_stroke; 1656 line_cap_square.visible = StrokeTool.add_stroke; 1657 MainWindow.get_toolbox ().update_expanders (); 1658 stroke_expander.redraw (); 1659 } 1660 } 1661 1662 } 1663