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