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