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