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