.
1 /*
2 Copyright (C) 2012, 2013, 2014 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 Expander draw_tools;
26 public static Expander grid_expander;
27 Expander shape_tools;
28 public static Expander draw_tool_modifiers;
29 public static Expander stroke_expander;
30 public static Expander zoombar_tool;
31 public static Expander view_tools;
32 public static Expander guideline_tools;
33
34 public static PointType point_type = PointType.DOUBLE_CURVE;
35
36 public static Tool add_stroke;
37 public static SpinButton object_stroke;
38 Tool outline;
39
40 public static MoveTool move_tool;
41 public static PenTool pen_tool;
42
43 public static BezierTool bezier_tool;
44 PointTool point_tool;
45 public static ZoomTool zoom_tool;
46 public static ResizeTool resize_tool;
47 public static TrackTool track_tool;
48 public static BackgroundTool move_background;
49 public static Tool move_canvas;
50
51 static Tool quadratic_points;
52 static Tool cubic_points;
53 static Tool double_points;
54 static Tool convert_points;
55
56 public static CutBackgroundTool cut_background;
57 Tool show_bg;
58 Tool bg_selection;
59 SpinButton background_threshold;
60 public static SpinButton background_scale;
61 Tool high_contrast_background;
62 SpinButton auto_trace_resolution;
63 Tool auto_trace;
64 SpinButton auto_trace_simplify;
65 Tool delete_background;
66
67 Tool rectangle;
68 Tool circle;
69
70 Tool help_lines;
71 Tool xheight_help_lines;
72 Tool background_help_lines;
73
74 SpinButton x_coordinate;
75 SpinButton y_coordinate;
76 SpinButton rotation;
77 SpinButton width;
78 SpinButton height;
79 SpinButton skew;
80
81 Tool tie_handles;
82 Tool reflect_handle;
83 Tool create_line;
84 Tool close_path_tool;
85
86 Tool delete_button;
87 public Tool insert_point_on_path_tool;
88 Tool undo_tool;
89 Tool select_all_button;
90
91 OrientationTool reverse_path_tool;
92 Tool move_layer;
93 Tool flip_vertical;
94 Tool flip_horizontal;
95
96 public ZoomBar zoom_bar;
97
98 public DrawingTools (GlyphCanvas main_glyph_canvas) {
99 bool selected_line;
100
101 glyph_canvas = main_glyph_canvas;
102
103 background_scale = new SpinButton ();
104
105 draw_tools = new Expander (t_("Drawing Tools"));
106 draw_tool_modifiers = new Expander (t_("Control Point"));
107 stroke_expander = new Expander (t_("Stroke"));
108 shape_tools = new Expander (t_("Geometrical Shapes"));
109 zoombar_tool = new Expander (t_("Zoom"));
110 view_tools = new Expander ();
111 guideline_tools = new Expander (t_("Guidelines & Grid"));
112
113 Expander font_name = new Expander ();
114 Expander key_tools = new Expander (); // tools on android
115 Expander test_tools = new Expander ();
116 Expander grid = new Expander (t_("Grid Size"));
117
118 grid_expander = grid;
119
120 // font name
121 font_name.add_tool (new FontName ());
122
123 // Draw tools
124 bezier_tool = new BezierTool ("bezier_tool");
125 bezier_tool.select_action.connect ((self) => {
126 update_drawing_and_background_tools (self);
127 });
128 draw_tools.add_tool (bezier_tool);
129
130 pen_tool = new PenTool ("pen_tool");
131 pen_tool.select_action.connect ((self) => {
132 update_drawing_and_background_tools (self);
133 });
134 draw_tools.add_tool (pen_tool);
135
136 point_tool = new PointTool ("point_tool");
137 point_tool.select_action.connect ((self) => {
138 update_drawing_and_background_tools (self);
139 });
140 draw_tools.add_tool (point_tool);
141
142 zoom_tool = new ZoomTool ("zoom_tool");
143 zoom_tool.select_action.connect ((self) => {
144 update_drawing_and_background_tools (self);
145 });
146 draw_tools.add_tool (zoom_tool);
147
148 move_tool = new MoveTool ("move");
149 move_tool.select_action.connect ((self) => {
150 update_drawing_and_background_tools (self);
151 });
152 draw_tools.add_tool (move_tool);
153
154 resize_tool = new ResizeTool ("resize");
155 resize_tool.select_action.connect ((self) => {
156 update_drawing_and_background_tools (self);
157 });
158 draw_tools.add_tool (resize_tool);
159
160 track_tool = new TrackTool ("track"); // draw outline on freehand
161 track_tool.select_action.connect ((self) => {
162 update_drawing_and_background_tools (self);
163 });
164 draw_tools.add_tool (track_tool);
165
166 move_background = new BackgroundTool ("move_background");
167 move_background.select_action.connect ((self) => {
168 update_drawing_and_background_tools (self);
169 });
170 draw_tools.add_tool (move_background);
171
172 move_canvas = new Tool ("move_canvas", t_("Move canvas"));
173 move_canvas.select_action.connect ((self) => {
174 update_drawing_and_background_tools (self);
175 });
176 draw_tools.add_tool (move_canvas);
177
178 // Tools on android
179 // Delete key
180 delete_button = new Tool ("delete_button", t_("Delete"));
181 delete_button.select_action.connect ((self) => {
182 TabContent.key_press (Key.DEL);
183 });
184 key_tools.add_tool (delete_button);
185
186 // Select all points or paths
187 select_all_button = new Tool ("select_all", t_("Select all points or paths"));
188 select_all_button.select_action.connect ((self) => {
189 Glyph g = MainWindow.get_current_glyph ();
190
191 if (point_tool.is_selected ()
192 || pen_tool.is_selected ()
193 || track_tool.is_selected ()) {
194 pen_tool.select_all_points ();
195 g.open_path ();
196 } else {
197 DrawingTools.move_tool.select_all_paths ();
198 }
199 });
200 key_tools.add_tool (select_all_button);
201
202 // Undo
203 undo_tool = new Tool ("undo_tool", t_("Undo"));
204 undo_tool.select_action.connect ((self) => {
205 TabContent.undo ();
206 });
207 key_tools.add_tool (undo_tool);
208
209 bool insert_points = false;
210 insert_point_on_path_tool = new Tool ("new_point_on_path", t_("Insert new points on path"));
211 insert_point_on_path_tool.select_action.connect ((self) => {
212 insert_points = !insert_points;
213 insert_point_on_path_tool.set_selected (insert_points);
214 });
215 insert_point_on_path_tool.set_persistent (true);
216 key_tools.add_tool (insert_point_on_path_tool);
217
218 // quadratic Bézier points
219 quadratic_points = new Tool ("quadratic_points", t_("Create quadratic Bézier curves"));
220 quadratic_points.select_action.connect ((self) => {
221 point_type = PointType.QUADRATIC;
222 Preferences.set ("point_type", "quadratic_points");
223 update_type_selection ();
224 });
225 draw_tool_modifiers.add_tool (quadratic_points);
226
227 // cubic Bézier points
228 cubic_points = new Tool ("cubic_points", t_("Create cubic Bézier curves"));
229 cubic_points.select_action.connect ((self) => {
230 point_type = PointType.CUBIC;
231 Preferences.set ("point_type", "cubic_points");
232 update_type_selection ();
233 });
234 draw_tool_modifiers.add_tool (cubic_points);
235
236 // two quadratic points off curve points for each quadratic control point
237 double_points = new Tool ("double_points", t_("Quadratic path with two line handles"));
238 double_points.select_action.connect ((self) => {
239 point_type = PointType.DOUBLE_CURVE;
240 Preferences.set ("point_type", "double_points");
241 update_type_selection ();
242 });
243 draw_tool_modifiers.add_tool (double_points);
244
245 // convert point
246 convert_points = new Tool ("convert_point", t_("Convert selected points"));
247 convert_points.select_action.connect ((self) => {
248 PenTool.convert_point_types ();
249 GlyphCanvas.redraw ();
250 update_type_selection ();
251 PenTool.reset_stroke ();
252 });
253 convert_points.set_persistent (false);
254 draw_tool_modifiers.add_tool (convert_points);
255
256 // x coordinate
257 x_coordinate = new SpinButton ("x_coordinate", t_("X coordinate"));
258 x_coordinate.set_big_number (true);
259 x_coordinate.set_int_value ("0.000");
260 x_coordinate.set_int_step (0.1);
261 x_coordinate.set_min (-999.99);
262 x_coordinate.set_max (999.99);
263 x_coordinate.show_icon (true);
264 x_coordinate.set_persistent (false);
265 x_coordinate.new_value_action.connect((self) => {
266 Glyph glyph = MainWindow.get_current_glyph ();
267 double x, y, w, h;
268 double delta;
269
270 glyph.selection_boundaries (out x, out y, out w, out h);
271 delta = x_coordinate.get_value () - x + glyph.left_limit;
272
273 foreach (Path path in glyph.active_paths) {
274 path.move (delta, 0);
275 }
276
277 GlyphCanvas.redraw ();
278 });
279 draw_tool_modifiers.add_tool (x_coordinate);
280
281 move_tool.objects_moved.connect (() => {
282 Glyph glyph = MainWindow.get_current_glyph ();
283 x_coordinate.set_value_round (MoveTool.selection_box_center_x
284 - (MoveTool.selection_box_width / 2)
285 - glyph.left_limit, true, false);
286 });
287
288 move_tool.selection_changed.connect (() => {
289 Glyph glyph = MainWindow.get_current_glyph ();
290 x_coordinate.set_value_round (MoveTool.selection_box_center_x
291 - (MoveTool.selection_box_width / 2)
292 - glyph.left_limit, true, false);
293 });
294
295 move_tool.objects_deselected.connect (() => {
296 x_coordinate.set_value_round (0, true, false);
297 x_coordinate.hide_value ();
298 });
299
300 // y coordinate
301 y_coordinate = new SpinButton ("y_coordinate", t_("Y coordinate"));
302 y_coordinate.set_big_number (true);
303 y_coordinate.set_int_value ("0.000");
304 y_coordinate.set_int_step (0.1);
305 y_coordinate.set_min (-999.99);
306 y_coordinate.set_max (999.99);
307 y_coordinate.show_icon (true);
308 y_coordinate.set_persistent (false);
309 y_coordinate.new_value_action.connect((self) => {
310 double x, y, w, h;
311 Glyph glyph = MainWindow.get_current_glyph ();
312 Font font = BirdFont.get_current_font ();
313
314 glyph.selection_boundaries (out x, out y, out w, out h);
315
316 foreach (Path path in glyph.active_paths) {
317 path.move (0, y_coordinate.get_value () - (y - h) - font.base_line);
318 }
319
320 GlyphCanvas.redraw ();
321 });
322 draw_tool_modifiers.add_tool (y_coordinate);
323
324 move_tool.objects_moved.connect (() => {
325 Font font = BirdFont.get_current_font ();
326 y_coordinate.set_value_round (MoveTool.selection_box_center_y
327 - (MoveTool.selection_box_height / 2)
328 + font.base_line, true, false);
329 });
330
331 move_tool.selection_changed.connect (() => {
332 Font font = BirdFont.get_current_font ();
333 y_coordinate.set_value_round (MoveTool.selection_box_center_y
334 - (MoveTool.selection_box_height / 2)
335 + font.base_line, true, false);
336 });
337
338 move_tool.objects_deselected.connect (() => {
339 y_coordinate.set_value_round (0, true, false);
340 y_coordinate.hide_value ();
341 });
342
343 // rotation
344 rotation = new SpinButton ("rotation", t_("Rotation"));
345 rotation.set_big_number (true);
346 rotation.set_int_value ("0.000");
347 rotation.set_int_step (0.1);
348 rotation.set_min (-360);
349 rotation.set_max (360);
350 rotation.show_icon (true);
351 rotation.set_persistent (false);
352 rotation.new_value_action.connect ((self) => {
353 double x, y, w, h;
354 Glyph glyph = MainWindow.get_current_glyph ();
355 double angle = (self.get_value () / 360) * 2 * PI;
356 Path last_path;
357 glyph.selection_boundaries (out x, out y, out w, out h);
358
359 x += w / 2;
360 y -= h / 2;
361
362 if (glyph.active_paths.size > 0) {
363 last_path = glyph.active_paths.get (glyph.active_paths.size - 1);
364 resize_tool.rotate_selected_paths (angle - last_path.rotation, x, y);
365 }
366
367 GlyphCanvas.redraw ();
368 });
369
370 resize_tool.objects_rotated.connect ((angle) => {
371 rotation.set_value_round (angle, true, false);
372 PenTool.reset_stroke ();
373 });
374
375 move_tool.objects_deselected.connect (() => {
376 rotation.set_value_round (0, true, false);
377 rotation.hide_value ();
378 });
379
380 draw_tool_modifiers.add_tool (rotation);
381
382 // skew
383 skew = new SpinButton ("skew", t_("Skew"));
384 skew.set_big_number (true);
385 skew.set_int_value ("0.000");
386 skew.set_int_step (1);
387 skew.set_min (-100);
388 skew.set_max (100);
389 skew.show_icon (true);
390 skew.set_persistent (false);
391 skew.new_value_action.connect ((self) => {
392 resize_tool.skew (-skew.get_value ());
393 PenTool.reset_stroke ();
394 GlyphCanvas.redraw ();
395 });
396
397 move_tool.objects_moved.connect (() => {
398 Glyph glyph = MainWindow.get_current_glyph ();
399 double d;
400
401 if (glyph.active_paths.size > 0) {
402 d = glyph.active_paths.get (0).skew;
403 resize_tool.last_skew = d;
404 skew.set_value_round (-d, true, false);
405 }
406 });
407
408 move_tool.objects_deselected.connect (() => {
409 skew.set_value_round (0, true, false);
410 skew.hide_value ();
411 });
412
413 draw_tool_modifiers.add_tool (skew);
414
415 // width
416 width = new SpinButton ("width", t_("Width"));
417 width.set_big_number (true);
418 width.set_int_value ("0.0000");
419 width.set_int_step (0.01);
420 width.show_icon (true);
421 width.set_persistent (false);
422 width.new_value_action.connect ((self) => {
423 double x, y, w, h;
424 Glyph glyph;
425 double new_size;
426
427 glyph = MainWindow.get_current_glyph ();
428 glyph.selection_boundaries (out x, out y, out w, out h);
429
430 new_size = self.get_value () / w;
431
432 if (self.get_value () > 0 && new_size != 1) {
433 resize_tool.resize_selected_paths (new_size);
434 }
435
436 GlyphCanvas.redraw ();
437 });
438 draw_tool_modifiers.add_tool (width);
439
440 // height
441 height = new SpinButton ("height", t_("Height"));
442 height.set_big_number (true);
443 height.set_int_value ("0.0000");
444 height.set_int_step (0.01);
445 height.show_icon (true);
446 height.set_persistent (false);
447 height.new_value_action.connect ((self) => {
448 double x, y, w, h;
449 Glyph glyph;
450 double new_size;
451
452 glyph = MainWindow.get_current_glyph ();
453 glyph.selection_boundaries (out x, out y, out w, out h);
454
455 new_size = self.get_value () / h;
456
457 if (self.get_value () > 0 && new_size != 1) {
458 resize_tool.resize_selected_paths (new_size);
459 }
460
461 GlyphCanvas.redraw ();
462 });
463 draw_tool_modifiers.add_tool (height);
464
465 resize_tool.objects_resized.connect ((w, h) => {
466 height.set_value_round (h, true, false);
467 width.set_value_round (w, true, false);
468 });
469
470 move_tool.objects_deselected.connect (() => {
471 width.set_value_round (0, true, false);
472 width.hide_value ();
473
474 height.set_value_round (0, true, false);
475 height.hide_value ();
476 });
477
478 move_tool.objects_moved.connect (() => {
479 width.set_value_round (MoveTool.selection_box_width, true, false);
480 height.set_value_round (MoveTool.selection_box_height, true, false);
481 });
482
483 // tie edit point handles
484 tie_handles = new Tool ("tie_point", t_("Tie curve handles for the selected edit point"));
485 tie_handles.select_action.connect ((self) => {
486 bool tie, end_point;
487 EditPoint p;
488
489 if (PenTool.move_selected_handle) {
490 p = PenTool.active_handle.parent;
491 tie = !p.tie_handles;
492
493 // don't tie end points
494 foreach (Path path in MainWindow.get_current_glyph ().active_paths) {
495 if (path.is_open ()) {
496 if (p == path.get_first_point () || p == path.get_last_point ()) {
497 tie = false;
498 }
499 }
500 }
501
502 if (tie) {
503 p.process_tied_handle ();
504 p.set_reflective_handles (false);
505 }
506
507 p.set_tie_handle (tie);
508
509 PenTool.handle_selection.path.update_region_boundaries ();
510 } else {
511 foreach (PointSelection ep in PenTool.selected_points) {
512 tie = !ep.point.tie_handles;
513
514 end_point = ep.point == ep.path.get_first_point ()
515 || ep.point == ep.path.get_last_point ();
516
517 if (!ep.path.is_open () || !end_point) {
518 if (tie) {
519 ep.point.process_tied_handle ();
520 ep.point.set_reflective_handles (false);
521 }
522
523 ep.point.set_tie_handle (tie);
524 ep.path.update_region_boundaries ();
525 }
526 }
527 }
528
529 MainWindow.get_current_glyph ().update_view ();
530 PenTool.reset_stroke ();
531 });
532 draw_tool_modifiers.add_tool (tie_handles);
533
534 // symmetrical handles
535 reflect_handle = new Tool ("symmetric", t_("Symmetrical handles"));
536 reflect_handle.select_action.connect ((self) => {
537 bool symmetrical, end_point;
538 PointSelection ep;
539 if (PenTool.selected_points.size > 0) {
540 ep = PenTool.selected_points.get (0);
541 symmetrical = ep.point.reflective_point;
542
543 foreach (PointSelection p in PenTool.selected_points) {
544 end_point = p.point == p.path.get_first_point ()
545 || p.point == p.path.get_last_point ();
546
547 if (!p.path.is_open () || !end_point) {
548 p.point.set_reflective_handles (!symmetrical);
549 p.point.process_symmetrical_handles ();
550
551 if (symmetrical) {
552 ep.point.set_tie_handle (false);
553 }
554
555 p.path.update_region_boundaries ();
556 }
557 }
558 MainWindow.get_current_glyph ().update_view ();
559 }
560
561 PenTool.reset_stroke ();
562 });
563 draw_tool_modifiers.add_tool (reflect_handle);
564
565 create_line = new Tool ("create_line", t_("Convert segment to line."));
566 create_line.select_action.connect ((self) => {
567 PenTool.convert_segment_to_line ();
568 MainWindow.get_current_glyph ().update_view ();
569 PenTool.reset_stroke ();
570 });
571 draw_tool_modifiers.add_tool (create_line);
572
573 reverse_path_tool = new OrientationTool ("reverse_path", t_("Create counter from outline"));
574 draw_tool_modifiers.add_tool (reverse_path_tool);
575
576 // close path
577 close_path_tool = new Tool ("close_path", t_("Close path"));
578 close_path_tool.select_action.connect ((self) => {
579 Tool current;
580 Glyph g;
581
582 current = MainWindow.get_toolbox ().get_current_tool ();
583
584 if (current is BezierTool) {
585 ((BezierTool) current).stop_drawing ();
586 }
587
588 PenTool.reset_stroke ();
589
590 g = MainWindow.get_current_glyph ();
591 g.close_path ();
592 g.clear_active_paths ();
593
594 self.set_selected (false);
595 GlyphCanvas.redraw ();
596 });
597 draw_tool_modifiers.add_tool (close_path_tool);
598
599 move_layer = new Tool ("move_layer", t_("Move to path to the bottom layer"));
600 move_layer.select_action.connect ((self) => {
601 Glyph g = MainWindow.get_current_glyph ();
602
603 foreach (Path p in g.active_paths) {
604 g.path_list.remove (p);
605 g.path_list.insert (0, p);
606 }
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.set_threshold (background_threshold.get_value ());
716 b.update_background ();
717 }
718 });
719
720 draw_tool_modifiers.add_tool (background_threshold);
721
722 auto_trace_resolution = new SpinButton ("auto_trace_resolution", t_("Amount of autotrace details"));
723 auto_trace_resolution.set_value_round (1);
724 auto_trace_resolution.show_icon (true);
725
726 auto_trace_resolution.new_value_action.connect ((self) => {
727 Glyph g = MainWindow.get_current_glyph ();
728 BackgroundImage? bg = g.get_background_image ();
729 BackgroundImage b;
730
731 if (bg != null) {
732 b = (!) bg;
733 b.set_trace_resolution (auto_trace_resolution.get_value ());
734 b.update_background ();
735 }
736 });
737
738 draw_tool_modifiers.add_tool (auto_trace_resolution);
739
740 auto_trace_simplify = new SpinButton ("auto_trace_simplify", t_("Autotrace simplification"));
741 auto_trace_simplify.set_value_round (0.5);
742 auto_trace_simplify.show_icon (true);
743
744 auto_trace_simplify.new_value_action.connect ((self) => {
745 Glyph g = MainWindow.get_current_glyph ();
746 BackgroundImage? bg = g.get_background_image ();
747 BackgroundImage b;
748
749 if (bg != null) {
750 b = (!) bg;
751 b.set_trace_simplification (auto_trace_simplify.get_value ());
752 }
753 });
754
755 draw_tool_modifiers.add_tool (auto_trace_simplify);
756
757 auto_trace = new Tool ("autotrace", t_("Autotrace background image"));
758 auto_trace.select_action.connect ((self) => {
759 Task t = new Task ();
760 t.task.connect (auto_trace_background);
761 MainWindow.native_window.run_background_thread (t);
762 });
763
764 draw_tool_modifiers.add_tool (auto_trace);
765
766 delete_background = new Tool ("delete_background", t_("Delete background image"));
767 delete_background.select_action.connect ((self) => {
768 MainWindow.get_current_glyph ().delete_background ();
769 });
770
771 draw_tool_modifiers.add_tool (delete_background);
772
773 // add stroke to path
774 add_stroke = new Tool ("apply_stroke", t_("Apply stroke"));
775 add_stroke.select_action.connect ((self) => {
776 Font f;
777 Glyph g = MainWindow.get_current_glyph ();
778 StrokeTool.add_stroke = !StrokeTool.add_stroke;
779 StrokeTool.stroke_width = object_stroke.get_value ();
780
781 add_stroke.selected = StrokeTool.add_stroke;
782
783 GlyphCanvas.redraw ();
784 g.store_undo_state ();
785
786 if (StrokeTool.add_stroke) {
787 foreach (Path p in g.active_paths) {
788 p.stroke = StrokeTool.stroke_width;
789 }
790 } else {
791 foreach (Path p in g.active_paths) {
792 p.stroke = 0;
793 }
794 }
795
796 f = BirdFont.get_current_font ();
797 f.settings.set_setting ("apply_stroke", @"$(StrokeTool.add_stroke)");
798
799 add_stroke.selected = StrokeTool.add_stroke;
800 });
801 stroke_expander.add_tool (add_stroke);
802 add_stroke.selected = StrokeTool.add_stroke;
803
804 // edit stroke width
805 object_stroke = new SpinButton ("object_stroke", t_("Stroke width"));
806 object_stroke.set_big_number (true);
807 object_stroke.set_value_round (2);
808 object_stroke.set_max (0.01);
809 object_stroke.set_max (50);
810
811 object_stroke.new_value_action.connect((self) => {
812 Font f;
813 Glyph g = MainWindow.get_current_glyph ();
814
815 bool tool = resize_tool.is_selected ()
816 || move_tool.is_selected ()
817 || pen_tool.is_selected ()
818 || track_tool.is_selected ()
819 || point_tool.is_selected ()
820 || bezier_tool.is_selected ();
821
822 StrokeTool.stroke_width = object_stroke.get_value ();
823
824 if (tool && StrokeTool.add_stroke) {
825 foreach (Path p in g.active_paths) {
826 p.stroke = StrokeTool.stroke_width;
827 p.reset_stroke ();
828 }
829 }
830
831 f = BirdFont.get_current_font ();
832 f.settings.set_setting ("stroke_width", object_stroke.get_display_value ());
833
834 GlyphCanvas.redraw ();
835 });
836 stroke_expander.add_tool (object_stroke);
837
838 move_tool.selection_changed.connect (() => {
839 update_stroke_settings ();
840 });
841
842 move_tool.objects_moved.connect (() => {
843 update_stroke_settings ();
844 });
845
846 // create outline from path
847 outline = new Tool ("stroke_to_outline", t_("Create outline form stroke"));
848 outline.select_action.connect ((self) => {
849 StrokeTool.stroke_selected_paths ();
850 outline.set_selected (false);
851 });
852 stroke_expander.add_tool (outline);
853
854 if (BirdFont.has_argument ("--test")) {
855 Tool test_case = new Tool ("test_case");
856 test_case.select_action.connect((self) => {
857 if (self.is_selected ()) {
858 if (TestBirdFont.is_running ()) {
859 TestBirdFont.pause ();
860 } else {
861 TestBirdFont.continue ();
862 }
863 }
864 });
865 test_tools.add_tool (test_case);
866
867 Tool slow_test = new Tool ("slow_test");
868 slow_test.select_action.connect((self) => {
869 bool s = TestBirdFont.is_slow_test ();
870 TestBirdFont.set_slow_test (!s);
871 s = TestBirdFont.is_slow_test ();
872 self.set_selected (s);
873 });
874
875 test_tools.add_tool (slow_test);
876
877 // Run from commad line
878 string? st = BirdFont.get_argument ("--test");
879 if (st != null && ((!)st).char_count () > 0) {
880 IdleSource idle = new IdleSource ();
881
882 idle.set_callback (() => {
883 MainWindow.get_toolbox ().select_tool (test_case);
884 return false;
885 });
886
887 idle.attach (null);
888 }
889
890 if (BirdFont.has_argument ("--slow")) {
891 MainWindow.get_toolbox ().select_tool (slow_test);
892 }
893
894 }
895
896 // guide lines, grid and other guidlines
897 help_lines = new Tool ("help_lines", t_("Show guidelines"));
898 help_lines.select_action.connect ((self) => {
899 bool h;
900 h = GlyphCanvas.get_current_glyph ().get_show_help_lines ();
901 GlyphCanvas.get_current_glyph ().set_show_help_lines (!h);
902 self.set_selected (!h);
903 GlyphCanvas.get_current_glyph ().redraw_help_lines ();
904 });
905 selected_line = GlyphCanvas.get_current_glyph ().get_show_help_lines ();
906 help_lines.set_selected (selected_line);
907 guideline_tools.add_tool (help_lines);
908
909 xheight_help_lines = new Tool ("show_xheight_helplines", t_("Show more guidelines"));
910 xheight_help_lines.select_action.connect ((self) => {
911 Glyph g = MainWindow.get_current_glyph ();
912 bool v = !g.get_xheight_lines_visible ();
913 g.set_xheight_lines_visible (v);
914 self.set_selected (v);
915 GlyphCanvas.redraw ();
916
917 if (v && !help_lines.is_selected ()) {
918 MainWindow.get_toolbox ().select_tool (help_lines);
919 }
920 });
921 selected_line = GlyphCanvas.get_current_glyph ().get_xheight_lines_visible ();
922 xheight_help_lines.set_selected (selected_line);
923 guideline_tools.add_tool (xheight_help_lines);
924
925 background_help_lines = new Tool ("background_help_lines", t_("Show guidelines at top and bottom margin"));
926 background_help_lines.select_action.connect ((self) => {
927 Glyph g = MainWindow.get_current_glyph ();
928 bool v = !g.get_margin_lines_visible ();
929 g.set_margin_lines_visible (v);
930 self.set_selected (v);
931 GlyphCanvas.redraw ();
932
933 if (v && !help_lines.is_selected ()) {
934 MainWindow.get_toolbox ().select_tool (help_lines);
935 }
936 });
937 selected_line = GlyphCanvas.get_current_glyph ().get_margin_lines_visible ();
938 background_help_lines.set_selected (selected_line);
939 guideline_tools.add_tool (background_help_lines);
940
941 Tool new_grid = new GridTool ("show_grid");
942 guideline_tools.add_tool (new_grid);
943
944 // Zoom tools
945 zoom_bar = new ZoomBar ();
946 zoom_bar.new_zoom.connect ((z) => {
947 Glyph g = MainWindow.get_current_glyph ();
948 double zoom = 20 * z + 1;
949 double xc, yc, nxc, nyc;
950
951 xc = Glyph.path_coordinate_x (Glyph.xc ());
952 yc = Glyph.path_coordinate_y (Glyph.yc ());
953
954 g.set_zoom (zoom);
955
956 nxc = Glyph.path_coordinate_x (Glyph.xc ());
957 nyc = Glyph.path_coordinate_y (Glyph.yc ());
958
959 g.view_offset_x -= nxc - xc;
960 g.view_offset_y += nyc - yc;
961
962 GlyphCanvas.redraw ();
963 });
964 zoombar_tool.add_tool (zoom_bar);
965
966 Tool reset_zoom = new Tool ("zoom_1_1", t_("Zoom Out More"));
967 reset_zoom.select_action.connect ((self) => {
968 zoom_tool.store_current_view ();
969 glyph_canvas.get_current_display ().reset_zoom ();
970 glyph_canvas.redraw_area(0, 0, GlyphCanvas.allocation.width, GlyphCanvas.allocation.height);
971 });
972 view_tools.add_tool (reset_zoom);
973 reset_zoom.set_tool_visibility (false);
974
975 Tool full_glyph = new Tool ("full_glyph", t_("Show full glyph"));
976 full_glyph.select_action.connect((self) => {
977 zoom_tool.store_current_view ();
978 zoom_tool.zoom_full_glyph ();
979 });
980 view_tools.add_tool (full_glyph);
981
982 Tool zoom_boundaries = new Tool ("zoom_boundaries", t_("Fit in view"));
983 zoom_boundaries.select_action.connect((self) => {
984 zoom_tool.store_current_view ();
985 glyph_canvas.get_current_display ().zoom_max ();
986 });
987 view_tools.add_tool (zoom_boundaries);
988
989 Tool zoom_bg = new Tool ("zoom_background_image", t_("Zoom in on background image"));
990 zoom_bg.select_action.connect((self) => {
991 if (MainWindow.get_current_glyph ().get_background_image () != null) {
992 zoom_tool.store_current_view ();
993 ZoomTool.zoom_full_background_image ();
994 glyph_canvas.redraw_area(0, 0, GlyphCanvas.allocation.width, GlyphCanvas.allocation.height);
995 }
996 });
997 view_tools.add_tool (zoom_bg);
998
999 Tool zoom_prev = new Tool ("prev", t_("Previous view"));
1000 zoom_prev.select_action.connect((self) => {
1001 zoom_tool.previous_view ();
1002 });
1003 view_tools.add_tool (zoom_prev);
1004
1005 Tool zoom_next = new Tool ("next", t_("Next view"));
1006 zoom_next.select_action.connect((self) => {
1007 zoom_tool.next_view ();
1008 });
1009 view_tools.add_tool (zoom_next);
1010 zoom_next.set_tool_visibility (false);
1011
1012 // shape tools
1013 circle = new CircleTool ("circle");
1014 circle.select_action.connect ((self) => {
1015 update_drawing_and_background_tools (self);
1016 });
1017 shape_tools.add_tool (circle);
1018
1019 rectangle = new RectangleTool ("rectangle");
1020 rectangle.select_action.connect ((self) => {
1021 update_drawing_and_background_tools (self);
1022 });
1023 shape_tools.add_tool (rectangle);
1024
1025 add_expander (font_name);
1026 add_expander (draw_tools);
1027
1028 if (BirdFont.android) {
1029 add_expander (key_tools);
1030 }
1031
1032 add_expander (draw_tool_modifiers);
1033
1034 add_expander (stroke_expander);
1035
1036 add_expander (guideline_tools);
1037 add_expander (grid);
1038 add_expander (zoombar_tool);
1039 add_expander (view_tools);
1040 add_expander (shape_tools);
1041
1042 // Fixa: add_expander (trace);
1043 if (BirdFont.has_argument ("--test")) {
1044 add_expander (test_tools);
1045 }
1046
1047 draw_tools.set_persistent (true);
1048 draw_tools.set_unique (false);
1049
1050 stroke_expander.set_persistent (true);
1051 stroke_expander.set_unique (false);
1052
1053 key_tools.set_persistent (false);
1054 key_tools.set_unique (false);
1055
1056 draw_tool_modifiers.set_persistent (true);
1057 draw_tool_modifiers.set_unique (false);
1058
1059 test_tools.set_persistent (true);
1060
1061 guideline_tools.set_persistent (true);
1062 guideline_tools.set_unique (false);
1063
1064 grid.set_persistent (true);
1065 grid.set_unique (true);
1066
1067 shape_tools.set_persistent (true);
1068 shape_tools.set_unique (true);
1069
1070 // let these tools progagate events even when other tools are selected
1071 foreach (Tool t in draw_tools.tool) {
1072 t.editor_events = true;
1073 }
1074
1075 foreach (Tool t in shape_tools.tool) {
1076 t.editor_events = true;
1077 t.persistent = true;
1078 }
1079
1080 move_background.editor_events = true;
1081 cut_background.editor_events = true;
1082 move_canvas.editor_events = true;
1083
1084 move_background.persistent = true;
1085 cut_background.persistent = true;
1086 move_canvas.persistent = true;
1087
1088 // Default selection
1089 IdleSource idle = new IdleSource ();
1090 idle.set_callback (() => {
1091 Toolbox tb = MainWindow.get_toolbox ();
1092
1093 tb.reset_active_tool ();
1094 update_drawing_and_background_tools (bezier_tool);
1095 tb.select_tool (bezier_tool);
1096 tb.set_current_tool (bezier_tool);
1097
1098 set_point_type_from_preferences ();
1099
1100 if (GlyphCanvas.get_current_glyph ().get_show_help_lines ()) {
1101 help_lines.set_selected (true);
1102 help_lines.set_active (false);
1103 }
1104
1105 add_new_grid (1);
1106 add_new_grid (2);
1107 add_new_grid (4);
1108
1109 MainWindow.get_toolbox ().move (0, 0);
1110
1111 return false;
1112 });
1113 idle.attach (null);
1114
1115 // update selelction when the user switches tab
1116 MainWindow.get_tab_bar ().signal_tab_selected.connect((tab) => {
1117 Glyph glyph;
1118
1119 if (tab.get_display () is Glyph) {
1120 glyph = (Glyph) tab.get_display ();
1121 show_bg.set_selected (glyph.get_background_visible ());
1122 update_line_selection (glyph);
1123 }
1124 });
1125 }
1126
1127 public static void update_stroke_settings () {
1128 bool stroke = false;
1129 Glyph g = MainWindow.get_current_glyph ();
1130
1131 foreach (Path p in g.active_paths) {
1132 if (p.stroke > 0) {
1133 stroke = true;
1134 }
1135 }
1136
1137 add_stroke.selected = stroke;
1138 StrokeTool.add_stroke = stroke;
1139 // FIXME: This is slow: Toolbox.redraw_tool_box ();
1140 }
1141
1142 void auto_trace_background () {
1143 Glyph g = MainWindow.get_current_glyph ();
1144 BackgroundImage? bg = g.get_background_image ();
1145 BackgroundImage b;
1146 PathList pl;
1147
1148 if (bg != null) {
1149 b = (!) bg;
1150 pl = b.autotrace ();
1151 foreach (Path p in pl.paths) {
1152 g.add_path (p);
1153 }
1154 }
1155 }
1156
1157 void update_line_selection (Glyph glyph) {
1158 help_lines.set_selected (glyph.get_show_help_lines ());
1159 xheight_help_lines.set_selected (glyph.get_xheight_lines_visible ());
1160 background_help_lines.set_selected (glyph.get_margin_lines_visible ());
1161 }
1162
1163 public static void set_point_type_from_preferences () {
1164 string type = Preferences.get ("point_type");
1165 if (type == "double_points") {
1166 Toolbox.select_tool_by_name ("double_points");
1167 } else if (type == "quadratic_points") {
1168 Toolbox.select_tool_by_name ("quadratic_points");
1169 } if (type == "cubic_points") {
1170 Toolbox.select_tool_by_name ("cubic_points");
1171 }
1172 }
1173
1174 void hide_all_modifiers () {
1175 x_coordinate.set_tool_visibility (false);
1176 y_coordinate.set_tool_visibility (false);
1177 rotation.set_tool_visibility (false);
1178 width.set_tool_visibility (false);
1179 height.set_tool_visibility (false);
1180 skew.set_tool_visibility (false);
1181 reverse_path_tool.set_tool_visibility (false);
1182 move_layer.set_tool_visibility (false);
1183 flip_vertical.set_tool_visibility (false);
1184 flip_horizontal.set_tool_visibility (false);
1185
1186 tie_handles.set_tool_visibility (false);
1187 reflect_handle.set_tool_visibility (false);
1188 create_line.set_tool_visibility (false);
1189 close_path_tool.set_tool_visibility (false);
1190
1191 quadratic_points.set_tool_visibility (false);
1192 cubic_points.set_tool_visibility (false);
1193 double_points.set_tool_visibility (false);
1194 convert_points.set_tool_visibility (false);
1195
1196 cut_background.set_tool_visibility (false);
1197 show_bg.set_tool_visibility (false);
1198 bg_selection.set_tool_visibility (false);
1199 background_threshold.set_tool_visibility (false);
1200 background_scale.set_tool_visibility (false);
1201 high_contrast_background.set_tool_visibility (false);
1202 auto_trace_resolution.set_tool_visibility (false);
1203 auto_trace.set_tool_visibility (false);
1204 auto_trace_simplify.set_tool_visibility (false);
1205 delete_background.set_tool_visibility (false);
1206 }
1207
1208 void show_background_tool_modifiers () {
1209 draw_tool_modifiers.set_headline (t_("Background Tools"));
1210
1211 cut_background.set_tool_visibility (true);
1212 show_bg.set_tool_visibility (true);
1213 bg_selection.set_tool_visibility (true);
1214 background_threshold.set_tool_visibility (true);
1215 background_scale.set_tool_visibility (true);
1216 high_contrast_background.set_tool_visibility (true);
1217 auto_trace_resolution.set_tool_visibility (true);
1218 auto_trace.set_tool_visibility (true);
1219 auto_trace_simplify.set_tool_visibility (true);
1220 delete_background.set_tool_visibility (true);
1221 }
1222
1223 void show_point_tool_modifiers () {
1224 draw_tool_modifiers.set_headline (t_("Control Points"));
1225
1226 tie_handles.set_tool_visibility (true);
1227 reflect_handle.set_tool_visibility (true);
1228 create_line.set_tool_visibility (true);
1229 close_path_tool.set_tool_visibility (true);
1230
1231 quadratic_points.set_tool_visibility (true);
1232 cubic_points.set_tool_visibility (true);
1233 double_points.set_tool_visibility (true);
1234 convert_points.set_tool_visibility (true);
1235
1236 reverse_path_tool.set_tool_visibility (true);
1237 }
1238
1239 void show_object_tool_modifiers () {
1240 draw_tool_modifiers.set_headline (t_("Object Tools"));
1241
1242 x_coordinate.set_tool_visibility (true);
1243 y_coordinate.set_tool_visibility (true);
1244 rotation.set_tool_visibility (true);
1245 width.set_tool_visibility (true);
1246 height.set_tool_visibility (true);
1247 skew.set_tool_visibility (true);
1248
1249 reverse_path_tool.set_tool_visibility (true);
1250 move_layer.set_tool_visibility (true);
1251 flip_vertical.set_tool_visibility (true);
1252 flip_horizontal.set_tool_visibility (true);
1253 }
1254
1255 public void update_drawing_and_background_tools (Tool current_tool) {
1256 IdleSource idle = new IdleSource ();
1257
1258 idle.set_callback (() => {
1259 Glyph g = MainWindow.get_current_glyph ();
1260
1261 hide_all_modifiers ();
1262
1263 move_background.set_selected (false);
1264 cut_background.set_selected (false);
1265
1266 bezier_tool.set_selected (false);
1267 pen_tool.set_selected (false);
1268 point_tool.set_selected (false);
1269 zoom_tool.set_selected (false);
1270 move_tool.set_selected (false);
1271 resize_tool.set_selected (false);
1272 track_tool.set_selected (false);
1273 move_canvas.set_selected (false);
1274 delete_background.set_selected (false);
1275
1276 show_bg.set_selected (g.get_background_visible ());
1277 show_bg.set_active (false);
1278 bg_selection.set_selected (false);
1279 background_scale.set_active (false);
1280
1281 rectangle.set_selected (false);
1282 circle.set_selected (false);
1283
1284 reverse_path_tool.set_selected (false);
1285 move_layer.set_selected (false);
1286 flip_vertical.set_selected (false);
1287 flip_horizontal.set_selected (false);
1288
1289 current_tool.set_selected (true);
1290
1291 if (resize_tool.is_selected () || move_tool.is_selected ()) {
1292 show_object_tool_modifiers ();
1293 } else if (bezier_tool.is_selected ()
1294 || pen_tool.is_selected ()
1295 || point_tool.is_selected ()
1296 || track_tool.is_selected ()) {
1297 show_point_tool_modifiers ();
1298 } else if (move_background.is_selected ()
1299 || cut_background.is_selected ()
1300 || show_bg.is_selected ()
1301 || high_contrast_background.is_selected ()
1302 || auto_trace.is_selected ()) {
1303 show_background_tool_modifiers ();
1304 }
1305
1306 MainWindow.get_toolbox ().update_expanders ();
1307 Toolbox.redraw_tool_box ();
1308
1309 return false;
1310 });
1311
1312 idle.attach (null);
1313 }
1314
1315 void update_type_selection () {
1316 IdleSource idle = new IdleSource ();
1317
1318 // Do this in idle, after the animation
1319 idle.set_callback (() => {
1320 Font f = BirdFont.get_current_font ();
1321
1322 quadratic_points.set_selected (false);
1323 cubic_points.set_selected (false);
1324 double_points.set_selected (false);
1325
1326 switch (point_type) {
1327 case PointType.QUADRATIC:
1328 quadratic_points.set_selected (true);
1329 f.settings.set_setting ("point_type", "quadratic");
1330 break;
1331 case PointType.CUBIC:
1332 cubic_points.set_selected (true);
1333 f.settings.set_setting ("point_type", "cubic");
1334 break;
1335 case PointType.DOUBLE_CURVE:
1336 double_points.set_selected (true);
1337 f.settings.set_setting ("point_type", "double_curve");
1338 break;
1339 }
1340
1341 convert_points.set_selected (false);
1342
1343 Toolbox.redraw_tool_box ();
1344 return false;
1345 });
1346
1347 idle.attach (null);
1348 }
1349
1350 public static void set_default_point_type (string type) {
1351 if (type == "quadratic") {
1352 quadratic_points.set_selected (true);
1353 point_type = PointType.QUADRATIC;
1354 } else if (type == "cubic") {
1355 cubic_points.set_selected (true);
1356 point_type = PointType.CUBIC;
1357 } else if (type == "double_curve") {
1358 double_points.set_selected (true);
1359 point_type = PointType.DOUBLE_CURVE;
1360 }
1361 }
1362
1363 public override Gee.ArrayList<Expander> get_expanders () {
1364 return expanders;
1365 }
1366
1367 /** Insert new points of this type. */
1368 public static PointType get_selected_point_type () {
1369 return point_type;
1370 }
1371
1372 public void remove_all_grid_buttons () {
1373 grid_expander.tool.clear ();
1374
1375 GridTool.sizes.clear ();
1376
1377 MainWindow.get_toolbox ().update_expanders ();
1378 MainWindow.get_toolbox ().redraw (0, 0, Toolbox.allocation_width, Toolbox.allocation_height);
1379 }
1380
1381 public void parse_grid (string spin_button_value) {
1382 SpinButton sb = add_new_grid ();
1383 sb.set_value (spin_button_value);
1384 MainWindow.get_toolbox ().select_tool (sb);
1385 }
1386
1387 public static SpinButton add_new_grid (double size = 2) {
1388 SpinButton grid_width = new SpinButton ("grid_width", t_("Set size for grid"));
1389 Toolbox tb = MainWindow.get_toolbox ();
1390
1391 grid_width.new_value_action.connect((self) => {
1392 grid_width.select_action (grid_width);
1393 });
1394
1395 grid_width.select_action.connect((self) => {
1396 SpinButton sb = (SpinButton) self;
1397 GridTool.set_grid_width (sb.get_value ());
1398 GlyphCanvas.redraw ();
1399 });
1400
1401 grid_expander.add_tool (grid_width);
1402
1403 GridTool.sizes.add (grid_width);
1404
1405 grid_width.set_value_round (size);
1406
1407 tb.update_expanders ();
1408
1409 tb.redraw (0, 0, Toolbox.allocation_width, Toolbox.allocation_height);
1410
1411 tb.select_tool (grid_width);
1412 grid_width.set_active (false);
1413
1414 return grid_width;
1415 }
1416
1417 public void remove_current_grid () {
1418 Tool grid_width;
1419 Toolbox tb = MainWindow.get_toolbox ();
1420
1421 foreach (Tool t in grid_expander.tool) {
1422 if (t.is_selected () && t is SpinButton) {
1423 GridTool.sizes.remove ((SpinButton)t);
1424 grid_expander.tool.remove (t);
1425 break;
1426 }
1427 }
1428
1429 if (grid_expander.tool.size > 0) {
1430 grid_width = grid_expander.tool.get (grid_expander.tool.size - 1);
1431 tb.select_tool (grid_width);
1432 grid_width.set_active (false);
1433 }
1434
1435 MainWindow.get_toolbox ().update_expanders ();
1436 tb.redraw (0, 0, Toolbox.allocation_width, Toolbox.allocation_height);
1437 }
1438
1439 private void add_expander (Expander e) {
1440 expanders.add (e);
1441 }
1442
1443 public override Gee.ArrayList<string> get_displays () {
1444 Gee.ArrayList<string> d = new Gee.ArrayList<string> ();
1445 d.add ("Glyph");
1446 return d;
1447 }
1448 }
1449
1450 }
1451