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