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.
Revert "Stroke settings"
1 /* 2 Copyright (C) 2012, 2013, 2014 Johan Mattsson 3 4 This library is free software; you can redistribute it and/or modify 5 it under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 3 of the 7 License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Lesser General Public License for more details. 13 */ 14 15 using Cairo; 16 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 Expander draw_tools; 26 Expander grid_expander; 27 Expander shape_tools; 28 public static Expander draw_tool_modifiers; 29 public static Expander stroke_expander; 30 public static Expander zoombar_tool; 31 public static Expander view_tools; 32 public static Expander guideline_tools; 33 34 public static PointType point_type = PointType.DOUBLE_CURVE; 35 36 public static SpinButton object_stroke; 37 38 public static MoveTool move_tool; 39 public static PenTool pen_tool; 40 41 public static ForesightTool foresight_tool; 42 PointTool point_tool; 43 public static ZoomTool zoom_tool; 44 public static ResizeTool resize_tool; 45 StrokeTool stroke_tool; 46 public static TrackTool track_tool; 47 public static BackgroundTool move_background; 48 public static Tool move_canvas; 49 50 Tool quadratic_points; 51 Tool cubic_points; 52 Tool double_points; 53 Tool convert_points; 54 55 public static CutBackgroundTool cut_background; 56 Tool show_bg; 57 Tool bg_selection; 58 SpinButton background_threshold; 59 public static SpinButton background_scale; 60 Tool high_contrast_background; 61 SpinButton auto_trace_resolution; 62 Tool auto_trace; 63 SpinButton auto_trace_simplify; 64 Tool delete_background; 65 66 Tool rectangle; 67 Tool circle; 68 69 Tool help_lines; 70 Tool xheight_help_lines; 71 Tool background_help_lines; 72 73 SpinButton x_coordinate; 74 SpinButton y_coordinate; 75 SpinButton rotation; 76 SpinButton width; 77 SpinButton height; 78 SpinButton skew; 79 80 Tool tie_handles; 81 Tool reflect_handle; 82 Tool create_line; 83 84 Tool delete_button; 85 public Tool insert_point_on_path_tool; 86 Tool undo_tool; 87 Tool select_all_button; 88 89 OrientationTool reverse_path_tool; 90 Tool move_layer; 91 Tool flip_vertical; 92 Tool flip_horizontal; 93 94 public ZoomBar zoom_bar; 95 96 public DrawingTools (GlyphCanvas main_glyph_canvas) { 97 bool selected_line; 98 99 glyph_canvas = main_glyph_canvas; 100 101 background_scale = new SpinButton (); 102 103 draw_tools = new Expander (t_("Drawing Tools")); 104 draw_tool_modifiers = new Expander (t_("Control Point")); 105 stroke_expander = new Expander (t_("Stroke")); 106 shape_tools = new Expander (t_("Geometrical Shapes")); 107 zoombar_tool = new Expander (t_("Zoom")); 108 view_tools = new Expander (); 109 guideline_tools = new Expander (t_("Guidelines & Grid")); 110 111 Expander font_name = new Expander (); 112 Expander key_tools = new Expander (); // tools on android 113 Expander test_tools = new Expander (); 114 Expander grid = new Expander (t_("Grid Size")); 115 116 grid_expander = grid; 117 118 // font name 119 font_name.add_tool (new FontName ()); 120 121 // Draw tools 122 foresight_tool = new ForesightTool ("foresight"); 123 foresight_tool.select_action.connect ((self) => { 124 update_drawing_and_background_tools (self); 125 }); 126 draw_tools.add_tool (foresight_tool); 127 128 Tool bezier_line = new Tool ("bezier_line", t_("Convert the last segment to a straight line")); 129 bezier_line.select_action.connect ((self) => { 130 foresight_tool.switch_to_line_mode (); 131 }); 132 bezier_line.is_tool_modifier = true; 133 draw_tools.add_tool (bezier_line); 134 bezier_line.set_tool_visibility (false); 135 136 pen_tool = new PenTool ("pen_tool"); 137 pen_tool.select_action.connect ((self) => { 138 update_drawing_and_background_tools (self); 139 }); 140 draw_tools.add_tool (pen_tool); 141 142 point_tool = new PointTool ("point_tool"); 143 point_tool.select_action.connect ((self) => { 144 update_drawing_and_background_tools (self); 145 }); 146 draw_tools.add_tool (point_tool); 147 148 zoom_tool = new ZoomTool ("zoom_tool"); 149 zoom_tool.select_action.connect ((self) => { 150 update_drawing_and_background_tools (self); 151 }); 152 draw_tools.add_tool (zoom_tool); 153 154 move_tool = new MoveTool ("move"); 155 move_tool.select_action.connect ((self) => { 156 update_drawing_and_background_tools (self); 157 }); 158 draw_tools.add_tool (move_tool); 159 160 resize_tool = new ResizeTool ("resize"); 161 resize_tool.select_action.connect ((self) => { 162 update_drawing_and_background_tools (self); 163 }); 164 draw_tools.add_tool (resize_tool); 165 166 track_tool = new TrackTool ("track"); // draw outline on freehand 167 track_tool.select_action.connect ((self) => { 168 update_drawing_and_background_tools (self); 169 }); 170 draw_tools.add_tool (track_tool); 171 172 move_background = new BackgroundTool ("move_background"); 173 move_background.select_action.connect ((self) => { 174 update_drawing_and_background_tools (self); 175 }); 176 draw_tools.add_tool (move_background); 177 178 move_canvas = new Tool ("move_canvas", t_("Move canvas")); 179 move_canvas.select_action.connect ((self) => { 180 update_drawing_and_background_tools (self); 181 }); 182 draw_tools.add_tool (move_canvas); 183 184 // Tools on android 185 // Delete key 186 delete_button = new Tool ("delete_button", t_("Delete")); 187 delete_button.select_action.connect ((self) => { 188 TabContent.key_press (Key.DEL); 189 }); 190 key_tools.add_tool (delete_button); 191 192 // Select all points or paths 193 select_all_button = new Tool ("select_all", t_("Select all points or paths")); 194 select_all_button.select_action.connect ((self) => { 195 Glyph g = MainWindow.get_current_glyph (); 196 197 if (point_tool.is_selected () 198 || pen_tool.is_selected () 199 || track_tool.is_selected ()) { 200 pen_tool.select_all_points (); 201 g.open_path (); 202 } else { 203 DrawingTools.move_tool.select_all_paths (); 204 } 205 }); 206 key_tools.add_tool (select_all_button); 207 208 // Undo 209 undo_tool = new Tool ("undo_tool", t_("Undo")); 210 undo_tool.select_action.connect ((self) => { 211 TabContent.undo (); 212 }); 213 key_tools.add_tool (undo_tool); 214 215 bool insert_points = false; 216 insert_point_on_path_tool = new Tool ("new_point_on_path", t_("Insert new points on path")); 217 insert_point_on_path_tool.select_action.connect ((self) => { 218 insert_points = !insert_points; 219 insert_point_on_path_tool.set_selected (insert_points); 220 }); 221 insert_point_on_path_tool.set_persistent (true); 222 key_tools.add_tool (insert_point_on_path_tool); 223 224 // stroke 225 Tool stroke_settings = new Tool ("stroke"); 226 stroke_settings.select_action.connect((self) => { 227 StrokeTool.show_stroke_tools = !StrokeTool.show_stroke_tools; 228 stroke_settings.set_selected (StrokeTool.show_stroke_tools); 229 stroke_expander.visible = StrokeTool.show_stroke_tools; 230 MainWindow.get_toolbox ().update_expanders (); 231 Toolbox.redraw_tool_box (); 232 }); 233 234 if (BirdFont.has_argument ("--test")) { 235 draw_tool_modifiers.add_tool (stroke_settings); 236 } 237 238 // quadratic Bézier points 239 quadratic_points = new Tool ("quadratic_points", t_("Create quadratic Bézier curves")); 240 quadratic_points.select_action.connect ((self) => { 241 point_type = PointType.QUADRATIC; 242 Preferences.set ("point_type", "quadratic_points"); 243 update_type_selection (); 244 }); 245 draw_tool_modifiers.add_tool (quadratic_points); 246 247 // cubic Bézier points 248 cubic_points = new Tool ("cubic_points", t_("Create cubic Bézier curves")); 249 cubic_points.select_action.connect ((self) => { 250 point_type = PointType.CUBIC; 251 Preferences.set ("point_type", "cubic_points"); 252 update_type_selection (); 253 }); 254 draw_tool_modifiers.add_tool (cubic_points); 255 256 // two quadratic points off curve points for each quadratic control point 257 double_points = new Tool ("double_points", t_("Quadratic path with two line handles")); 258 double_points.select_action.connect ((self) => { 259 point_type = PointType.DOUBLE_CURVE; 260 Preferences.set ("point_type", "double_points"); 261 update_type_selection (); 262 }); 263 draw_tool_modifiers.add_tool (double_points); 264 265 // convert point 266 convert_points = new Tool ("convert_point", t_("Convert selected points")); 267 convert_points.select_action.connect ((self) => { 268 PenTool.convert_point_types (); 269 GlyphCanvas.redraw (); 270 update_type_selection (); 271 }); 272 convert_points.set_persistent (false); 273 draw_tool_modifiers.add_tool (convert_points); 274 275 // x coordinate 276 x_coordinate = new SpinButton ("x_coordinate", t_("X coordinate")); 277 x_coordinate.set_big_number (true); 278 x_coordinate.set_int_value ("0.000"); 279 x_coordinate.set_int_step (0.1); 280 x_coordinate.set_min (-999.99); 281 x_coordinate.set_max (999.99); 282 x_coordinate.show_icon (true); 283 x_coordinate.set_persistent (false); 284 x_coordinate.new_value_action.connect((self) => { 285 Glyph glyph = MainWindow.get_current_glyph (); 286 double x, y, w, h; 287 double delta; 288 289 glyph.selection_boundaries (out x, out y, out w, out h); 290 delta = x_coordinate.get_value () - x + glyph.left_limit; 291 292 foreach (Path path in glyph.active_paths) { 293 path.move (delta, 0); 294 } 295 296 GlyphCanvas.redraw (); 297 }); 298 draw_tool_modifiers.add_tool (x_coordinate); 299 300 move_tool.objects_moved.connect (() => { 301 Glyph glyph = MainWindow.get_current_glyph (); 302 x_coordinate.set_value_round (MoveTool.selection_box_center_x 303 - (MoveTool.selection_box_width / 2) 304 - glyph.left_limit, true, false); 305 }); 306 307 move_tool.selection_changed.connect (() => { 308 Glyph glyph = MainWindow.get_current_glyph (); 309 x_coordinate.set_value_round (MoveTool.selection_box_center_x 310 - (MoveTool.selection_box_width / 2) 311 - glyph.left_limit, true, false); 312 }); 313 314 move_tool.objects_deselected.connect (() => { 315 x_coordinate.set_value_round (0, true, false); 316 x_coordinate.hide_value (); 317 }); 318 319 // y coordinate 320 y_coordinate = new SpinButton ("y_coordinate", t_("Y coordinate")); 321 y_coordinate.set_big_number (true); 322 y_coordinate.set_int_value ("0.000"); 323 y_coordinate.set_int_step (0.1); 324 y_coordinate.set_min (-999.99); 325 y_coordinate.set_max (999.99); 326 y_coordinate.show_icon (true); 327 y_coordinate.set_persistent (false); 328 y_coordinate.new_value_action.connect((self) => { 329 double x, y, w, h; 330 Glyph glyph = MainWindow.get_current_glyph (); 331 Font font = BirdFont.get_current_font (); 332 333 glyph.selection_boundaries (out x, out y, out w, out h); 334 335 foreach (Path path in glyph.active_paths) { 336 path.move (0, y_coordinate.get_value () - (y - h) - font.base_line); 337 } 338 339 GlyphCanvas.redraw (); 340 }); 341 draw_tool_modifiers.add_tool (y_coordinate); 342 343 move_tool.objects_moved.connect (() => { 344 Font font = BirdFont.get_current_font (); 345 y_coordinate.set_value_round (MoveTool.selection_box_center_y 346 - (MoveTool.selection_box_height / 2) 347 + font.base_line, true, false); 348 }); 349 350 move_tool.selection_changed.connect (() => { 351 Font font = BirdFont.get_current_font (); 352 y_coordinate.set_value_round (MoveTool.selection_box_center_y 353 - (MoveTool.selection_box_height / 2) 354 + font.base_line, true, false); 355 }); 356 357 move_tool.objects_deselected.connect (() => { 358 y_coordinate.set_value_round (0, true, false); 359 y_coordinate.hide_value (); 360 }); 361 362 // rotation 363 rotation = new SpinButton ("rotation", t_("Rotation")); 364 rotation.set_big_number (true); 365 rotation.set_int_value ("0.000"); 366 rotation.set_int_step (0.1); 367 rotation.set_min (-360); 368 rotation.set_max (360); 369 rotation.show_icon (true); 370 rotation.set_persistent (false); 371 rotation.new_value_action.connect ((self) => { 372 double x, y, w, h; 373 Glyph glyph = MainWindow.get_current_glyph (); 374 double angle = (self.get_value () / 360) * 2 * PI; 375 Path last_path; 376 glyph.selection_boundaries (out x, out y, out w, out h); 377 378 x += w / 2; 379 y -= h / 2; 380 381 if (glyph.active_paths.size > 0) { 382 last_path = glyph.active_paths.get (glyph.active_paths.size - 1); 383 resize_tool.rotate_selected_paths (angle - last_path.rotation, x, y); 384 } 385 386 GlyphCanvas.redraw (); 387 }); 388 389 resize_tool.objects_rotated.connect ((angle) => { 390 rotation.set_value_round (angle, true, false); 391 }); 392 393 move_tool.objects_deselected.connect (() => { 394 rotation.set_value_round (0, true, false); 395 rotation.hide_value (); 396 }); 397 398 draw_tool_modifiers.add_tool (rotation); 399 400 // skew 401 skew = new SpinButton ("skew", t_("Skew")); 402 skew.set_big_number (true); 403 skew.set_int_value ("0.000"); 404 skew.set_int_step (1); 405 skew.set_min (-100); 406 skew.set_max (100); 407 skew.show_icon (true); 408 skew.set_persistent (false); 409 skew.new_value_action.connect ((self) => { 410 resize_tool.skew (-skew.get_value ()); 411 GlyphCanvas.redraw (); 412 }); 413 414 move_tool.objects_moved.connect (() => { 415 Glyph glyph = MainWindow.get_current_glyph (); 416 double d; 417 418 if (glyph.active_paths.size > 0) { 419 d = glyph.active_paths.get (0).skew; 420 resize_tool.last_skew = d; 421 skew.set_value_round (-d, true, false); 422 } 423 }); 424 425 move_tool.objects_deselected.connect (() => { 426 skew.set_value_round (0, true, false); 427 skew.hide_value (); 428 }); 429 430 draw_tool_modifiers.add_tool (skew); 431 432 // width 433 width = new SpinButton ("width", t_("Width")); 434 width.set_big_number (true); 435 width.set_int_value ("0.0000"); 436 width.set_int_step (0.01); 437 width.show_icon (true); 438 width.set_persistent (false); 439 width.new_value_action.connect ((self) => { 440 double x, y, w, h; 441 Glyph glyph; 442 double new_size; 443 444 glyph = MainWindow.get_current_glyph (); 445 glyph.selection_boundaries (out x, out y, out w, out h); 446 447 new_size = self.get_value () / w; 448 449 if (self.get_value () > 0 && new_size != 1) { 450 resize_tool.resize_selected_paths (new_size); 451 } 452 453 GlyphCanvas.redraw (); 454 }); 455 draw_tool_modifiers.add_tool (width); 456 457 // height 458 height = new SpinButton ("height", t_("Height")); 459 height.set_big_number (true); 460 height.set_int_value ("0.0000"); 461 height.set_int_step (0.01); 462 height.show_icon (true); 463 height.set_persistent (false); 464 height.new_value_action.connect ((self) => { 465 double x, y, w, h; 466 Glyph glyph; 467 double new_size; 468 469 glyph = MainWindow.get_current_glyph (); 470 glyph.selection_boundaries (out x, out y, out w, out h); 471 472 new_size = self.get_value () / h; 473 474 if (self.get_value () > 0 && new_size != 1) { 475 resize_tool.resize_selected_paths (new_size); 476 } 477 478 GlyphCanvas.redraw (); 479 }); 480 draw_tool_modifiers.add_tool (height); 481 482 resize_tool.objects_resized.connect ((w, h) => { 483 height.set_value_round (h, true, false); 484 width.set_value_round (w, true, false); 485 }); 486 487 move_tool.objects_deselected.connect (() => { 488 width.set_value_round (0, true, false); 489 width.hide_value (); 490 491 height.set_value_round (0, true, false); 492 height.hide_value (); 493 }); 494 495 move_tool.objects_moved.connect (() => { 496 width.set_value_round (MoveTool.selection_box_width, true, false); 497 height.set_value_round (MoveTool.selection_box_height, true, false); 498 }); 499 500 // tie edit point handles 501 tie_handles = new Tool ("tie_point", t_("Tie curve handles for the selected edit point")); 502 tie_handles.select_action.connect ((self) => { 503 bool tie; 504 EditPoint p; 505 506 if (PenTool.move_selected_handle) { 507 p = PenTool.active_handle.parent; 508 tie = !p.tie_handles; 509 510 if (tie) { 511 p.process_tied_handle (); 512 p.set_reflective_handles (false); 513 } 514 515 p.set_tie_handle (tie); 516 517 PenTool.handle_selection.path.update_region_boundaries (); 518 } else { 519 foreach (PointSelection ep in PenTool.selected_points) { 520 tie = !ep.point.tie_handles; 521 522 if (tie) { 523 ep.point.process_tied_handle (); 524 ep.point.set_reflective_handles (false); 525 } 526 527 ep.point.set_tie_handle (tie); 528 ep.path.update_region_boundaries (); 529 } 530 } 531 532 MainWindow.get_current_glyph ().update_view (); 533 }); 534 draw_tool_modifiers.add_tool (tie_handles); 535 536 // symmetrical handles 537 reflect_handle = new Tool ("symmetric", t_("Symmetrical handles")); 538 reflect_handle.select_action.connect ((self) => { 539 bool symmetrical; 540 PointSelection ep; 541 if (PenTool.selected_points.size > 0) { 542 ep = PenTool.selected_points.get (0); 543 symmetrical = ep.point.reflective_point; 544 foreach (PointSelection p in PenTool.selected_points) { 545 p.point.set_reflective_handles (!symmetrical); 546 p.point.process_symmetrical_handles (); 547 548 if (symmetrical) { 549 ep.point.set_tie_handle (false); 550 } 551 552 p.path.update_region_boundaries (); 553 } 554 MainWindow.get_current_glyph ().update_view (); 555 } 556 }); 557 draw_tool_modifiers.add_tool (reflect_handle); 558 559 create_line = new Tool ("create_line", t_("Convert segment to line.")); 560 create_line.select_action.connect ((self) => { 561 PenTool.convert_segment_to_line (); 562 MainWindow.get_current_glyph ().update_view (); 563 }); 564 draw_tool_modifiers.add_tool (create_line); 565 566 reverse_path_tool = new OrientationTool ("reverse_path", t_("Create counter from outline")); 567 draw_tool_modifiers.add_tool (reverse_path_tool); 568 569 move_layer = new Tool ("move_layer", t_("Move to path to the bottom layer")); 570 move_layer.select_action.connect ((self) => { 571 Glyph g = MainWindow.get_current_glyph (); 572 573 foreach (Path p in g.active_paths) { 574 g.path_list.remove (p); 575 g.path_list.insert (0, p); 576 } 577 }); 578 draw_tool_modifiers.add_tool (move_layer); 579 580 flip_vertical = new Tool ("flip_vertical", t_("Flip path vertically")); 581 flip_vertical.select_action.connect ((self) => { 582 MoveTool.flip_vertical (); 583 MainWindow.get_current_glyph ().update_view (); 584 }); 585 draw_tool_modifiers.add_tool (flip_vertical); 586 587 flip_horizontal = new Tool ("flip_horizontal", t_("Flip path horizontally")); 588 flip_horizontal.select_action.connect ((self) => { 589 MoveTool.flip_horizontal (); 590 MainWindow.get_current_glyph ().update_view (); 591 }); 592 draw_tool_modifiers.add_tool (flip_horizontal); 593 594 // background tools 595 background_scale = new SpinButton ("scale_background", t_("Set size for background image")); 596 background_scale.show_icon (true); 597 background_scale.set_int_value ("1.000"); 598 599 background_scale.new_value_action.connect((self) => { 600 background_scale.select_action (self); 601 }); 602 603 background_scale.select_action.connect((self) => { 604 SpinButton sb = (SpinButton) self; 605 Glyph g = MainWindow.get_current_glyph (); 606 BackgroundImage? img = g.get_background_image (); 607 double s = sb.get_value (); 608 BackgroundImage i; 609 double xc, yc; 610 611 if (img != null) { 612 i = (!) img; 613 xc = i.img_middle_x; 614 yc = i.img_middle_y; 615 616 i.set_img_scale (s, s); 617 618 i.img_middle_x = xc; 619 i.img_middle_y = yc; 620 } 621 622 GlyphCanvas.redraw (); 623 }); 624 625 draw_tool_modifiers.add_tool (background_scale); 626 627 cut_background = new CutBackgroundTool ("cut_background"); 628 cut_background.select_action.connect ((self) => { 629 update_drawing_and_background_tools (self); 630 }); 631 draw_tool_modifiers.add_tool (cut_background); 632 633 show_bg = new Tool ("show_background", t_("Show/hide background image")); 634 show_bg.select_action.connect ((self) => { 635 update_drawing_and_background_tools (self); 636 }); 637 show_bg.select_action.connect ((self) => { 638 Glyph g = MainWindow.get_current_glyph (); 639 g.set_background_visible (!g.get_background_visible ()); 640 GlyphCanvas.redraw (); 641 }); 642 draw_tool_modifiers.add_tool (show_bg); 643 644 bg_selection = new Tool ("insert_background", t_("Insert a new background image")); 645 bg_selection.select_action.connect ((self) => { 646 update_drawing_and_background_tools (self); 647 }); 648 649 bg_selection.select_action.connect((self) => { 650 if (MainWindow.get_current_display () is Glyph) { 651 BackgroundTool.import_background_image (); 652 } 653 }); 654 655 bg_selection.set_show_background (true); 656 draw_tool_modifiers.add_tool (bg_selection); 657 658 high_contrast_background = new Tool ("high_contrast_background", t_("High contrast")); 659 high_contrast_background.select_action.connect ((self) => { 660 Glyph g = MainWindow.get_current_glyph (); 661 BackgroundImage? bg = g.get_background_image (); 662 BackgroundImage b; 663 664 if (bg != null) { 665 b = (!) bg; 666 b.set_high_contrast (!b.high_contrast); 667 b.update_background (); 668 } 669 }); 670 draw_tool_modifiers.add_tool (high_contrast_background); 671 672 background_threshold = new SpinButton ("contrast_threshold", t_("Set background threshold")); 673 background_threshold.show_icon (true); 674 background_threshold.set_value_round (1); 675 676 background_threshold.new_value_action.connect ((self) => { 677 Glyph g = MainWindow.get_current_glyph (); 678 BackgroundImage? bg = g.get_background_image (); 679 BackgroundImage b; 680 681 if (bg != null) { 682 b = (!) bg; 683 b.set_threshold (background_threshold.get_value ()); 684 b.update_background (); 685 } 686 }); 687 688 draw_tool_modifiers.add_tool (background_threshold); 689 690 auto_trace_resolution = new SpinButton ("auto_trace_resolution", t_("Amount of autotrace details")); 691 auto_trace_resolution.set_value_round (1); 692 auto_trace_resolution.show_icon (true); 693 694 auto_trace_resolution.new_value_action.connect ((self) => { 695 Glyph g = MainWindow.get_current_glyph (); 696 BackgroundImage? bg = g.get_background_image (); 697 BackgroundImage b; 698 699 if (bg != null) { 700 b = (!) bg; 701 b.set_trace_resolution (auto_trace_resolution.get_value ()); 702 b.update_background (); 703 } 704 }); 705 706 draw_tool_modifiers.add_tool (auto_trace_resolution); 707 708 auto_trace_simplify = new SpinButton ("auto_trace_simplify", t_("Autotrace simplification")); 709 auto_trace_simplify.set_value_round (0.5); 710 auto_trace_simplify.show_icon (true); 711 712 auto_trace_simplify.new_value_action.connect ((self) => { 713 Glyph g = MainWindow.get_current_glyph (); 714 BackgroundImage? bg = g.get_background_image (); 715 BackgroundImage b; 716 717 if (bg != null) { 718 b = (!) bg; 719 b.set_trace_simplification (auto_trace_simplify.get_value ()); 720 } 721 }); 722 723 draw_tool_modifiers.add_tool (auto_trace_simplify); 724 725 auto_trace = new Tool ("autotrace", t_("Autotrace background image")); 726 auto_trace.select_action.connect ((self) => { 727 Task t = new Task (); 728 t.task.connect (auto_trace_background); 729 MainWindow.native_window.run_background_thread (t); 730 }); 731 732 draw_tool_modifiers.add_tool (auto_trace); 733 734 delete_background = new Tool ("delete_background", t_("Delete background image")); 735 delete_background.select_action.connect ((self) => { 736 MainWindow.get_current_glyph ().delete_background (); 737 }); 738 739 draw_tool_modifiers.add_tool (delete_background); 740 741 // add stroke to path 742 Tool add_stroke = new Tool ("apply_stroke", t_("Apply stroke")); 743 add_stroke.select_action.connect ((self) => { 744 Glyph g = MainWindow.get_current_glyph (); 745 StrokeTool.add_stroke = !StrokeTool.add_stroke; 746 add_stroke.selected = StrokeTool.add_stroke; 747 748 if (StrokeTool.add_stroke) { 749 foreach (Path p in g.active_paths) { 750 p.stroke = StrokeTool.stroke_width; 751 } 752 } else { 753 foreach (Path p in g.active_paths) { 754 p.stroke = 0; 755 } 756 } 757 758 GlyphCanvas.redraw (); 759 }); 760 stroke_expander.add_tool (add_stroke); 761 762 // edit stroke width 763 object_stroke = new SpinButton ("object_stroke", t_("Stroke width")); 764 object_stroke.set_value_round (StrokeTool.stroke_width); 765 object_stroke.set_int_step (0.015); 766 767 object_stroke.new_value_action.connect((self) => { 768 bool tool = resize_tool.is_selected () 769 || move_tool.is_selected () 770 || pen_tool.is_selected () 771 || track_tool.is_selected () 772 || point_tool.is_selected () 773 || foresight_tool.is_selected (); 774 775 if (tool && object_stroke.is_selected () && StrokeTool.add_stroke) { 776 StrokeTool.set_stroke_for_selected_paths (object_stroke.get_value ()); 777 } 778 779 StrokeTool.stroke_width = object_stroke.get_value (); 780 }); 781 stroke_expander.add_tool (object_stroke); 782 783 // create outline from path 784 Tool outline = new Tool ("stroke_to_outline", t_("Create outline form stroke")); 785 outline.select_action.connect ((self) => { 786 stroke_tool.select_action (stroke_tool); 787 }); 788 stroke_expander.add_tool (outline); 789 790 if (BirdFont.has_argument ("--test")) { 791 Tool test_case = new Tool ("test_case"); 792 test_case.select_action.connect((self) => { 793 if (self.is_selected ()) { 794 if (TestBirdFont.is_running ()) { 795 TestBirdFont.pause (); 796 } else { 797 TestBirdFont.continue (); 798 } 799 } 800 }); 801 test_tools.add_tool (test_case); 802 803 Tool slow_test = new Tool ("slow_test"); 804 slow_test.select_action.connect((self) => { 805 bool s = TestBirdFont.is_slow_test (); 806 TestBirdFont.set_slow_test (!s); 807 s = TestBirdFont.is_slow_test (); 808 self.set_selected (s); 809 }); 810 811 test_tools.add_tool (slow_test); 812 813 // Run from commad line 814 string? st = BirdFont.get_argument ("--test"); 815 if (st != null && ((!)st).char_count () > 0) { 816 IdleSource idle = new IdleSource (); 817 818 idle.set_callback (() => { 819 MainWindow.get_toolbox ().select_tool (test_case); 820 return false; 821 }); 822 823 idle.attach (null); 824 } 825 826 if (BirdFont.has_argument ("--slow")) { 827 MainWindow.get_toolbox ().select_tool (slow_test); 828 } 829 830 } 831 832 // guide lines, grid and other guidlines 833 help_lines = new Tool ("help_lines", t_("Show guidelines")); 834 help_lines.select_action.connect ((self) => { 835 bool h; 836 h = GlyphCanvas.get_current_glyph ().get_show_help_lines (); 837 GlyphCanvas.get_current_glyph ().set_show_help_lines (!h); 838 self.set_selected (!h); 839 GlyphCanvas.get_current_glyph ().redraw_help_lines (); 840 }); 841 selected_line = GlyphCanvas.get_current_glyph ().get_show_help_lines (); 842 help_lines.set_selected (selected_line); 843 guideline_tools.add_tool (help_lines); 844 845 xheight_help_lines = new Tool ("show_xheight_helplines", t_("Show more guidelines")); 846 xheight_help_lines.select_action.connect ((self) => { 847 Glyph g = MainWindow.get_current_glyph (); 848 bool v = !g.get_xheight_lines_visible (); 849 g.set_xheight_lines_visible (v); 850 self.set_selected (v); 851 GlyphCanvas.redraw (); 852 853 if (v && !help_lines.is_selected ()) { 854 MainWindow.get_toolbox ().select_tool (help_lines); 855 } 856 }); 857 selected_line = GlyphCanvas.get_current_glyph ().get_xheight_lines_visible (); 858 xheight_help_lines.set_selected (selected_line); 859 guideline_tools.add_tool (xheight_help_lines); 860 861 background_help_lines = new Tool ("background_help_lines", t_("Show guidelines at top and bottom margin")); 862 background_help_lines.select_action.connect ((self) => { 863 Glyph g = MainWindow.get_current_glyph (); 864 bool v = !g.get_margin_lines_visible (); 865 g.set_margin_lines_visible (v); 866 self.set_selected (v); 867 GlyphCanvas.redraw (); 868 869 if (v && !help_lines.is_selected ()) { 870 MainWindow.get_toolbox ().select_tool (help_lines); 871 } 872 }); 873 selected_line = GlyphCanvas.get_current_glyph ().get_margin_lines_visible (); 874 background_help_lines.set_selected (selected_line); 875 guideline_tools.add_tool (background_help_lines); 876 877 Tool new_grid = new GridTool ("show_grid"); 878 guideline_tools.add_tool (new_grid); 879 880 // Zoom tools 881 zoom_bar = new ZoomBar (); 882 zoom_bar.new_zoom.connect ((z) => { 883 Glyph g = MainWindow.get_current_glyph (); 884 double zoom = 20 * z + 1; 885 double xc, yc, nxc, nyc; 886 887 xc = Glyph.path_coordinate_x (Glyph.xc ()); 888 yc = Glyph.path_coordinate_y (Glyph.yc ()); 889 890 g.set_zoom (zoom); 891 892 nxc = Glyph.path_coordinate_x (Glyph.xc ()); 893 nyc = Glyph.path_coordinate_y (Glyph.yc ()); 894 895 g.view_offset_x -= nxc - xc; 896 g.view_offset_y += nyc - yc; 897 898 GlyphCanvas.redraw (); 899 }); 900 zoombar_tool.add_tool (zoom_bar); 901 902 Tool reset_zoom = new Tool ("zoom_1_1", t_("Zoom Out More")); 903 reset_zoom.select_action.connect ((self) => { 904 zoom_tool.store_current_view (); 905 glyph_canvas.get_current_display ().reset_zoom (); 906 glyph_canvas.redraw_area(0, 0, GlyphCanvas.allocation.width, GlyphCanvas.allocation.height); 907 }); 908 view_tools.add_tool (reset_zoom); 909 reset_zoom.set_tool_visibility (false); 910 911 Tool full_glyph = new Tool ("full_glyph", t_("Show full glyph")); 912 full_glyph.select_action.connect((self) => { 913 zoom_tool.store_current_view (); 914 zoom_tool.zoom_full_glyph (); 915 }); 916 view_tools.add_tool (full_glyph); 917 918 Tool zoom_boundaries = new Tool ("zoom_boundaries", t_("Fit in view")); 919 zoom_boundaries.select_action.connect((self) => { 920 zoom_tool.store_current_view (); 921 glyph_canvas.get_current_display ().zoom_max (); 922 }); 923 view_tools.add_tool (zoom_boundaries); 924 925 Tool zoom_bg = new Tool ("zoom_background_image", t_("Zoom in on background image")); 926 zoom_bg.select_action.connect((self) => { 927 if (MainWindow.get_current_glyph ().get_background_image () != null) { 928 zoom_tool.store_current_view (); 929 ZoomTool.zoom_full_background_image (); 930 glyph_canvas.redraw_area(0, 0, GlyphCanvas.allocation.width, GlyphCanvas.allocation.height); 931 } 932 }); 933 view_tools.add_tool (zoom_bg); 934 935 Tool zoom_prev = new Tool ("prev", t_("Previous view")); 936 zoom_prev.select_action.connect((self) => { 937 zoom_tool.previous_view (); 938 }); 939 view_tools.add_tool (zoom_prev); 940 941 Tool zoom_next = new Tool ("next", t_("Next view")); 942 zoom_next.select_action.connect((self) => { 943 zoom_tool.next_view (); 944 }); 945 view_tools.add_tool (zoom_next); 946 zoom_next.set_tool_visibility (false); 947 948 // shape tools 949 circle = new CircleTool ("circle"); 950 circle.select_action.connect ((self) => { 951 update_drawing_and_background_tools (self); 952 }); 953 shape_tools.add_tool (circle); 954 955 rectangle = new RectangleTool ("rectangle"); 956 rectangle.select_action.connect ((self) => { 957 update_drawing_and_background_tools (self); 958 }); 959 shape_tools.add_tool (rectangle); 960 961 stroke_expander.visible = false; 962 963 add_expander (font_name); 964 add_expander (draw_tools); 965 966 if (BirdFont.android) { 967 add_expander (key_tools); 968 } 969 970 add_expander (draw_tool_modifiers); 971 add_expander (stroke_expander); 972 add_expander (guideline_tools); 973 add_expander (grid); 974 add_expander (zoombar_tool); 975 add_expander (view_tools); 976 add_expander (shape_tools); 977 978 // Fixa: add_expander (trace); 979 if (BirdFont.has_argument ("--test")) { 980 add_expander (test_tools); 981 } 982 983 draw_tools.set_persistent (true); 984 draw_tools.set_unique (false); 985 986 stroke_expander.set_persistent (true); 987 stroke_expander.set_unique (false); 988 989 key_tools.set_persistent (false); 990 key_tools.set_unique (false); 991 992 draw_tool_modifiers.set_persistent (true); 993 draw_tool_modifiers.set_unique (false); 994 995 test_tools.set_persistent (true); 996 997 guideline_tools.set_persistent (true); 998 guideline_tools.set_unique (false); 999 1000 grid.set_persistent (true); 1001 grid.set_unique (true); 1002 1003 shape_tools.set_persistent (true); 1004 shape_tools.set_unique (true); 1005 1006 // let these tools progagate events even when other tools are selected 1007 foreach (Tool t in draw_tools.tool) { 1008 t.editor_events = true; 1009 } 1010 1011 foreach (Tool t in shape_tools.tool) { 1012 t.editor_events = true; 1013 t.persistent = true; 1014 } 1015 1016 move_background.editor_events = true; 1017 cut_background.editor_events = true; 1018 move_canvas.editor_events = true; 1019 1020 move_background.persistent = true; 1021 cut_background.persistent = true; 1022 move_canvas.persistent = true; 1023 1024 // Default selection 1025 IdleSource idle = new IdleSource (); 1026 idle.set_callback (() => { 1027 MainWindow.get_toolbox ().reset_active_tool (); 1028 1029 foresight_tool.set_selected (true); 1030 update_drawing_and_background_tools (foresight_tool); 1031 1032 select_draw_tool (); 1033 set_point_type_from_preferences (); 1034 1035 if (GlyphCanvas.get_current_glyph ().get_show_help_lines ()) { 1036 help_lines.set_selected (true); 1037 help_lines.set_active (false); 1038 } 1039 1040 add_new_grid (1); 1041 add_new_grid (2); 1042 add_new_grid (4); 1043 1044 MainWindow.get_toolbox ().move (0, 0); 1045 1046 return false; 1047 }); 1048 idle.attach (null); 1049 1050 // update selelction when the user switches tab 1051 MainWindow.get_tab_bar ().signal_tab_selected.connect((tab) => { 1052 Glyph glyph; 1053 1054 if (tab.get_display () is Glyph) { 1055 glyph = (Glyph) tab.get_display (); 1056 show_bg.set_selected (glyph.get_background_visible ()); 1057 update_line_selection (glyph); 1058 } 1059 }); 1060 } 1061 1062 void auto_trace_background () { 1063 Glyph g = MainWindow.get_current_glyph (); 1064 BackgroundImage? bg = g.get_background_image (); 1065 BackgroundImage b; 1066 PathList pl; 1067 1068 if (bg != null) { 1069 b = (!) bg; 1070 pl = b.autotrace (); 1071 foreach (Path p in pl.paths) { 1072 g.add_path (p); 1073 } 1074 } 1075 } 1076 1077 void update_line_selection (Glyph glyph) { 1078 help_lines.set_selected (glyph.get_show_help_lines ()); 1079 xheight_help_lines.set_selected (glyph.get_xheight_lines_visible ()); 1080 background_help_lines.set_selected (glyph.get_margin_lines_visible ()); 1081 } 1082 1083 public static void set_point_type_from_preferences () { 1084 string type = Preferences.get ("point_type"); 1085 if (type == "double_points") { 1086 Toolbox.select_tool_by_name ("double_points"); 1087 } else if (type == "quadratic_points") { 1088 Toolbox.select_tool_by_name ("quadratic_points"); 1089 } if (type == "cubic_points") { 1090 Toolbox.select_tool_by_name ("cubic_points"); 1091 } 1092 } 1093 1094 void hide_all_modifiers () { 1095 x_coordinate.set_tool_visibility (false); 1096 y_coordinate.set_tool_visibility (false); 1097 rotation.set_tool_visibility (false); 1098 width.set_tool_visibility (false); 1099 height.set_tool_visibility (false); 1100 skew.set_tool_visibility (false); 1101 reverse_path_tool.set_tool_visibility (false); 1102 move_layer.set_tool_visibility (false); 1103 flip_vertical.set_tool_visibility (false); 1104 flip_horizontal.set_tool_visibility (false); 1105 1106 tie_handles.set_tool_visibility (false); 1107 reflect_handle.set_tool_visibility (false); 1108 create_line.set_tool_visibility (false); 1109 1110 quadratic_points.set_tool_visibility (false); 1111 cubic_points.set_tool_visibility (false); 1112 double_points.set_tool_visibility (false); 1113 convert_points.set_tool_visibility (false); 1114 1115 cut_background.set_tool_visibility (false); 1116 show_bg.set_tool_visibility (false); 1117 bg_selection.set_tool_visibility (false); 1118 background_threshold.set_tool_visibility (false); 1119 background_scale.set_tool_visibility (false); 1120 high_contrast_background.set_tool_visibility (false); 1121 auto_trace_resolution.set_tool_visibility (false); 1122 auto_trace.set_tool_visibility (false); 1123 auto_trace_simplify.set_tool_visibility (false); 1124 delete_background.set_tool_visibility (false); 1125 } 1126 1127 void show_background_tool_modifiers () { 1128 draw_tool_modifiers.set_headline (t_("Background Tools")); 1129 1130 cut_background.set_tool_visibility (true); 1131 show_bg.set_tool_visibility (true); 1132 bg_selection.set_tool_visibility (true); 1133 background_threshold.set_tool_visibility (true); 1134 background_scale.set_tool_visibility (true); 1135 high_contrast_background.set_tool_visibility (true); 1136 auto_trace_resolution.set_tool_visibility (true); 1137 auto_trace.set_tool_visibility (true); 1138 auto_trace_simplify.set_tool_visibility (true); 1139 delete_background.set_tool_visibility (true); 1140 } 1141 1142 void show_point_tool_modifiers () { 1143 draw_tool_modifiers.set_headline (t_("Control Points")); 1144 1145 tie_handles.set_tool_visibility (true); 1146 reflect_handle.set_tool_visibility (true); 1147 create_line.set_tool_visibility (true); 1148 1149 quadratic_points.set_tool_visibility (true); 1150 cubic_points.set_tool_visibility (true); 1151 double_points.set_tool_visibility (true); 1152 convert_points.set_tool_visibility (true); 1153 1154 reverse_path_tool.set_tool_visibility (true); 1155 } 1156 1157 void show_object_tool_modifiers () { 1158 draw_tool_modifiers.set_headline (t_("Object Tools")); 1159 1160 x_coordinate.set_tool_visibility (true); 1161 y_coordinate.set_tool_visibility (true); 1162 rotation.set_tool_visibility (true); 1163 width.set_tool_visibility (true); 1164 height.set_tool_visibility (true); 1165 skew.set_tool_visibility (true); 1166 1167 reverse_path_tool.set_tool_visibility (true); 1168 move_layer.set_tool_visibility (true); 1169 flip_vertical.set_tool_visibility (true); 1170 flip_horizontal.set_tool_visibility (true); 1171 } 1172 1173 public void update_drawing_and_background_tools (Tool current_tool) { 1174 IdleSource idle = new IdleSource (); 1175 1176 idle.set_callback (() => { 1177 Glyph g = MainWindow.get_current_glyph (); 1178 1179 hide_all_modifiers (); 1180 1181 move_background.set_selected (false); 1182 cut_background.set_selected (false); 1183 1184 foresight_tool.set_selected (false); 1185 pen_tool.set_selected (false); 1186 point_tool.set_selected (false); 1187 zoom_tool.set_selected (false); 1188 move_tool.set_selected (false); 1189 resize_tool.set_selected (false); 1190 stroke_tool.set_selected (false); 1191 track_tool.set_selected (false); 1192 move_canvas.set_selected (false); 1193 delete_background.set_selected (false); 1194 1195 show_bg.set_selected (g.get_background_visible ()); 1196 show_bg.set_active (false); 1197 bg_selection.set_selected (false); 1198 background_scale.set_active (false); 1199 1200 rectangle.set_selected (false); 1201 circle.set_selected (false); 1202 1203 reverse_path_tool.set_selected (false); 1204 move_layer.set_selected (false); 1205 flip_vertical.set_selected (false); 1206 flip_horizontal.set_selected (false); 1207 1208 current_tool.set_selected (true); 1209 1210 if (resize_tool.is_selected () || move_tool.is_selected ()) { 1211 show_object_tool_modifiers (); 1212 } else if (foresight_tool.is_selected () 1213 || pen_tool.is_selected () 1214 || point_tool.is_selected () 1215 || track_tool.is_selected ()) { 1216 show_point_tool_modifiers (); 1217 } else if (move_background.is_selected () 1218 || cut_background.is_selected () 1219 || show_bg.is_selected () 1220 || high_contrast_background.is_selected () 1221 || auto_trace.is_selected ()) { 1222 show_background_tool_modifiers (); 1223 } 1224 1225 MainWindow.get_toolbox ().update_expanders (); 1226 Toolbox.redraw_tool_box (); 1227 1228 return false; 1229 }); 1230 1231 idle.attach (null); 1232 } 1233 1234 void update_type_selection () { 1235 IdleSource idle = new IdleSource (); 1236 1237 // Do this in idle, after the animation 1238 idle.set_callback (() => { 1239 quadratic_points.set_selected (false); 1240 cubic_points.set_selected (false); 1241 double_points.set_selected (false); 1242 1243 switch (point_type) { 1244 case PointType.QUADRATIC: 1245 quadratic_points.set_selected (true); 1246 break; 1247 case PointType.CUBIC: 1248 cubic_points.set_selected (true); 1249 break; 1250 case PointType.DOUBLE_CURVE: 1251 double_points.set_selected (true); 1252 break; 1253 } 1254 1255 convert_points.set_selected (false); 1256 1257 Toolbox.redraw_tool_box (); 1258 return false; 1259 }); 1260 1261 idle.attach (null); 1262 } 1263 1264 public override Gee.ArrayList<Expander> get_expanders () { 1265 return expanders; 1266 } 1267 1268 /** Insert new points of this type. */ 1269 public static PointType get_selected_point_type () { 1270 return point_type; 1271 } 1272 1273 private void select_draw_tool () { 1274 Toolbox.select_tool_by_name ("pen_tool"); 1275 } 1276 1277 public void remove_all_grid_buttons () { 1278 grid_expander.tool.clear (); 1279 1280 GridTool.sizes.clear (); 1281 1282 MainWindow.get_toolbox ().update_expanders (); 1283 MainWindow.get_toolbox ().redraw (0, 0, Toolbox.allocation_width, Toolbox.allocation_height); 1284 } 1285 1286 public void parse_grid (string spin_button_value) { 1287 SpinButton sb = add_new_grid (); 1288 sb.set_value (spin_button_value); 1289 MainWindow.get_toolbox ().select_tool (sb); 1290 } 1291 1292 public SpinButton add_new_grid (double size = 2) { 1293 SpinButton grid_width = new SpinButton ("grid_width", t_("Set size for grid")); 1294 Toolbox tb = MainWindow.get_toolbox (); 1295 1296 grid_width.new_value_action.connect((self) => { 1297 grid_width.select_action (grid_width); 1298 }); 1299 1300 grid_width.select_action.connect((self) => { 1301 SpinButton sb = (SpinButton) self; 1302 GridTool.set_grid_width (sb.get_value ()); 1303 GlyphCanvas.redraw (); 1304 }); 1305 1306 grid_expander.add_tool (grid_width); 1307 1308 GridTool.sizes.add (grid_width); 1309 1310 grid_width.set_value_round (size); 1311 1312 tb.update_expanders (); 1313 1314 tb.redraw (0, 0, Toolbox.allocation_width, Toolbox.allocation_height); 1315 1316 tb.select_tool (grid_width); 1317 grid_width.set_active (false); 1318 1319 return grid_width; 1320 } 1321 1322 public void remove_current_grid () { 1323 Tool grid_width; 1324 Toolbox tb = MainWindow.get_toolbox (); 1325 1326 foreach (Tool t in grid_expander.tool) { 1327 if (t.is_selected () && t is SpinButton) { 1328 GridTool.sizes.remove ((SpinButton)t); 1329 grid_expander.tool.remove (t); 1330 break; 1331 } 1332 } 1333 1334 if (grid_expander.tool.size > 0) { 1335 grid_width = grid_expander.tool.get (grid_expander.tool.size - 1); 1336 tb.select_tool (grid_width); 1337 grid_width.set_active (false); 1338 } 1339 1340 MainWindow.get_toolbox ().update_expanders (); 1341 tb.redraw (0, 0, Toolbox.allocation_width, Toolbox.allocation_height); 1342 } 1343 1344 private void add_expander (Expander e) { 1345 expanders.add (e); 1346 } 1347 1348 public override Gee.ArrayList<string> get_displays () { 1349 Gee.ArrayList<string> d = new Gee.ArrayList<string> (); 1350 d.add ("Glyph"); 1351 return d; 1352 } 1353 } 1354 1355 } 1356