.
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
17 namespace BirdFont {
18
19 public class Tool : Widget {
20
21 public double x = 0;
22 public double y = 0;
23 public double w = 33 * Toolbox.get_scale ();
24 public double h = (33 / 1.11) * Toolbox.get_scale ();
25
26 double scale;
27
28 public bool active = false;
29 public bool selected = false;
30
31 Text icon_font;
32 ImageSurface? icon = null;
33
34 public signal void select_action (Tool selected);
35 public signal void deselect_action (Tool selected);
36
37 public signal void press_action (Tool selected, int button, int x, int y);
38 public signal void double_click_action (Tool selected, int button, int x, int y);
39 public signal void move_action (Tool selected, int x, int y);
40 public signal void move_out_action (Tool selected);
41 public signal void release_action (Tool selected, int button, int x, int y);
42
43 /** Returns true if tool is listening for scroll wheel actions. */
44 public signal bool scroll_wheel_up_action (Tool selected);
45 public signal bool scroll_wheel_down_action (Tool selected);
46
47 public signal void key_press_action (Tool selected, uint32 keyval);
48 public signal void key_release_action (Tool selected, uint32 keyval);
49
50 public signal void panel_press_action (Tool selected, uint button, double x, double y);
51 public signal void panel_release_action (Tool selected, uint button, double x, double y);
52
53 /** @return true is event is consumed. */
54 public signal bool panel_move_action (Tool selected, double x, double y);
55
56 public signal void draw_action (Tool selected, Context cr, Glyph glyph);
57
58 public string name = "";
59
60 static int next_id = 1;
61
62 int id;
63
64 public bool new_selection = false;
65
66 bool show_bg = true;
67
68 public string tip = "";
69
70 // keyboard bindings
71 public uint modifier_flag;
72 public unichar key;
73
74 public bool persistent = false;
75 public bool editor_events = false;
76
77 bool waiting_for_tooltip = false;
78 bool showing_this_tooltip = false;
79 static Tool active_tooltip = new Tool ();
80
81 bool visible = true;
82
83 /** Create tool with a certain name and load icon "name".png */
84 public Tool (string? name = null, string tip = "") {
85 this.tip = tip;
86
87 icon_font = new Text ();
88
89 scale = w / 111.0; // scale to 320 dpi
90
91 if (name != null) {
92 set_icon ((!) name);
93 this.name = (!) name;
94 }
95
96 id = next_id;
97 next_id++;
98
99 panel_press_action.connect ((self, button, x, y) => {
100 });
101
102 move_out_action.connect ((self) => {
103 MainWindow.get_toolbox ().hide_tooltip ();
104 active_tooltip.showing_this_tooltip = false;
105 });
106
107 panel_move_action.connect ((self, x, y) => {
108 if (is_active ()) {
109 wait_for_tooltip ();
110 }
111 return false;
112 });
113 }
114
115 public override double get_height () {
116 return 33 * scale;
117 }
118
119 public override double get_width () {
120 return 33 * scale;
121 }
122
123 public void set_tool_visibility (bool v) {
124 visible = v;
125 }
126
127 public bool tool_is_visible () {
128 return visible;
129 }
130
131 void wait_for_tooltip () {
132 TimeoutSource timer_show;
133 int timeout_interval = 1500;
134
135 if (active_tooltip != this) {
136 if (active_tooltip.showing_this_tooltip) {
137 timeout_interval = 1;
138 }
139
140 active_tooltip.showing_this_tooltip = false;
141 showing_this_tooltip = false;
142 active_tooltip = this;
143
144 if (!waiting_for_tooltip) {
145 waiting_for_tooltip = true;
146 timer_show = new TimeoutSource (timeout_interval);
147 timer_show.set_callback (() => {
148 if (tip != "" && active_tooltip.is_active () && !active_tooltip.showing_this_tooltip) {
149 show_tooltip ();
150 }
151 waiting_for_tooltip = false;
152 return waiting_for_tooltip;
153 });
154 timer_show.attach (null);
155 }
156 }
157 }
158
159 public static void show_tooltip () {
160 TimeoutSource timer_hide;
161 Toolbox toolbox;
162
163 toolbox = MainWindow.get_toolbox ();
164
165 // hide tooltip label later
166 if (!active_tooltip.showing_this_tooltip) {
167 timer_hide = new TimeoutSource (1500);
168 timer_hide.set_callback (() => {
169 if (!active_tooltip.is_active ()) {
170 toolbox.hide_tooltip ();
171 active_tooltip.showing_this_tooltip = false;
172 active_tooltip = new Tool ();
173 }
174 return active_tooltip.showing_this_tooltip;
175 });
176 timer_hide.attach (null);
177 }
178
179 active_tooltip.showing_this_tooltip = true;
180
181 toolbox.hide_tooltip ();
182 toolbox.show_tooltip (active_tooltip.tip, (int) active_tooltip.x, (int) active_tooltip.y);
183 }
184
185 public void set_icon (string name) {
186 bool found;
187
188 icon_font = new Text ((!) name);
189 found = icon_font.load_font ("icons.bf");
190 icon_font.use_cache (false);
191 icon_font.set_font_size (35);
192
193 if (!found) {
194 warning ("Icon font for toolbox was not found.");
195 }
196 }
197
198 public bool is_active () {
199 return active;
200 }
201
202 public void set_show_background (bool bg) {
203 show_bg = bg;
204 }
205
206 public int get_id () {
207 return id;
208 }
209
210 public string get_name () {
211 return name;
212 }
213
214 public bool is_selected () {
215 return selected;
216 }
217
218 public string get_tip () {
219 return tip;
220 }
221
222 public new bool is_over (double xp, double yp) {
223 return (x <= xp <= x + w && y <= yp <= y + h);
224 }
225
226 public bool set_selected (bool a) {
227 new_selection = true;
228 selected = a;
229 set_active (a);
230
231 if (!a) {
232 deselect_action (this);
233 }
234
235 return true;
236 }
237
238 /** @return true if this tool changes state, */
239 public bool set_active (bool ac) {
240 bool ret = (active != ac);
241 active = ac;
242 return ret;
243 }
244
245 public override void draw (Context cr) {
246 double xt = x;
247 double yt = y;
248
249 double bgx, bgy;
250 double iconx, icony;
251
252 string border = "Tool Border 3";
253 string background = "Tool Border 3";
254
255 cr.save ();
256
257 bgx = xt;
258 bgy = yt;
259
260 // Button in four states
261 if (selected) {
262 border = "Tool Border 1";
263 background = "Tool Background 1";
264 }
265
266 if (selected && active) {
267 border = "Tool Border 2";
268 background = "Tool Background 2";
269 }
270
271 if (!selected) {
272 border = "Tool Border 3";
273 background = "Tool Background 3";
274 }
275
276 if (!selected && active) {
277 border = "Tool Border 4";
278 background = "Tool Background 4";
279 }
280
281 Theme.color (cr, background);
282 draw_rounded_rectangle (cr, bgx, bgy, 34, 28, 4);
283 cr.fill ();
284
285 cr.set_line_width (1);
286 Theme.color (cr, border);
287 draw_rounded_rectangle (cr, bgx, bgy, 34, 28, 4);
288 cr.stroke ();
289
290 iconx = bgx + w / 2 - icon_font.get_sidebearing_extent () / 2;
291 icony = bgy + h / 2 - icon_font.get_height () / 2;
292
293 Theme.text_color (icon_font, "Button Foreground");
294
295 icon_font.widget_x = iconx;
296 icon_font.widget_y = icony;
297
298 icon_font.draw (cr);
299
300 cr.restore ();
301 }
302
303 /** Run pending events in main loop before continuing. */
304 public static void @yield () {
305 int t = 0;
306 TimeoutSource time = new TimeoutSource (500);
307 bool timeout;
308 unowned MainContext context;
309 bool acquired;
310
311 if (TestBirdFont.is_slow_test ()) {
312 timeout = false;
313
314 time.set_callback (() => {
315 timeout = true;
316 return false;
317 });
318
319 time.attach (null);
320 } else {
321 timeout = true;
322 }
323
324 context = MainContext.default ();
325 acquired = context.acquire ();
326
327 if (unlikely (!acquired)) {
328 warning ("Failed to acquire main loop.\n");
329 return;
330 }
331
332 while (context.pending () || TestBirdFont.is_slow_test ()) {
333 context.iteration (true);
334 t++;
335
336 if (!context.pending () && TestBirdFont.is_slow_test ()) {
337 if (timeout) break;
338 }
339 }
340
341 context.release ();
342 }
343
344 public void set_persistent (bool p) {
345 persistent = p;
346 }
347 }
348
349 }
350