.
1 /*
2 Copyright (C) 2012 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 Toolbox : GLib.Object {
21 public static ToolCollection current_set;
22
23 public static DrawingTools drawing_tools;
24 public static KerningTools kerning_tools;
25 public static PreviewTools preview_tools;
26 public static OverviewTools overview_tools;
27 public static BackgroundTools background_tools;
28 public static HiddenTools hidden_tools;
29 public static SpacingTools spacing_tools;
30
31 Tool current_tool;
32
33 public Tool press_tool;
34
35 public signal void redraw (int x, int y, int w, int h);
36
37 public static int allocation_width = 0;
38 public static int allocation_height = 0;
39
40 /** Scrolling with scroll wheel */
41 bool scrolling_toolbox = false;
42
43 /** Scroll with touch pad. */
44 bool scrolling_touch = false;
45 double scroll_y = 0;
46
47 public List<ToolCollection> tool_sets = new List<ToolCollection> ();
48
49 static double scale = 1;
50
51 string? tool_tip = null;
52 double tool_tip_x = 0;
53 double tool_tip_y = 0;
54
55 public Toolbox (GlyphCanvas glyph_canvas, TabBar tab_bar) {
56 current_tool = new Tool ("no_icon");
57 press_tool = new Tool (null);
58
59 drawing_tools = new DrawingTools (glyph_canvas);
60 kerning_tools = new KerningTools ();
61 preview_tools = new PreviewTools ();
62 overview_tools = new OverviewTools ();
63 background_tools = new BackgroundTools ();
64 hidden_tools = new HiddenTools ();
65 spacing_tools = new SpacingTools ();
66
67 tool_sets.append (drawing_tools);
68 tool_sets.append (kerning_tools);
69 tool_sets.append (preview_tools);
70 tool_sets.append (overview_tools);
71 tool_sets.append (background_tools);
72 tool_sets.append (hidden_tools); // tools without a button
73
74 current_set = drawing_tools;
75
76 tab_bar.signal_tab_selected.connect ((tab) => {
77 string tab_name = tab.get_display ().get_name ();
78 set_toolbox_from_tab (tab_name, tab);
79 });
80
81 update_expanders ();
82 }
83
84 public static void set_toolbox_from_tab (string tab_name, Tab? t = null) {
85 if (tab_name == "Spacing") {
86 current_set = (ToolCollection) spacing_tools;
87 } else if (tab_name == "Kerning") {
88 current_set = (ToolCollection) kerning_tools;
89 } else if (tab_name == "Preview") {
90 current_set = (ToolCollection) preview_tools;
91 } else if (tab_name == "Overview") {
92 current_set = (ToolCollection) overview_tools;
93 } else if (tab_name == "Backgrounds") {
94 current_set = (ToolCollection) background_tools;
95 } else if (t != null && ((!) t).get_display () is Glyph) {
96 current_set = (ToolCollection) drawing_tools;
97 } else {
98 current_set = new EmptySet ();
99 }
100
101 MainWindow.get_toolbox ().update_expanders ();
102 redraw_tool_box ();
103 }
104
105 public static Tool get_move_tool () {
106 return DrawingTools.move_tool;
107 }
108
109 public static void set_object_stroke (double width) {
110 DrawingTools.object_stroke.set_value_round (width);
111 redraw_tool_box ();
112 }
113
114 public static void set_allocation (int w, int h) {
115 if (w != allocation_width || allocation_height != h) {
116 allocation_width = w;
117 allocation_height = h;
118
119 scale = Toolbox.allocation_width / 160.0;
120
121 Toolbox.redraw_tool_box ();
122 }
123 }
124
125 public void press (uint button, double x, double y) {
126 if (MenuTab.suppress_event) {
127 warn_if_test ("Event suppressed");
128 return;
129 }
130
131 foreach (Expander exp in current_set.get_expanders ()) {
132 foreach (Tool t in exp.tool) {
133 if (t.tool_is_visible () && t.is_over (x, y)) {
134 t.panel_press_action (t, button, x, y);
135 press_tool = t;
136 }
137 }
138 }
139
140 scrolling_touch = true;
141 scroll_y = y;
142 }
143
144 public void release (uint button, double x, double y) {
145 bool active;
146
147 if (MenuTab.suppress_event) {
148 warn_if_test ("Event suppressed");
149 return;
150 }
151
152 foreach (Expander exp in current_set.get_expanders ()) {
153 foreach (Tool t in exp.tool) {
154 if (t.tool_is_visible ()) {
155 active = t.is_over (x, y);
156
157 if (active) {
158 if (press_tool == t) {
159 select_tool (t);
160 }
161 }
162
163 t.panel_release_action (t, button, x, y);
164 }
165 }
166 }
167
168 scrolling_touch = false;
169 }
170
171 public void scroll_up (double x, double y) {
172 bool action = false;
173
174 if (MenuTab.suppress_event) {
175 warn_if_test ("Event suppressed");
176 return;
177 }
178
179 if (!scrolling_toolbox) {
180 foreach (Expander exp in current_set.get_expanders ()) {
181 foreach (Tool t in exp.tool) {
182 if (t.tool_is_visible () && t.is_over (x, y)) {
183 action = t.scroll_wheel_up_action (t);
184 press_tool = t;
185 }
186 }
187 }
188 }
189
190 if (!action) {
191 scroll_current_set (35);
192 }
193
194 redraw_tool_box ();
195 }
196
197 void scroll_current_set (double d) {
198 current_set.scroll += d;
199
200 if (current_set.scroll > 0) {
201 current_set.scroll = 0;
202 }
203
204 if (current_set.content_height < allocation_height) {
205 current_set.scroll = 0;
206 } else if (current_set.content_height + current_set.scroll < allocation_height) {
207 current_set.scroll = allocation_height - current_set.content_height;
208 }
209
210 update_expanders ();
211 suppress_scroll ();
212 }
213
214 public void scroll_down (double x, double y) {
215 bool action = false;
216
217 if (!scrolling_toolbox) {
218 foreach (Expander exp in current_set.get_expanders ()) {
219 foreach (Tool t in exp.tool) {
220 if (t.tool_is_visible () && t.is_over (x, y)) {
221 action = t.scroll_wheel_down_action (t);
222 press_tool = t;
223 }
224 }
225 }
226 }
227
228 if (!action) {
229 scroll_current_set (-35);
230 }
231
232 redraw_tool_box ();
233 }
234
235 void suppress_scroll () {
236 scrolling_toolbox = true;
237
238 Timeout.add (2000, () => {
239 scrolling_toolbox = false;
240 return false;
241 });
242 }
243
244 public void move (double x, double y) {
245 bool update;
246 bool a;
247 bool consumed = false;
248 bool active;
249
250 foreach (Expander exp in current_set.get_expanders ()) {
251 a = exp.is_over (x, y);
252 update = exp.set_active (a);
253
254 if (update) {
255 redraw ((int) exp.x - 10, (int) exp.y - 10, (int) (exp.x + exp.w + 10), (int) (exp.y + exp.h + 10));
256 }
257
258
259 foreach (Tool t in exp.tool) {
260 if (t.tool_is_visible ()) {
261 active = t.is_over (x, y);
262
263 if (!active && t.is_active ()) {
264 t.move_out_action (t);
265 }
266
267 update = t.set_active (active);
268
269 if (update) {
270 redraw (0, 0, allocation_width, allocation_height);
271 }
272
273 if (t.panel_move_action (t, x, y)) {
274 consumed = true;
275 }
276 }
277 }
278 }
279
280 if (scrolling_touch && !consumed && BirdFont.android) {
281 scroll_current_set (y - scroll_y);
282 scroll_y = y;
283 redraw_tool_box ();
284 }
285 }
286
287 public static void redraw_tool_box () {
288 if (MenuTab.suppress_event) {
289 warn_if_test ("Don't redraw toolbox when background thread is running.");
290 return;
291 }
292
293 Toolbox t = MainWindow.get_toolbox ();
294 if (!is_null (t)) {
295 t.redraw (0, 0, allocation_width, allocation_height);
296 }
297 }
298
299 public void reset_active_tool () {
300 foreach (Expander exp in current_set.get_expanders ()) {
301 foreach (Tool t in exp.tool) {
302 t.set_active (false);
303 }
304 }
305 }
306
307 public Tool? get_active_tool () {
308 foreach (Expander exp in current_set.get_expanders ()) {
309 foreach (Tool t in exp.tool) {
310 if (t.is_active ()) {
311 return t;
312 }
313 }
314 }
315
316 return null;
317 }
318
319 public void set_current_tool (Tool tool) {
320 if (tool.editor_events) {
321 current_tool = tool;
322 }
323 }
324
325 public Tool get_current_tool () {
326 return current_tool;
327 }
328
329 public void select_tool (Tool tool) {
330 bool update;
331
332 foreach (Expander exp in current_set.get_expanders ()) {
333 foreach (Tool t in exp.tool) {
334 if (tool.get_id () == t.get_id ()) {
335 if (!t.tool_is_visible ()) {
336 warning ("Tool is hidden");
337 } else {
338 update = false;
339
340 update = tool.set_selected (true);
341 if (tool.persistent) {
342 update = tool.set_active (true);
343 }
344
345 tool.select_action (tool);
346
347 if (update) {
348 redraw ((int) exp.x - 10, (int) exp.y - 10, allocation_width, (int) (allocation_height - exp.y + 10));
349 }
350
351 set_current_tool (tool);
352 }
353 }
354 }
355
356 }
357 }
358
359 public Tool get_tool (string name) {
360 foreach (ToolCollection tc in tool_sets) {
361 foreach (Expander e in tc.get_expanders ()) {
362 foreach (Tool t in e.tool) {
363 if (t.get_name () == name) {
364 return t;
365 }
366 }
367 }
368 }
369
370 warning ("No tool found for name \"%s\".\n", name);
371
372 return new Tool ("no_icon");
373 }
374
375 public static void set_tool_visible (string name, bool visible) {
376 Toolbox tb = MainWindow.get_toolbox ();
377 Tool t = tb.get_tool (name);
378 t.set_tool_visibility (visible);
379 tb.update_expanders ();
380 Toolbox.redraw_tool_box ();
381 }
382
383 public static void select_tool_by_name (string name) {
384 Toolbox b = MainWindow.get_toolbox ();
385
386 if (is_null (b)) {
387 return;
388 }
389
390 b.select_tool (b.get_tool (name));
391 }
392
393 public static void set_scale (double s) {
394 scale = s;
395 }
396
397 public static double get_scale () {
398 return scale;
399 }
400
401 public void set_default_tool_size () {
402 foreach (ToolCollection t in tool_sets) {
403 foreach (Expander e in t.get_expanders ()) {
404 e.update_tool_position ();
405 }
406 }
407 }
408
409 public void update_expanders () {
410 double pos;
411
412 foreach (Expander e in current_set.get_expanders ()) {
413 e.set_scroll (current_set.scroll);
414 }
415
416 pos = 4 * get_scale ();
417 foreach (Expander e in current_set.get_expanders ()) {
418 e.set_offset (pos);
419
420 pos += e.get_content_height () + 4 * get_scale ();
421
422 current_set.content_height = pos;
423
424 if (BirdFont.android) {
425 current_set.content_height *= 1.15;
426 }
427 }
428
429 foreach (Expander e in current_set.get_expanders ()) {
430 e.set_active (false);
431 }
432 }
433
434 private void draw_expanders (int w, int h, Context cr) {
435 foreach (Expander e in current_set.get_expanders ()) {
436 e.draw (w, h, cr);
437 e.draw_content (w, h, cr);
438 }
439 }
440
441 public void draw (int w, int h, Context cr) {
442 EmptySet empty_set;
443 ImageSurface bg;
444 double scale_x, scale_y, scale;
445
446 if (current_set is EmptySet) {
447 empty_set = (EmptySet) current_set;
448
449 if (empty_set.background != null) {
450 bg = (!) empty_set.background;
451
452 scale_x = (double) allocation_width / bg.get_width ();
453 scale_y = (double) allocation_height / bg.get_height ();
454
455 scale = fmax (scale_x, scale_y);
456
457 cr.save ();
458 cr.scale (scale, scale);
459 cr.set_source_surface (bg, 0, 0);
460 cr.paint ();
461 cr.restore ();
462
463 draw_expanders (w, h, cr);
464 }
465 } else {
466 cr.save ();
467
468 cr.rectangle (0, 0, w, h);
469 cr.set_line_width (0);
470 Theme.color (cr, "Background 4");
471 cr.fill ();
472
473 draw_expanders (w, h, cr);
474
475 cr.restore ();
476
477 draw_tool_tip (cr);
478 }
479 }
480
481 private void draw_tool_tip (Context cr) {
482 TextArea t;
483
484 if (tool_tip != null && tool_tip != "") {
485 t = new TextArea (17 * get_scale ());
486 t.allocation = new WidgetAllocation.for_area (0, 0, allocation_width, allocation_height);
487 t.set_editable (false);
488 t.set_text ((!) tool_tip);
489 t.width = allocation_width - 20 * get_scale ();
490 t.min_height = 17 * get_scale ();
491 t.height = 17 * get_scale ();
492
493 t.layout ();
494
495 t.widget_x = 10 * get_scale ();
496 t.widget_y = tool_tip_y - t.height - 5 * get_scale ();
497
498 t.draw (cr);
499 }
500 }
501
502 public void hide_tooltip () {
503 if (tool_tip != null) {
504 tool_tip = null;
505 redraw_tool_box ();
506 }
507 }
508
509 public void show_tooltip (string tool_tip, double x, double y) {
510 if (tool_tip != "") {
511 this.tool_tip = tool_tip;
512 this.tool_tip_x = x;
513 this.tool_tip_y = y;
514
515 redraw_tool_box ();
516 }
517 }
518
519 public class EmptySet : ToolCollection {
520
521 public ImageSurface? background;
522 Gee.ArrayList<Expander> expanders;
523
524 public EmptySet () {
525 background = Icons.get_icon ("corvus_monedula.png");
526 expanders = new Gee.ArrayList<Expander> ();
527 }
528
529 public override Gee.ArrayList<Expander> get_expanders () {
530 return expanders;
531 }
532 }
533
534 }
535
536 }
537