.
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 Expander : GLib.Object {
21
22 private static const double HEADLINE_MARGIN = 4;
23
24 public double x = 7;
25 public double y = 5;
26 public double scroll = 0;
27
28 public double w = 6;
29 public double h = 5;
30
31 public double margin = 0;
32
33 protected double opacity = 0;
34
35 protected bool active = false;
36
37 public Gee.ArrayList<Tool> tool;
38
39 bool persist = false;
40 bool unique = false;
41
42 double content_height = 0;
43
44 string? headline;
45 Text title;
46
47 public bool visible = true;
48 Surface? cached = null;
49
50 public Expander (string? headline = null) {
51 this.headline = headline;
52
53 title = new Text ();
54
55 if (headline != null) {
56 title.set_text ((!) headline);
57 }
58
59 tool = new Gee.ArrayList<Tool> ();
60 }
61
62 public void clear_cache () {
63 cached = null;
64 }
65
66 public void set_headline (string? h) {
67 headline = h;
68 }
69
70 public double get_content_height () {
71 return content_height;
72 }
73
74 /** Returns true if tools can be used with the current canvas after
75 * they have been selectes and false if they are a commands to be executed.
76 */
77 public bool is_persistent () {
78 return persist;
79 }
80
81 /** Returns true if all other tools in thid expander should be deselected
82 * when a tool is selected.
83 */
84 public bool is_unique () {
85 return unique;
86 }
87
88 public void set_persistent (bool p) {
89 persist = p;
90 }
91
92 public void set_unique (bool u) {
93 unique = u;
94 }
95
96 public void update_tool_position () {
97 double scale = Toolbox.get_scale ();
98 double margin_small = 5 * scale;
99 double xt = x;
100 double yt = y + margin_small; // + scroll
101 bool new_row = false;
102 bool has_visible_tools = false;
103 Tool previous;
104 bool first_row;
105
106 foreach (Tool t in tool) {
107 if (t.tool_is_visible ()) {
108 has_visible_tools = true;
109 break;
110 }
111 }
112
113 if (!has_visible_tools) {
114 content_height = 0;
115 return;
116 }
117
118 foreach (Tool t in tool) {
119 if (t is ZoomBar) {
120 t.w = Toolbox.allocation_width * scale;
121 t.h = 10 * scale; // 7
122 } else if (t is LabelTool) {
123 t.w = Toolbox.allocation_width * scale;
124 t.h = 22 * scale;
125 } else if (t is FontName) {
126 t.w = Toolbox.allocation_width * scale;
127 t.h = 20 * scale;
128 } else if (t is KerningRange) {
129 t.w = Toolbox.allocation_width * scale;
130 t.h = 17 * scale;
131 } else if (t is LayerLabel) {
132 t.w = Toolbox.allocation_width * scale;
133 t.h = 21 * scale;
134 } else if (t is ColorPicker) {
135 t.w = Toolbox.allocation_width * scale;
136 t.h = 5 * ((ColorPicker) t).bar_height;
137 } else {
138 t.w = 33 * scale;
139 t.h = (33 / 1.11) * scale;
140 }
141 }
142
143 if (tool.size > 0) {
144 content_height = tool.get (0).h + margin_small;
145 } else {
146 content_height = 0;
147 }
148
149 if (headline != null && tool.size > 0) {
150 yt += 17 * scale + HEADLINE_MARGIN;
151 content_height += 17 * scale + HEADLINE_MARGIN;
152 }
153
154 if (tool.size > 0) {
155 previous = tool.get (0);
156 first_row = true;
157 foreach (Tool t in tool) {
158 if (t.tool_is_visible ()) {
159 new_row = xt + t.w > Toolbox.allocation_width - 7 * scale;
160
161 if (t is ZoomBar) {
162 t.x = xt;
163 t.y = yt;
164 yt += t.h + 7 * scale;
165 previous = t;
166 continue;
167 }
168
169 if (previous is ZoomBar) {
170 content_height += t.h;
171 }
172
173 if (new_row && !first_row) {
174 content_height += previous.h;
175 xt = x;
176 yt += previous.h;
177
178 if (!(t is LabelTool) && !(previous is LayerLabel)) {
179 yt += 7 * scale;
180 }
181
182 if (!(previous is LayerLabel)) {
183 content_height += margin_small;
184 }
185 }
186
187 t.x = xt;
188 t.y = yt;
189
190 xt += t.w + 7 * scale;
191
192 if (previous is ZoomBar) {
193 content_height += 7 * scale;
194 }
195
196 previous = t;
197 first_row = false;
198 }
199 }
200
201 content_height += 5 * scale;
202 }
203
204 if (unlikely (content_height < 0)) {
205 warning (@"content_height < 0");
206 }
207 }
208
209 public void set_scroll (double scroll) {
210 this.scroll = scroll;
211 }
212
213 public void set_offset (double ty) {
214 y = ty;
215 update_tool_position ();
216 }
217
218 public void redraw () {
219 cached = null;
220 Toolbox.redraw_tool_box ();
221 }
222
223 public void add_tool (Tool t, int position = -1) {
224 if (position < 0) {
225 tool.add (t);
226 } else {
227 return_if_fail (position <= tool.size);
228 tool.insert (position, t);
229 }
230
231 t.redraw_tool.connect (() => {
232 cached = null;
233 });
234
235 update_tool_position ();
236
237 t.select_action.connect ((selected) => {
238 MainWindow.get_toolbox ().redraw ((int) x, (int) y, (int) w + 300, (int) (h + margin));
239
240 if (is_unique ()) {
241 foreach (var deselected in tool) {
242 if (selected.get_id () != deselected.get_id ()) {
243 deselected.set_selected (false);
244 }
245 }
246 }
247
248 if (!selected.new_selection && selected.persistent) {
249 if (is_persistent ()) {
250 selected.set_selected (true);
251 } else {
252 selected.set_selected (false);
253 }
254 }
255
256 selected.new_selection = false;
257 });
258 }
259
260 public bool is_over (double xp, double yp) {
261 double yt = y + scroll + 2;
262 return yt - 7 <= yp <= yt + 7 && xp < 17;
263 }
264
265 public bool set_active (bool a) {
266 bool r = (active != a);
267 opacity = (a) ? 1 : 0;
268 active = a;
269 return r;
270 }
271
272 public void draw (Context cr) {
273 Surface cache;
274
275 if (unlikely (cached == null)) {
276 Context cc;
277 double text_height = 17 * Toolbox.get_scale ();
278 double offset_y = 0;
279
280 cache = Screen.create_background_surface (Toolbox.allocation_width, (int) (h + content_height));
281 cc = new Context (cache);
282 cc.scale(Screen.get_scale(), Screen.get_scale());
283
284 if (tool.size > 0 && headline != null) {
285 Theme.text_color (title, "Text Tool Box");
286 title.set_font_size (text_height);
287 title.draw_at_top (cc, x, 0);
288 offset_y = text_height + HEADLINE_MARGIN;
289 }
290
291 draw_content (cc, offset_y);
292 cached = (!) cache;
293 }
294
295 if (cached != null) {
296 cache = (!) cached;
297 Screen.paint_background_surface (cr, cache, 0, (int) (y + scroll));
298 }
299 }
300
301 public void draw_content (Context cr, double text_end) {
302 double offset_y = 0;
303 double offset_x = 0;
304
305 update_tool_position ();
306
307 if (tool.size > 0) {
308 offset_x = tool.get (0).x;
309 offset_y = tool.get (0).y - text_end;
310 }
311
312 cr.save ();
313 foreach (Tool t in tool) {
314 if (t.tool_is_visible ()) {
315 t.draw_tool (cr, offset_x - x, offset_y);
316 }
317 }
318 cr.restore ();
319 }
320
321 }
322
323 }
324