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