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