1 /*
2  * Copyright (C) 2017-2019 Robin Gareus <robin@gareus.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #include <math.h> // M_PI
20 #include <assert.h>
21 #include <algorithm> // std:min
22 
23 #include "gtkmm2ext/colors.h"
24 #include "gtkmm2ext/rgb_macros.h"
25 #include "widgets/ardour_icon.h"
26 
27 using namespace ArdourWidgets::ArdourIcon;
28 
29 /* general style info:
30  *
31  * - geometry: icons should be centered, spanning
32  *   wh = std::min (width * .5, height *.5) * .55;
33  *
34  * - all shapes should have a contrasting outline
35  *   (usually white foreground, black outline)
36  */
37 
38 #define DEFAULT_LINE_WIDTH ceil (std::min (width, height) * .035)
39 
40 #define OUTLINEWIDTH 1.5 // px
41 
42 #define VECTORICONSTROKEFILL(fillalpha)              \
43   cairo_set_line_width (cr, OUTLINEWIDTH);           \
44   cairo_set_source_rgba (cr, 0, 0, 0, 1.0);          \
45   cairo_stroke_preserve (cr);                        \
46   cairo_set_source_rgba (cr, 1, 1, 1, (fillalpha));  \
47   cairo_fill (cr);
48 
49 #define VECTORICONSTROKEOUTLINE(LW, color)           \
50   cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);     \
51   cairo_set_line_width (cr, (LW) + OUTLINEWIDTH);    \
52   ardour_icon_set_source_inv_rgba (cr, color);       \
53   cairo_stroke_preserve (cr);                        \
54   Gtkmm2ext::set_source_rgba (cr, color);            \
55   cairo_set_line_width (cr, (LW));                   \
56   cairo_stroke (cr);
57 
58 #define VECTORICONSTROKE(LW, color)                  \
59   cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);     \
60   Gtkmm2ext::set_source_rgba (cr, color);            \
61   cairo_set_line_width (cr, (LW));                   \
62   cairo_stroke (cr);
63 
64 
65 /** inverse color */
ardour_icon_set_source_inv_rgba(cairo_t * cr,uint32_t color)66 static void ardour_icon_set_source_inv_rgba (cairo_t *cr, uint32_t color)
67 {
68 	cairo_set_source_rgba (cr,
69 			1.0 - ((color >> 24) & 0xff) / 255.0,
70 			1.0 - ((color >> 16) & 0xff) / 255.0,
71 			1.0 - ((color >>  8) & 0xff) / 255.0,
72 			((color >>  0) & 0xff) / 255.0
73 			);
74 }
75 
76 /*****************************************************************************
77  * Tool Icons.
78  * Foreground is always white, compatible with small un-blurred rendering.
79  */
80 
81 /** internal edit icon */
icon_tool_content(cairo_t * cr,const int width,const int height)82 static void icon_tool_content (cairo_t *cr, const int width, const int height) {
83 #define EM_POINT(X,Y) round (x + (X) * em) + .5, round (y + (Y) * em) + .5
84 
85 		const double x  = width * .5;
86 		const double y  = height * .5;
87 		const double em = std::min (x, y) * .1; // 1px at 20x20
88 
89 		// draw dot outlines (control-points)
90 		cairo_move_to (cr, EM_POINT(-6.0,  0.0));
91 		cairo_close_path (cr);
92 		cairo_move_to (cr, EM_POINT(-2.5,  4.0));
93 		cairo_close_path (cr);
94 		cairo_move_to (cr, EM_POINT( 5.0, -5.0));
95 		cairo_close_path (cr);
96 
97 		cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
98 		ardour_icon_set_source_inv_rgba (cr, 0xffffffff);
99 		cairo_set_line_width (cr, 3 * em + OUTLINEWIDTH);
100 		cairo_stroke (cr);
101 
102 		// "midi note" lines
103 		cairo_move_to (cr, EM_POINT(-7.0, -5.0));
104 		cairo_line_to (cr, EM_POINT( 0.0, -5.0));
105 
106 		cairo_move_to (cr, EM_POINT( 2.0,  4.0));
107 		cairo_line_to (cr, EM_POINT( 6.0,  4.0));
108 
109 		// automation line (connect control-points)
110 		cairo_move_to (cr, EM_POINT(-6.0,  0.0));
111 		cairo_line_to (cr, EM_POINT(-2.5,  4.0));
112 		cairo_line_to (cr, EM_POINT( 5.0, -5.0));
113 
114 		cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
115 		VECTORICONSTROKEOUTLINE(1 * em, 0xffffffff);
116 
117 		// remove automation line outline at control-points
118 		cairo_move_to (cr, EM_POINT(-6.0,  0.0));
119 		cairo_close_path (cr);
120 		cairo_move_to (cr, EM_POINT(-2.5,  4.0));
121 		cairo_close_path (cr);
122 		cairo_move_to (cr, EM_POINT( 5.0, -5.0));
123 		cairo_close_path (cr);
124 
125 		Gtkmm2ext::set_source_rgba (cr, 0xffffffff);
126 		cairo_set_line_width (cr, 3 * em);
127 		cairo_stroke (cr);
128 #undef EM_POINT
129 }
130 
131 /** range tool |<->| */
icon_tool_range(cairo_t * cr,const int width,const int height)132 static void icon_tool_range (cairo_t *cr, const int width, const int height)
133 {
134 	const double x  = width * .5;
135 	const double y  = height * .5;
136 	const double wh = std::min (x, y) * .55;
137 	const double ar = wh * .6; // arrow
138 
139 	const double bw = ceil (wh) - .5;
140 	const double y0 = ceil (y);
141 	const double ym = rint (y0 - wh * .1) + .5; // arrow-horizontal; slightly to the top, on a px
142 	const double x0 = rint (x) - bw; // left arrow tip
143 	const double x1 = rint (x) + bw; // right arrow tip
144 
145 	// left and right box
146 	cairo_move_to (cr, x0, y0 - bw);
147 	cairo_line_to (cr, x0, y0 + bw);
148 	cairo_move_to (cr, x1, y0 - bw);
149 	cairo_line_to (cr, x1, y0 + bw);
150 
151 	// arrows
152 	cairo_move_to (cr, x0 + ar, ym - ar);
153 	cairo_line_to (cr, x0 + .5, ym);
154 	cairo_line_to (cr, x0 + ar, ym + ar);
155 
156 	cairo_move_to (cr, x1 - ar, ym - ar);
157 	cairo_line_to (cr, x1 - .5, ym);
158 	cairo_line_to (cr, x1 - ar, ym + ar);
159 
160 	// line connecting the arrows
161 	cairo_move_to (cr, x0, ym);
162 	cairo_line_to (cr, x1, ym);
163 	VECTORICONSTROKEOUTLINE(DEFAULT_LINE_WIDTH, 0xffffffff);
164 }
165 
166 /** Grab/Object tool - 6x8em "hand", with 'em' wide index finger. */
icon_tool_grab(cairo_t * cr,const int width,const int height)167 static void icon_tool_grab (cairo_t *cr, const int width, const int height)
168 {
169 	const double x  = width * .5;
170 	const double y  = height * .5;
171 	const double em = std::min (x, y) * .15; // 1.5px at 20x20
172 
173 #define EM_POINT(X,Y) x + (X) * em, y + (Y) * em
174 
175 	// wrist
176 	cairo_move_to (cr, EM_POINT( 2.0,  4.0));
177 	cairo_line_to (cr, EM_POINT(-1.5,  4.0));
178 	cairo_line_to (cr, EM_POINT(-2.5,  2.0));
179 	// thumb
180 	cairo_line_to (cr, EM_POINT(-3.0,  1.0));
181 
182 	// index finger
183 	cairo_line_to (cr, EM_POINT(-2.0,  0.0));
184 	cairo_line_to (cr, EM_POINT(-2.1, -4.0));
185 	cairo_line_to (cr, EM_POINT(-1.5, -4.5));
186 	cairo_line_to (cr, EM_POINT(-1.1, -4.0));
187 	cairo_line_to (cr, EM_POINT(-1.0,  0.1));
188 
189 	// middle finger knuckle
190 	cairo_line_to (cr, EM_POINT(-0.6,  0.3));
191 	cairo_line_to (cr, EM_POINT(-0.3,  0.0));
192 	cairo_line_to (cr, EM_POINT(-0.2, -0.2));
193 	cairo_line_to (cr, EM_POINT( 0.1, -0.3));
194 	cairo_line_to (cr, EM_POINT( 0.4, -0.2));
195 	cairo_line_to (cr, EM_POINT( 0.5,  0.1));
196 
197 	// ring finger knuckle
198 	cairo_line_to (cr, EM_POINT( 0.8,  0.4));
199 	cairo_line_to (cr, EM_POINT( 1.1,  0.2));
200 	cairo_line_to (cr, EM_POINT( 1.2,  0.0));
201 	cairo_line_to (cr, EM_POINT( 1.5, -0.1));
202 	cairo_line_to (cr, EM_POINT( 1.8,  0.0));
203 	cairo_line_to (cr, EM_POINT( 1.9,  0.4));
204 
205 	// pinky
206 	cairo_line_to (cr, EM_POINT( 2.0,  0.6));
207 	cairo_line_to (cr, EM_POINT( 2.4,  0.4));
208 	cairo_line_to (cr, EM_POINT( 2.8,  0.5));
209 	cairo_line_to (cr, EM_POINT( 3.0,  1.0));
210 
211 	// wrist
212 	cairo_line_to (cr, EM_POINT( 3.0,  1.5));
213 	cairo_line_to (cr, EM_POINT( 2.0,  4.0));
214 
215 	cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
216 	cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
217 	VECTORICONSTROKEFILL(1.0);
218 #undef EM_POINT
219 }
220 
221 /** cut icon - scissors */
icon_tool_cut(cairo_t * cr,const int width,const int height)222 static void icon_tool_cut (cairo_t *cr, const int width, const int height)
223 {
224 	const double x  = width * .5;
225 	const double y  = height * .5;
226 	const double em = std::min (x, y) * .1; // 1px at 20x20
227 
228 #define EM_POINT(X,Y) x + (X) * em, y + (Y) * em
229 
230 	cairo_save (cr);
231 	cairo_translate (cr, EM_POINT(4, -3));
232 	cairo_scale (cr, 1.6, 1.0); // ellipse
233 	cairo_arc (cr, 0., 0., 1.5 * em, 0., 2 * M_PI);
234 	cairo_restore (cr);
235 
236 	cairo_move_to (cr, EM_POINT(-6.0,  2.5));
237 	cairo_line_to (cr, EM_POINT( 5.5, -2.0));
238 
239 	cairo_move_to (cr, EM_POINT(-6.0, -2.5));
240 	cairo_line_to (cr, EM_POINT( 5.5,  2.0));
241 
242 	cairo_save (cr);
243 	cairo_translate (cr, EM_POINT(4,  3));
244 	cairo_scale (cr, 1.6, 1.0); // ellipse
245 	cairo_arc (cr, 0., 0., 1.5 * em, 0., 2 * M_PI);
246 	cairo_restore (cr);
247 
248 	cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
249 	cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
250 
251 	VECTORICONSTROKEOUTLINE (1.5 * em, 0xffffffff);
252 #undef EM_POINT
253 }
254 
255 /** time stretch icon */
icon_tool_stretch(cairo_t * cr,const int width,const int height)256 static void icon_tool_stretch (cairo_t *cr, const int width, const int height)
257 {
258 	const double x  = width * .5;
259 	const double y  = height * .5;
260 	const double wh = std::min (x, y) * .55;
261 
262 	const double y0 = ceil (y);
263 	const double bw = rint (wh);
264 	const double lw = rint (wh / 3.0) / 2.0;
265 	const double x0 = rint (x + lw) + .5;
266 
267 	// box indication region
268 	cairo_rectangle (cr, x0 - lw - bw - .5, y0 - bw, lw + bw, 2 * bw);
269 	VECTORICONSTROKEFILL (0.75);
270 
271 	cairo_set_line_width (cr, 1.0);
272 
273 	// inside/left arrow
274 	cairo_move_to (cr, x0,          y);
275 	cairo_line_to (cr, x0 - lw * 2, y);
276 	cairo_line_to (cr, x0 - lw * 2, y - lw * 3.5);
277 	cairo_line_to (cr, x0 - lw * 6, y);
278 	cairo_line_to (cr, x0 - lw * 2, y + lw * 3.5);
279 	cairo_line_to (cr, x0 - lw * 2, y);
280 
281 	cairo_set_source_rgba (cr, 0, 0, 0, .5);
282 	cairo_stroke_preserve (cr);
283 	cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
284 	cairo_fill (cr);
285 
286 	// outside/right arrow
287 	cairo_move_to (cr, x0,          y);
288 	cairo_line_to (cr, x0 + lw * 2, y);
289 	cairo_line_to (cr, x0 + lw * 2, y - lw * 4);
290 	cairo_line_to (cr, x0 + lw * 6, y);
291 	cairo_line_to (cr, x0 + lw * 2, y + lw * 4);
292 	cairo_line_to (cr, x0 + lw * 2, y);
293 
294 	cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
295 	cairo_stroke_preserve (cr);
296 	cairo_set_source_rgba (cr, 1, 1, 1, 1.0);
297 	cairo_fill (cr);
298 }
299 
300 /** audition - small speaker with sound-waves*/
icon_tool_audition(cairo_t * cr,const int width,const int height)301 static void icon_tool_audition (cairo_t *cr, const int width, const int height)
302 {
303 	const double x  = width * .5;
304 	const double y  = height * .5;
305 	const double em = std::min (x, y) * .1; // 1px at 20x20
306 
307 #define EM_POINT(X,Y) x + (X) * em, y + (Y) * em
308 
309 	cairo_move_to (cr, EM_POINT(-7.0, -2.0));
310 	cairo_line_to (cr, EM_POINT(-7.0,  2.0));
311 	cairo_line_to (cr, EM_POINT(-6.0,  3.0));
312 	cairo_line_to (cr, EM_POINT(-3.0,  3.0));
313 	cairo_line_to (cr, EM_POINT( 2.0,  6.0));
314 	cairo_line_to (cr, EM_POINT( 2.0, -6.0));
315 	cairo_line_to (cr, EM_POINT(-3.0, -3.0));
316 	cairo_line_to (cr, EM_POINT(-6.0, -3.0));
317 	cairo_close_path (cr);
318 
319 	cairo_pattern_t *speaker;
320 	speaker = cairo_pattern_create_linear (EM_POINT(0, -3.0), EM_POINT(0, 3.0));
321 	cairo_pattern_add_color_stop_rgba (speaker, 0.0,  0.8, 0.8, 0.8, 1.0);
322 	cairo_pattern_add_color_stop_rgba (speaker, 0.25, 1.0, 1.0, 1.0, 1.0);
323 	cairo_pattern_add_color_stop_rgba (speaker, 1.0,  0.6, 0.6, 0.6, 1.0);
324 
325 	cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
326 	cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
327 	cairo_set_line_width (cr, 1.5);
328 	cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
329 	cairo_stroke_preserve (cr);
330 	cairo_set_source (cr, speaker);
331 	cairo_fill (cr);
332 	cairo_pattern_destroy (speaker);
333 
334 	// TODO use a slight curve
335 	cairo_move_to (cr, EM_POINT(-3.0, -3.0));
336 	cairo_line_to (cr, EM_POINT(-3.5,  0.0));
337 	cairo_line_to (cr, EM_POINT(-3.0,  3.0));
338 	cairo_set_source_rgba (cr, 0, 0, 0, 0.7);
339 	cairo_set_line_width (cr, 1.0);
340 	cairo_stroke (cr);
341 
342 	cairo_save (cr);
343 	cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
344 	cairo_set_source_rgba (cr, 1, 1, 1, 1);
345 
346 	cairo_translate (cr, EM_POINT (4.0, 0));
347 	cairo_scale (cr, 0.8, 1.25); // ellipse
348 
349 	cairo_arc (cr, 0, 0, 4 * em, -.5 * M_PI, .5 * M_PI);
350 	cairo_set_line_width (cr, .8 * em);
351 	cairo_stroke (cr);
352 
353 	cairo_arc (cr, 0, 0, 2 * em, -.5 * M_PI, .5 * M_PI);
354 	cairo_set_line_width (cr, .5 * em);
355 	cairo_stroke (cr);
356 	cairo_restore (cr);
357 #undef EM_POINT
358 }
359 
360 /** pen top-left to bottom right */
icon_tool_draw(cairo_t * cr,const int width,const int height)361 static void icon_tool_draw (cairo_t *cr, const int width, const int height)
362 {
363 	const double x  = width * .5;
364 	const double y  = height * .5;
365 	const double em = std::min (x, y) * .1; // 1px at 20x20
366 
367 #define EM_POINT(X,Y) x + (X) * em, y + (Y) * em
368 
369 	// pen [6,-5] to [-3, 3]
370 	// y = -8 * x / 9 + 1/3
371 
372 	// top-right end
373 	cairo_move_to (cr, EM_POINT( 5.0, -6.11));
374 	cairo_line_to (cr, EM_POINT( 6.4, -5.35)); // todo round properly.
375 	cairo_line_to (cr, EM_POINT( 7.0, -3.88));
376 
377 	// bottom-left w/tip
378 	cairo_line_to (cr, EM_POINT(-2.0,  4.11));
379 	cairo_line_to (cr, EM_POINT(-6.0,  5.66)); // pen tip
380 	cairo_line_to (cr, EM_POINT(-4.0,  1.88));
381 	cairo_close_path (cr);
382 
383 	cairo_pattern_t *pen;
384 	pen = cairo_pattern_create_linear (EM_POINT(-3.0, -6.0), EM_POINT(6.0, 4.0));
385 	cairo_pattern_add_color_stop_rgba (pen, 0.4, 0.6, 0.6, 0.6, 1.0);
386 	cairo_pattern_add_color_stop_rgba (pen, 0.5, 1.0, 1.0, 1.0, 1.0);
387 	cairo_pattern_add_color_stop_rgba (pen, 0.6, 0.1, 0.1, 0.1, 1.0);
388 
389 	cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
390 	cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
391 	cairo_set_line_width (cr, em + .5);
392 	cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
393 	cairo_stroke_preserve (cr);
394 	cairo_set_source (cr, pen);
395 	cairo_fill (cr);
396 
397 	// separate the tip
398 	cairo_move_to (cr, EM_POINT(-2.0,  4.11));
399 	cairo_line_to (cr, EM_POINT(-3.0,  2.8)); // slight curve [-3,3]
400 	cairo_line_to (cr, EM_POINT(-4.0,  2.0));
401 	cairo_set_line_width (cr, OUTLINEWIDTH);
402 	cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
403 	cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
404 	cairo_stroke (cr);
405 
406 	// pen tip
407 	cairo_move_to (cr, EM_POINT(-5.0, 3.9));
408 	cairo_line_to (cr, EM_POINT(-6.0, 5.66));
409 	cairo_line_to (cr, EM_POINT(-4.1, 4.9));
410 	cairo_close_path (cr);
411 	cairo_set_source_rgba (cr, 0, 0, 0, 0.7);
412 	cairo_set_line_width (cr, em);
413 	cairo_stroke_preserve (cr);
414 	cairo_fill (cr);
415 
416 	cairo_pattern_destroy (pen);
417 #undef EM_POINT
418 }
419 
420 /** Toolbar icon - Time Axis View reduce height */
icon_tav_shrink(cairo_t * cr,const int width,const int height)421 static void icon_tav_shrink (cairo_t *cr, const int width, const int height)
422 {
423 	const double x = width * .5;
424 	const double y = height * .5;
425 	const double wh = std::min (x, y) * .66;
426 	const double ar = std::min (x, y) * .15;
427 	const double tri = .7 * (wh - ar);
428 
429 	cairo_rectangle (cr, x - wh, y - ar, 2 * wh, 2 * ar);
430 	VECTORICONSTROKEFILL(.75);
431 
432 	cairo_set_line_width (cr, 1.0);
433 
434 	cairo_move_to (cr, x,       y - ar - 0.5);
435 	cairo_line_to (cr, x - tri, y - wh + 0.5);
436 	cairo_line_to (cr, x + tri, y - wh + 0.5);
437 	cairo_close_path (cr);
438 
439 	cairo_set_source_rgba (cr, 1, 1, 1, .75);
440 	cairo_stroke_preserve (cr);
441 	cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
442 	cairo_fill (cr);
443 
444 	cairo_move_to (cr, x,       y + ar + 0.5);
445 	cairo_line_to (cr, x - tri, y + wh - 0.5);
446 	cairo_line_to (cr, x + tri, y + wh - 0.5);
447 	cairo_close_path (cr);
448 
449 	cairo_set_source_rgba (cr, 1, 1, 1, .75);
450 	cairo_stroke_preserve (cr);
451 	cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
452 	cairo_fill (cr);
453 }
454 
455 /** Toolbar icon - Time Axis View increase height */
icon_tav_expand(cairo_t * cr,const int width,const int height)456 static void icon_tav_expand (cairo_t *cr, const int width, const int height)
457 {
458 	const double x = width * .5;
459 	const double y = height * .5;
460 	const double wh = std::min (x, y) * .66;
461 	const double ar = std::min (x, y) * .15;
462 	const double tri = .7 * (wh - ar);
463 
464 	cairo_rectangle (cr, x - wh, y - wh, 2 * wh, 2 * wh);
465 	VECTORICONSTROKEFILL(.75);
466 
467 	cairo_set_line_width (cr, 1.0);
468 
469 	cairo_move_to (cr, x,       y - wh + 0.5);
470 	cairo_line_to (cr, x - tri, y - ar - 0.5);
471 	cairo_line_to (cr, x + tri, y - ar - 0.5);
472 	cairo_close_path (cr);
473 
474 	cairo_set_source_rgba (cr, 1, 1, 1, .5);
475 	cairo_stroke_preserve (cr);
476 	cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
477 	cairo_fill (cr);
478 
479 	cairo_move_to (cr, x      , y + wh - 0.5);
480 	cairo_line_to (cr, x - tri, y + ar + 0.5);
481 	cairo_line_to (cr, x + tri, y + ar + 0.5);
482 	cairo_close_path (cr);
483 
484 	cairo_set_source_rgba (cr, 1, 1, 1, .5);
485 	cairo_stroke_preserve (cr);
486 	cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
487 	cairo_fill (cr);
488 }
489 
490 /*****************************************************************************
491  * Record enable (transport & track header).
492  *
493  * hardcoded "red" #f46f6f
494  */
495 
496 /** standard rec-enable circle */
icon_rec_enable(cairo_t * cr,const int width,const int height,const Gtkmm2ext::ActiveState state)497 static void icon_rec_enable (cairo_t *cr, const int width, const int height, const Gtkmm2ext::ActiveState state)
498 {
499 	const double x = width * .5;
500 	const double y = height * .5;
501 	const double r = std::min (x, y) * .55;
502 	cairo_arc (cr, x, y, r, 0, 2 * M_PI);
503 	if (state == Gtkmm2ext::ExplicitActive) {
504 		cairo_set_source_rgba (cr, 1.0, .1, .1, 1.0);
505 	}
506 	else if (state == Gtkmm2ext::ImplicitActive) {
507 		cairo_set_source_rgba (cr, .9, .3, .3, 1.0);
508 	}
509 	else {
510 		cairo_set_source_rgba (cr, .4, .3, .3, 1.0);
511 	}
512 	cairo_fill_preserve (cr);
513 	cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.8); // outline
514 	cairo_set_line_width (cr, 1);
515 	cairo_stroke (cr);
516 }
517 
518 /*****************************************************************************
519  * Transport buttons, foreground is always white
520  */
521 
522 /** stop square box */
icon_transport_stop(cairo_t * cr,const int width,const int height)523 static void icon_transport_stop (cairo_t *cr, const int width, const int height)
524 {
525 	const int wh = std::min (width, height);
526 	cairo_rectangle (cr,
527 			(width - wh) * .5 + wh * .225,
528 			(height - wh) * .5 + wh * .225,
529 			wh * .55, wh * .55);
530 	VECTORICONSTROKEFILL(0.9); // small 'shine'
531 }
532 
533 /** play triangle */
icon_transport_play(cairo_t * cr,const int width,const int height)534 static void icon_transport_play (cairo_t *cr, const int width, const int height)
535 {
536 	const int wh = std::min (width, height) * .5;
537 	const double y = height * .5;
538 	const double x = width * .5;
539 
540 	const double tri = ceil (.577 * wh); // 1/sqrt(3)
541 
542 	cairo_move_to (cr,  x + wh * .5, y);
543 	cairo_line_to (cr,  x - wh * .5, y - tri);
544 	cairo_line_to (cr,  x - wh * .5, y + tri);
545 	cairo_close_path (cr);
546 
547 	VECTORICONSTROKEFILL(0.9);
548 }
549 
550 /** Midi Panic "!" */
icon_transport_panic(cairo_t * cr,const int width,const int height)551 static void icon_transport_panic (cairo_t *cr, const int width, const int height)
552 {
553 	const int wh = ceil (std::min (width, height) * .1) - .5;
554 	const double xc = rint (width * .5);
555 	const double yh = std::min (width, height);
556 	const double y0 = (height - yh) * .5;
557 	cairo_rectangle (cr,
558 	                 xc - wh, y0 + yh *.12,
559 	                 wh * 2,  yh *.48);
560 	VECTORICONSTROKEFILL(0.9);
561 
562 	cairo_arc (cr, xc, y0 + yh *.78, wh, 0, 2 * M_PI);
563 	VECTORICONSTROKEFILL(0.9);
564 }
565 
566 /** various combinations of lines and triangles "|>|", ">|" "|>" */
icon_transport_ck(cairo_t * cr,const enum ArdourWidgets::ArdourIcon::Icon icon,const int width,const int height)567 static void icon_transport_ck (cairo_t *cr,
568 		const enum ArdourWidgets::ArdourIcon::Icon icon,
569 		const int width, const int height)
570 {
571 	// small play triangle
572 	int wh = std::min (width, height);
573 	const double y = height * .5;
574 	const double x = width * .5;
575 	wh *= .18;
576 	const double tri = ceil (.577 * wh * 2); // 1/sqrt(3)
577 
578 	const float ln = std::min (width, height) * .07;
579 
580 	if (icon == TransportStart || icon == TransportRange) {
581 		cairo_rectangle (cr,
582 				x - wh - ln, y  - tri * 1.7,
583 				ln * 2,  tri * 3.4);
584 
585 		VECTORICONSTROKEFILL(1.0);
586 	}
587 
588 	if (icon == TransportEnd || icon == TransportRange) {
589 		cairo_rectangle (cr,
590 				x + wh - ln, y  - tri * 1.7,
591 				ln * 2,  tri * 3.4);
592 
593 		VECTORICONSTROKEFILL(1.0);
594 	}
595 
596 	if (icon == TransportStart) {
597 		cairo_move_to (cr,  x - wh, y);
598 		cairo_line_to (cr,  x + wh, y - tri);
599 		cairo_line_to (cr,  x + wh, y + tri);
600 	} else {
601 		cairo_move_to (cr,  x + wh, y);
602 		cairo_line_to (cr,  x - wh, y - tri);
603 		cairo_line_to (cr,  x - wh, y + tri);
604 	}
605 
606 	cairo_close_path (cr);
607 	VECTORICONSTROKEFILL(1.0);
608 }
609 
610 /** loop spiral */
icon_transport_loop(cairo_t * cr,const int width,const int height)611 static void icon_transport_loop (cairo_t *cr, const int width, const int height)
612 {
613 	const double x = width * .5;
614 	const double y = height * .5;
615 	const double r = std::min (x, y);
616 
617 	cairo_arc          (cr, x, y, r * .58, 0, 2 * M_PI);
618 	cairo_arc_negative (cr, x, y, r * .30, 2 * M_PI, 0);
619 
620 	VECTORICONSTROKEFILL (1.0);
621 
622 #define ARCARROW(rad, ang) \
623 	x + (rad) * sin ((ang) * 2.0 * M_PI), y + (rad) * cos ((ang) * 2.0 * M_PI)
624 
625 	cairo_move_to (cr, ARCARROW(r * .30, .72));
626 	cairo_line_to (cr, ARCARROW(r * .11, .72));
627 	cairo_line_to (cr, ARCARROW(r * .55, .60));
628 	cairo_line_to (cr, ARCARROW(r * .74, .72));
629 	cairo_line_to (cr, ARCARROW(r * .58, .72));
630 
631 	cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
632 	cairo_stroke_preserve (cr);
633 	cairo_close_path (cr);
634 	cairo_set_source_rgba (cr, 1, 1, 1, 1.0);
635 	cairo_fill (cr);
636 #undef ARCARROW
637 }
638 
639 /** de-construct thorwil's metronom */
icon_transport_metronom(cairo_t * cr,const int width,const int height)640 static void icon_transport_metronom (cairo_t *cr, const int width, const int height)
641 {
642 	const double x  = width * .5;
643 	const double y  = height * .5;
644 	const double wh = .95 * std::min (x, y);
645 	const double h  = wh * .80;
646 	const double w  = wh * .55;
647 	const double lw = w  * .34;
648 
649 	cairo_rectangle (cr,
650 			x - w * .7, y + h * .25,
651 			w * 1.4, lw);
652 
653 	VECTORICONSTROKEFILL(1.0);
654 
655 	cairo_move_to (cr,  x - w,       y + h);
656 	cairo_line_to (cr,  x + w,       y + h);
657 	cairo_line_to (cr,  x + w * .35, y - h);
658 	cairo_line_to (cr,  x - w * .35, y - h);
659 	cairo_line_to (cr,  x - w,       y + h);
660 
661 	cairo_move_to (cr,  x - w + lw,       y + h -lw);
662 	cairo_line_to (cr,  x - w * .35 + lw, y - h + lw);
663 	cairo_line_to (cr,  x + w * .35 - lw, y - h + lw);
664 	cairo_line_to (cr,  x + w - lw,       y + h -lw);
665 	cairo_line_to (cr,  x - w + lw,       y + h -lw);
666 
667 	VECTORICONSTROKEFILL(1.0);
668 
669 	// Pendulum
670 	// ddx = .70 w      = .75 * .5 wh              = .375 wh
671 	// ddy = .75 h - lw = .75 * .8 wh - wh .5 * .2 = .5 wh
672 	// ang = (ddx/ddy):
673 	// -> angle = atan (ang) = atan (375 / .5) ~= 36deg
674 	const double dx = lw * .2;  // 1 - cos(tan^-1(ang))
675 	const double dy = lw * .4;  // 1 - sin(tan^-1(ang))
676 	cairo_move_to (cr,  x - w * .3     , y + h * .25 + lw * .5);
677 	cairo_line_to (cr,  x - w + dx     , y - h + lw + dy);
678 	cairo_line_to (cr,  x - w + lw     , y - h + lw);
679 	cairo_line_to (cr,  x - w * .3 + lw, y + h * .25 + lw * .5);
680 	cairo_close_path (cr);
681 
682 	VECTORICONSTROKEFILL(1.0);
683 
684 	cairo_rectangle (cr,
685 			x - w * .7, y + h * .25,
686 			w * 1.4, lw);
687 	cairo_fill (cr);
688 }
689 
690 /*****************************************************************************
691  * Zoom: In "+", Out "-" and Full "[]"
692  */
icon_zoom(cairo_t * cr,const enum ArdourWidgets::ArdourIcon::Icon icon,const int width,const int height,const uint32_t fg_color)693 static void icon_zoom (cairo_t *cr, const enum ArdourWidgets::ArdourIcon::Icon icon, const int width, const int height, const uint32_t fg_color)
694 {
695 	const double x = width * .5;
696 	const double y = height * .5;
697 	const double r = std::min (x, y) * .7;
698 	const double wh = std::min (x, y) * .45;
699 
700 	// draw handle first
701 #define LINE45DEG(rad) \
702 	x + r * (rad) * .707, y + r * (rad) * .707 // sin(45deg) = cos(45deg) = .707
703 	cairo_move_to (cr, LINE45DEG(.9));
704 	cairo_line_to (cr, LINE45DEG(1.3));
705 	cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
706 	cairo_set_line_width (cr, 3.0);
707 	cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
708 	cairo_stroke (cr);
709 #undef LINE45DEG
710 
711 	// lens
712 	Gtkmm2ext::set_source_rgba (cr, fg_color);
713 	cairo_arc (cr, x, y, r, 0, 2 * M_PI);
714 	cairo_fill_preserve (cr);
715 
716 	// add a lens gradient
717 	cairo_pattern_t *lens;
718 	lens = cairo_pattern_create_radial (x - r, y - r, r * .5, x - r, y - r, r * 2);
719 	cairo_pattern_add_color_stop_rgba (lens, 0, 1, 1, 1, .4);
720 	cairo_pattern_add_color_stop_rgba (lens, 1, 0, 0, 0, .4);
721 	cairo_set_source (cr, lens);
722 	cairo_fill_preserve (cr);
723 	cairo_pattern_destroy (lens);
724 
725 	// outline
726 	cairo_set_line_width (cr, 1.5);
727 	//ardour_icon_set_source_inv_rgba (cr, fg_color); // alpha
728 	cairo_set_source_rgba (cr, .0, .0, .0, .8);
729 	cairo_stroke (cr);
730 
731 	// add "+", "-" or "[]"
732 	cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
733 	cairo_set_line_width (cr, .5 + DEFAULT_LINE_WIDTH);
734 	ardour_icon_set_source_inv_rgba (cr, fg_color);
735 
736 	if (icon == ZoomIn || icon == ZoomOut) {
737 		cairo_move_to (cr, x - wh, y);
738 		cairo_line_to (cr, x + wh, y);
739 		cairo_stroke (cr);
740 	}
741 	if (icon == ZoomIn) {
742 		cairo_move_to (cr, x, y - wh);
743 		cairo_line_to (cr, x, y + wh);
744 		cairo_stroke (cr);
745 	}
746 	if (icon == ZoomFull) {
747 		const double br0 = std::min (x, y) * .1;
748 		const double br1 = std::min (x, y) * .3;
749 		const double bry = std::min (x, y) * .3;
750 		cairo_move_to (cr, x - br0, y - bry);
751 		cairo_line_to (cr, x - br1, y - bry);
752 		cairo_line_to (cr, x - br1, y + bry);
753 		cairo_line_to (cr, x - br0, y + bry);
754 		cairo_stroke (cr);
755 
756 		cairo_move_to (cr, x + br0, y - bry);
757 		cairo_line_to (cr, x + br1, y - bry);
758 		cairo_line_to (cr, x + br1, y + bry);
759 		cairo_line_to (cr, x + br0, y + bry);
760 		cairo_stroke (cr);
761 	}
762 }
763 
764 /** Toolbar icon - Mixbus Zoom Expand, rotated TimeAxisExpand */
icon_zoom_expand(cairo_t * cr,const int width,const int height)765 static void icon_zoom_expand (cairo_t *cr, const int width, const int height)
766 {
767 	const double x = width * .5;
768 	const double y = height * .5;
769 	const double wh = std::min (x, y) * .66;
770 	const double ar = std::min (x, y) * .15;
771 	const double tri = .7 * (wh - ar);
772 
773 	cairo_rectangle (cr, x - wh, y - wh, 2 * wh, 2 * wh);
774 	VECTORICONSTROKEFILL(.75);
775 
776 	cairo_set_line_width (cr, 1.0);
777 
778 	cairo_move_to (cr, x - wh + 0.5, y);
779 	cairo_line_to (cr, x - ar - 0.5, y - tri);
780 	cairo_line_to (cr, x - ar - 0.5, y + tri);
781 	cairo_close_path (cr);
782 
783 	cairo_set_source_rgba (cr, 1, 1, 1, .5);
784 	cairo_stroke_preserve (cr);
785 	cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
786 	cairo_fill (cr);
787 
788 	cairo_move_to (cr, x + wh - 0.5, y);
789 	cairo_line_to (cr, x + ar + 0.5, y - tri);
790 	cairo_line_to (cr, x + ar + 0.5, y + tri);
791 	cairo_close_path (cr);
792 
793 	cairo_set_source_rgba (cr, 1, 1, 1, .5);
794 	cairo_stroke_preserve (cr);
795 	cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
796 	cairo_fill (cr);
797 }
798 
799 /*****************************************************************************
800  * Misc buttons
801  */
802 
803 /** "close" - "X" , no outline */
icon_close_cross(cairo_t * cr,const int width,const int height,const uint32_t fg_color)804 static void icon_close_cross (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
805 {
806 	const double x = width * .5;
807 	const double y = height * .5;
808 	const double o = .5 + std::min (x, y) * .4;
809 	Gtkmm2ext::set_source_rgba (cr, fg_color);
810 	cairo_set_line_width (cr, DEFAULT_LINE_WIDTH);
811 	cairo_move_to (cr, x-o, y-o);
812 	cairo_line_to (cr, x+o, y+o);
813 	cairo_move_to (cr, x+o, y-o);
814 	cairo_line_to (cr, x-o, y+o);
815 	cairo_stroke (cr);
816 }
817 
818 /** "hide" strike through eye */
icon_hide_eye(cairo_t * cr,const int width,const int height,const uint32_t fg_color)819 static void icon_hide_eye (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
820 {
821 	const double x = width * .5;
822 	const double y = height * .5;
823 	const double wh = std::min (x, y);
824 
825 	const double r  = .2 * wh;
826 	const double o =  .60 * wh;
827 	const double dx = .75 * wh;
828 	const double dy = .65 * wh;
829 
830 	cairo_move_to (cr, x - dx, y);
831 	cairo_curve_to (cr, x, y + dy, x, y + dy, x + dx, y);
832 	cairo_curve_to (cr, x, y - dy, x, y - dy, x - dx, y);
833 	VECTORICONSTROKE (DEFAULT_LINE_WIDTH, fg_color);
834 
835 	cairo_arc (cr, x, y, r, 0, 2 * M_PI);
836   //cairo_fill (cr);
837 	VECTORICONSTROKE (DEFAULT_LINE_WIDTH, fg_color);
838 
839 	cairo_move_to (cr, x - o, y + o);
840 	cairo_line_to (cr, x + o, y - o);
841 	VECTORICONSTROKEOUTLINE (DEFAULT_LINE_WIDTH, fg_color);
842 }
843 
844 /** slim "<" */
icon_scroll_left(cairo_t * cr,const int width,const int height,const uint32_t fg_color)845 static void icon_scroll_left (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
846 {
847 	const double x = width * .5;
848 	const double y = height * .5;
849 	const double wh = std::min (x, y);
850 
851 	const double tri1 = .2 * wh;
852 	const double tri2 = .4 * wh;
853 
854 	cairo_move_to (cr, x + tri1, y - tri2);
855 	cairo_line_to (cr, x - tri2, y);
856 	cairo_line_to (cr, x + tri1, y + tri2);
857 	VECTORICONSTROKE (DEFAULT_LINE_WIDTH, fg_color);
858 }
859 
860 /** slim ">" */
icon_scroll_right(cairo_t * cr,const int width,const int height,const uint32_t fg_color)861 static void icon_scroll_right (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
862 {
863 
864 	const double x = width * .5;
865 	const double y = height * .5;
866 	const double wh = std::min (x, y);
867 
868 	const double tri1 = .2 * wh;
869 	const double tri2 = .4 * wh;
870 
871 	cairo_move_to (cr, x - tri1, y - tri2);
872 	cairo_line_to (cr, x + tri2, y);
873 	cairo_line_to (cr, x - tri1, y + tri2);
874 	VECTORICONSTROKE (DEFAULT_LINE_WIDTH, fg_color);
875 }
876 
877 /** "<" */
icon_nudge_left(cairo_t * cr,const int width,const int height,const uint32_t fg_color)878 static void icon_nudge_left (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
879 {
880 	const double x = width * .5;
881 	const double y = height * .5;
882 	const double wh = std::min (x, y);
883 
884 	const double tri_x = .3 * wh;
885 	const double tri_y = .6 * wh;
886 
887 	cairo_move_to (cr, x + tri_x, y - tri_y);
888 	cairo_line_to (cr, x - tri_x, y);
889 	cairo_line_to (cr, x + tri_x, y + tri_y);
890 	VECTORICONSTROKEOUTLINE(.5 + DEFAULT_LINE_WIDTH, fg_color);
891 }
892 
893 /** ">" */
icon_nudge_right(cairo_t * cr,const int width,const int height,const uint32_t fg_color)894 static void icon_nudge_right (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
895 {
896 
897 	const double x = width * .5;
898 	const double y = height * .5;
899 	const double wh = std::min (x, y);
900 
901 	const double tri_x = .3 * wh;
902 	const double tri_y = .6 * wh;
903 
904 	cairo_move_to (cr, x - tri_x, y - tri_y);
905 	cairo_line_to (cr, x + tri_x, y);
906 	cairo_line_to (cr, x - tri_x, y + tri_y);
907 	VECTORICONSTROKEOUTLINE(.5 + DEFAULT_LINE_WIDTH, fg_color);
908 
909 }
910 
icon_plus_sign(cairo_t * cr,const int width,const int height,const uint32_t fg_color)911 static void icon_plus_sign (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
912 {
913 	const double lw = DEFAULT_LINE_WIDTH;
914 	const double lc = fmod (lw * .5, 1.0);
915 	const double xc = rint (width * .5) - lc;
916 	const double yc = rint (height * .5) - lc;
917 	const double ln = rint (std::min (width, height) * .2);
918 
919 	cairo_rectangle (cr, xc - lw * .5, yc - ln, lw,  ln * 2);
920 	cairo_rectangle (cr, xc - ln, yc - lw * .5, ln * 2,  lw);
921 
922   Gtkmm2ext::set_source_rgba (cr, fg_color);
923   cairo_fill (cr);
924 }
925 
icon_shaded_plus_sign(cairo_t * cr,const int width,const int height,const uint32_t fg_color)926 static void icon_shaded_plus_sign (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
927 {
928 	const double lw = std::min (10., ceil (std::min (width, height) * .035));
929 	const double ln = std::min (57., rint (std::min (width, height) * .2));
930 	const double lc = fmod (lw * .5, 1.0);
931 	const double xc = rint (width * .5) - lc;
932 	const double yc = rint (height * .5) - lc;
933 
934 	cairo_rectangle (cr, xc - lw * .5, yc - ln, lw,  ln * 2);
935 	cairo_rectangle (cr, xc - ln, yc - lw * .5, ln * 2,  lw);
936 
937 	int alpha = lw == 1 ? 0x80 : 0x20;
938 	Gtkmm2ext::set_source_rgba (cr, (fg_color & 0xffffff00) | alpha);
939 	cairo_fill (cr);
940 }
941 
942 /** mixer strip narrow/wide */
icon_strip_width(cairo_t * cr,const int width,const int height,const uint32_t fg_color)943 static void icon_strip_width (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
944 {
945 	const double lw = DEFAULT_LINE_WIDTH;
946 	const double xm = rint (width * .5) - lw * .5;
947 	const double ym = rint (height * .5) - lw * .5;
948 
949 	const double dx = ceil (width * .3);
950 	const double dy = ceil (height * .25);
951 
952 	const double x0 = xm - dx;
953 	const double x1 = xm + dx;
954 	const double y0 = ym - dy;
955 	const double y1 = ym + dy;
956 
957 	const double arx = width  * .15;
958 	const double ary = height * .15;
959 
960 	Gtkmm2ext::set_source_rgba (cr, fg_color);
961 	cairo_set_line_width (cr, lw);
962 
963 	// left + right
964 	cairo_move_to (cr, x0, y0);
965 	cairo_line_to (cr, x0, y1);
966 	cairo_move_to (cr, x1, y0);
967 	cairo_line_to (cr, x1, y1);
968 
969 	// horiz center line
970 	cairo_move_to (cr, x0, ym);
971 	cairo_line_to (cr, x1, ym);
972 
973 	// arrow left
974 	cairo_move_to (cr,  x0, ym);
975 	cairo_rel_line_to (cr, arx, -ary);
976 	cairo_move_to (cr,  x0, ym);
977 	cairo_rel_line_to (cr, arx, ary);
978 
979 	// arrow right
980 	cairo_move_to (cr,  x1,  ym);
981 	cairo_rel_line_to (cr, -arx, -ary);
982 	cairo_move_to (cr,  x1,  ym);
983 	cairo_rel_line_to (cr, -arx, ary);
984 	cairo_stroke (cr);
985 }
986 
987 /** 5-pin DIN MIDI socket */
icon_din_midi(cairo_t * cr,const int width,const int height,const uint32_t fg_color)988 static void icon_din_midi (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
989 {
990 	const double x = width * .5;
991 	const double y = height * .5;
992 	const double r = std::min (x, y) * .75;
993 	Gtkmm2ext::set_source_rgba (cr, fg_color);
994 	cairo_set_line_width (cr, ceil (r * .05));
995 	cairo_arc (cr, x, y, r, .57 * M_PI, 2.43 * M_PI);
996 	cairo_stroke (cr);
997 
998 	// pins equally spaced 45deg
999 	cairo_arc (cr, x, y * 0.5, r * .15, 0, 2 * M_PI);
1000 	cairo_fill (cr);
1001 	cairo_arc (cr, x * 0.5, y, r * .15, 0, 2 * M_PI);
1002 	cairo_fill (cr);
1003 	cairo_arc (cr, x * 1.5, y, r * .15, 0, 2 * M_PI);
1004 	cairo_fill (cr);
1005 	//  .5 + .5 * .5 * sin(45deg),  1.5 - .5 * .5 * cos(45deg)
1006 	cairo_arc (cr, x * 0.677, y * .677, r * .15, 0, 2 * M_PI);
1007 	cairo_fill (cr);
1008 	cairo_arc (cr, x * 1.323, y * .677, r * .15, 0, 2 * M_PI);
1009 	cairo_fill (cr);
1010 
1011 	// bottom notch
1012 	cairo_arc (cr, x, y+r, r * .26, 1.05 * M_PI, 1.95 * M_PI);
1013 	cairo_stroke (cr);
1014 }
1015 
1016 /*****************************************************************************
1017  * Plugin Window Buttons
1018  */
1019 
icon_add_sign(cairo_t * cr,const int width,const int height,const uint32_t fg_color)1020 static void icon_add_sign (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
1021 {
1022 	const double lw = DEFAULT_LINE_WIDTH;
1023 	const double lc = fmod (lw * .5, 1.0);
1024 	const double xc = rint (width * .5) - lc;
1025 	const double yc = rint (height * .5) - lc;
1026 	const double ln = rint (std::min (width, height) * .3);
1027 
1028 	cairo_rectangle (cr, xc - lw * .5, yc - ln, lw,  ln * 2);
1029 	cairo_rectangle (cr, xc - ln, yc - lw * .5, ln * 2,  lw);
1030 
1031   Gtkmm2ext::set_source_rgba (cr, fg_color);
1032   cairo_fill (cr);
1033 }
1034 
icon_no_parking(cairo_t * cr,const int width,const int height,const uint32_t fg_color)1035 static void icon_no_parking (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
1036 {
1037 	const double x = width * .5;
1038 	const double y = height * .5;
1039 	const double r = std::min (x, y) * .6;
1040 	const double rl = .7 * r;
1041 	cairo_arc (cr, x, y, r, 0, 2. * M_PI);
1042 	cairo_move_to (cr, x - rl, y - rl);
1043 	cairo_line_to (cr, x + rl, y + rl);
1044 	VECTORICONSTROKE (DEFAULT_LINE_WIDTH, fg_color);
1045 }
1046 
icon_save_arrow_box(cairo_t * cr,const int width,const int height,const uint32_t fg_color)1047 static void icon_save_arrow_box (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
1048 {
1049 	const double x = width * .5;
1050 	const double y = height * .5;
1051 
1052 	const double lw = DEFAULT_LINE_WIDTH;
1053 	const double lc = fmod (lw * .5, 1.0);
1054 
1055 	const double x0 = rint (x) - lc;
1056 	const double y0 = rint (y + std::min (x, y) * .05) - lc;
1057 	const double o0 = std::min (x, y) * .35;
1058 	const double ww = rint (std::min (x, y) * .55);
1059 	const double hh = rint (std::min (x, y) * .45);
1060 	const double ar = .5 + std::min (x, y) * .1;
1061 
1062 	/* box open at top middle */
1063 	cairo_move_to (cr, x0 - o0, y0 - hh);
1064 	cairo_line_to (cr, x0 - ww, y0 - hh);
1065 	cairo_line_to (cr, x0 - ww, y0 + hh);
1066 	cairo_line_to (cr, x0 + ww, y0 + hh);
1067 	cairo_line_to (cr, x0 + ww, y0 - hh);
1068 	cairo_line_to (cr, x0 + o0, y0 - hh);
1069 	VECTORICONSTROKE (lw, fg_color);
1070 
1071 	/* downward arrow into the box */
1072 	cairo_move_to (cr, x0,      y0 - ar);
1073 	cairo_line_to (cr, x0 - ar, y0 - ar);
1074 	cairo_line_to (cr, x0,      y0);
1075 	cairo_line_to (cr, x0 + ar, y0 - ar);
1076 	cairo_line_to (cr, x0,      y0 - ar);
1077 	cairo_line_to (cr, x0,      y0 - ww - ar);
1078 	VECTORICONSTROKE (lw, fg_color);
1079 }
1080 
icon_list_browse(cairo_t * cr,const int width,const int height,const uint32_t fg_color)1081 static void icon_list_browse (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
1082 {
1083 	const double x = width * .5;
1084 	const double y = height * .5;
1085 	const double d = std::min (x, y) * .5;
1086 	const double r = std::min (x, y) * .1;
1087 	const double l = std::min (x, y) * .2;
1088 	const double lw = DEFAULT_LINE_WIDTH;
1089 
1090   Gtkmm2ext::set_source_rgba (cr, fg_color);
1091 	cairo_arc (cr, x-d, y-d, r, 0, 2. * M_PI);
1092 	cairo_fill (cr);
1093 	cairo_arc (cr, x-d, y, r, 0, 2. * M_PI);
1094 	cairo_fill (cr);
1095 	cairo_arc (cr, x-d, y+d, r, 0, 2. * M_PI);
1096 	cairo_fill (cr);
1097 
1098 	cairo_move_to (cr, x - l, rint (y - d) + .5);
1099 	cairo_line_to (cr, x + d, rint (y - d) + .5);
1100 	cairo_move_to (cr, x - l, rint (y)     + .5);
1101 	cairo_line_to (cr, x + d, rint (y)     + .5);
1102 	cairo_move_to (cr, x - l, rint (y + d) + .5);
1103 	cairo_line_to (cr, x + d, rint (y + d) + .5);
1104 	VECTORICONSTROKE(lw, fg_color);
1105 }
1106 
icon_on_off(cairo_t * cr,const int width,const int height,const uint32_t fg_color)1107 static void icon_on_off (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
1108 {
1109 	const double x = width * .5;
1110 	const double y = height * .5;
1111 	const double r = std::min (x, y) * .65;
1112 	const double lw = DEFAULT_LINE_WIDTH;
1113 	const double lc = fmod (lw * .5, 1.0);
1114 	const double x0 = rint (x) - lc;
1115 
1116 	cairo_arc (cr, x0, y, r, -.3 * M_PI, 1.3 * M_PI);
1117 	cairo_move_to (cr, x0, y - r);
1118 	cairo_line_to (cr, x0, y);
1119 	VECTORICONSTROKE (lw, fg_color);
1120 }
1121 
icon_bypass(cairo_t * cr,const int width,const int height,const uint32_t fg_color)1122 static void icon_bypass (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
1123 {
1124 	const double x = width * .5;
1125 	const double y = height * .5;
1126 	const double y0 = height * .6;
1127 	const double r = std::min (x, y) * .75;
1128 	const double o = std::min (x, y) * .275;
1129 	const double pt = DEFAULT_LINE_WIDTH;
1130 
1131 	const double dashes[] = { 1, pt };
1132 	cairo_set_dash (cr, dashes, 2, 0);
1133 	cairo_move_to (cr, x - r, y0);
1134 	cairo_line_to (cr, x + r, y0);
1135 	VECTORICONSTROKE(pt * .8, fg_color);
1136 	cairo_set_dash (cr, 0, 0, 0);
1137 
1138 	cairo_move_to (cr, x - o, y0 - o);
1139 	cairo_line_to (cr, x + o, y0 + o);
1140 	cairo_move_to (cr, x + o, y0 - o);
1141 	cairo_line_to (cr, x - o, y0 + o);
1142 	VECTORICONSTROKE(pt * .8, fg_color);
1143 
1144 	cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
1145 	cairo_arc (cr, x, y0, r, 0, 0);
1146 	cairo_arc (cr, x, y0, r *.8, 1.92 * M_PI, 1.92 * M_PI);
1147 	cairo_arc (cr, x, y0, r * 1.17, 1.92 * M_PI, 1.92 * M_PI);
1148 	cairo_close_path (cr);
1149 	cairo_arc_negative (cr, x, y0, r, 0, M_PI);
1150 	VECTORICONSTROKE(pt, fg_color);
1151 }
1152 
icon_reset_knob(cairo_t * cr,const int width,const int height,const uint32_t fg_color)1153 static void icon_reset_knob (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
1154 {
1155 	const double x = width * .5;
1156 	const double y = height * .5;
1157 	const double r0 = std::min (x, y) * .3;
1158 	const double r1 = std::min (x, y) * .65;
1159 	const double ar = std::min (x, y) * .25;
1160 	const double lw = DEFAULT_LINE_WIDTH;
1161 	const double lc = fmod (lw * .5, 1.0);
1162 	const double x0 = rint (x) - lc;
1163 
1164 	cairo_arc (cr, x0, y, r0, 0, 2. * M_PI);
1165 	cairo_move_to (cr, x0, y - r0);
1166 	cairo_line_to (cr, x0, y);
1167 	VECTORICONSTROKE(lw, fg_color);
1168 
1169 	/* outer ring w/CCW arrow */
1170 	cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
1171 	cairo_arc (cr, x0, y, r1, -.25 * M_PI, -.25 * M_PI);
1172 	cairo_rel_line_to (cr, 0, ar);
1173 	cairo_rel_line_to (cr, ar, -ar);
1174 	cairo_arc (cr, x0, y, r1, -.25 * M_PI, -.25 * M_PI);
1175 	cairo_arc (cr, x0, y, r1, -.25 * M_PI, 1.50 * M_PI);
1176 	VECTORICONSTROKE(lw, fg_color);
1177 }
1178 
icon_config_wheel(cairo_t * cr,const int width,const int height,const uint32_t fg_color,int arrow)1179 static void icon_config_wheel (cairo_t *cr, const int width, const int height, const uint32_t fg_color, int arrow)
1180 {
1181 	const double x = width * .5;
1182 	const double y = height * .5;
1183 	const double r0 = std::min (x, y) * .3;
1184 	const double r1 = std::min (x, y) * .55;
1185 	const double r2 = std::min (x, y) * .70;
1186 	const double ar = std::min (x, y) * .25;
1187 	const double lw = DEFAULT_LINE_WIDTH;
1188 
1189 	for (int i = 0; i < 8; ++i) {
1190 		double ang0 = i * 2.0 * M_PI / 8.0;
1191 		double ang1 = (i + 1) * 2.0 * M_PI / 8.0;
1192 		double angm = 2.0 * M_PI / 48.0;
1193 		double angd = 2.0 * M_PI / 64.0;
1194 
1195 		cairo_arc (cr, x, y, r2, ang0 - angm, ang0 + angm);
1196 		cairo_arc (cr, x, y, r1, ang0 + angm + angd, ang1 - angm - angd);
1197 	}
1198 	cairo_close_path (cr);
1199 	VECTORICONSTROKE(lw, fg_color);
1200 
1201 	cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
1202 	if (arrow == 0) {
1203 		cairo_arc (cr, x, y, r0, 0, 2.0 * M_PI);
1204 	} else if (arrow > 0) {
1205 		/* clockwise pointing arrow */
1206 		cairo_arc (cr, x, y, r0, 1.9 * M_PI, 1.9 * M_PI);
1207 		cairo_rel_line_to (cr, 0, -ar);
1208 		cairo_rel_line_to (cr, -ar, ar);
1209 		cairo_arc (cr, x, y, r0, 1.9 * M_PI, 1.9 * M_PI);
1210 		cairo_arc_negative (cr, x, y, r0, 1.9 * M_PI, .5 * M_PI);
1211 	} else {
1212 		/* counterclockwise arrow */
1213 		cairo_arc (cr, x, y, r0, 1.1 * M_PI, 1.1 * M_PI);
1214 		cairo_rel_line_to (cr, 0, -ar);
1215 		cairo_rel_line_to (cr, ar, ar);
1216 		cairo_arc (cr, x, y, r0, 1.1 * M_PI, 1.1 * M_PI);
1217 		cairo_arc (cr, x, y, r0, 1.1 * M_PI, .5 * M_PI);
1218 	}
1219 	VECTORICONSTROKE(lw, fg_color);
1220 }
1221 
icon_pcb_via(cairo_t * cr,const int width,const int height,const uint32_t fg_color)1222 static void icon_pcb_via (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
1223 {
1224 	const double x = ceil (width * .5) - .5;
1225 	const double y = ceil (height * .5) - .5;
1226 
1227 	const double d = rint (std::min (x, y) * .5);
1228 	const double r = std::min (x, y) * .16;
1229 	const double p = std::min (x, y) * .1;
1230 
1231 	cairo_arc_negative (cr, x+d, y+d, r,        1.15 * M_PI, -.85 * M_PI);
1232 	cairo_arc          (cr, x+d, y+d, d * 1.12, 1.15 * M_PI, 1.15 * M_PI);
1233 
1234 	cairo_arc          (cr, x-d, y-d, d * 1.12, 0.15 * M_PI, .15 * M_PI);
1235 	cairo_arc          (cr, x-d, y-d, r,        0.15 * M_PI, 2.5 * M_PI);
1236 
1237 	cairo_arc          (cr, x-d, y-d, r,          .5 * M_PI,  .5 * M_PI);
1238 	cairo_arc          (cr, x-d, y+d, r,         -.5 * M_PI, 1.5 * M_PI);
1239 	VECTORICONSTROKE (p, fg_color);
1240 
1241 	cairo_arc (cr, x+d, y-d, r, -.5 * M_PI, 1.5 * M_PI);
1242 	VECTORICONSTROKE (p, fg_color);
1243 }
1244 
icon_latency_clock(cairo_t * cr,const int width,const int height,const uint32_t fg_color)1245 static void icon_latency_clock (cairo_t *cr, const int width, const int height, const uint32_t fg_color)
1246 {
1247 	const double x = width * .5;
1248 	const double y = height * .5;
1249 	const double y0 = std::min (x, y) * .4;
1250 	const double r0 = std::min (x, y) * .1;
1251 	const double r1 = std::min (x, y) * .5;
1252 	const double r2 = std::min (x, y) * .66;
1253 
1254 	const double lw = DEFAULT_LINE_WIDTH;
1255 	const double lc = fmod (lw * .5, 1.0);
1256 	const double x0 = rint (x) - lc;
1257 
1258 	cairo_move_to (cr, x0, y - y0);
1259 	cairo_arc     (cr, x0, y, r2, -.5 * M_PI, 1.25 * M_PI);
1260 	VECTORICONSTROKE(lw, fg_color);
1261 
1262 	cairo_arc (cr, x0, y, r0,  -.4 * M_PI  , .9 * M_PI);
1263 	cairo_arc (cr, x0, y, r1, 1.25 * M_PI, 1.25 * M_PI);
1264 	cairo_arc (cr, x0, y, r0,  -.4 * M_PI,  -.4 * M_PI);
1265 	cairo_close_path (cr);
1266   cairo_fill (cr);
1267 }
1268 
1269 /*****************************************************************************/
1270 
1271 bool
render(cairo_t * cr,const enum ArdourWidgets::ArdourIcon::Icon icon,const int width,const int height,const Gtkmm2ext::ActiveState state,const uint32_t fg_color)1272 ArdourWidgets::ArdourIcon::render (cairo_t *cr,
1273                                    const enum ArdourWidgets::ArdourIcon::Icon icon,
1274                                    const int width, const int height,
1275                                    const Gtkmm2ext::ActiveState state,
1276                                    const uint32_t fg_color)
1277 {
1278 	bool rv = true;
1279 	cairo_save (cr);
1280 
1281 	if (width < 6 || height < 6) {
1282 		return false;
1283 	}
1284 
1285 	switch (icon) {
1286 		case TransportStop:
1287 			icon_transport_stop (cr, width, height);
1288 			break;
1289 		case TransportPlay:
1290 			icon_transport_play (cr, width, height);
1291 			break;
1292 		case TransportLoop:
1293 			icon_transport_loop (cr, width, height);
1294 			break;
1295 		case TransportMetronom:
1296 			icon_transport_metronom (cr, width, height);
1297 			break;
1298 		case TransportPanic:
1299 			icon_transport_panic (cr, width, height);
1300 			break;
1301 		case TransportStart:
1302 			/* fallthrough */
1303 		case TransportEnd:
1304 			/* fallthrough */
1305 		case TransportRange:
1306 			icon_transport_ck (cr, icon, width, height);
1307 			break;
1308 		case RecButton:
1309 			icon_rec_enable (cr, width, height, state);
1310 			break;
1311 		case CloseCross:
1312 			icon_close_cross (cr, width, height, fg_color);
1313 			break;
1314 		case HideEye:
1315 			icon_hide_eye (cr, width, height, fg_color);
1316 			break;
1317 		case PlusSign:
1318 			icon_plus_sign (cr, width, height, fg_color);
1319 			break;
1320 		case ShadedPlusSign:
1321 			icon_shaded_plus_sign (cr, width, height, fg_color);
1322 			break;
1323 		case StripWidth:
1324 			icon_strip_width (cr, width, height, fg_color);
1325 			break;
1326 		case DinMidi:
1327 			icon_din_midi (cr, width, height, fg_color);
1328 			break;
1329 		case ScrollLeft:
1330 			icon_scroll_left (cr, width, height, fg_color);
1331 			break;
1332 		case ScrollRight:
1333 			icon_scroll_right (cr, width, height, fg_color);
1334 			break;
1335 		case NudgeLeft:
1336 			icon_nudge_left (cr, width, height, fg_color);
1337 			break;
1338 		case NudgeRight:
1339 			icon_nudge_right (cr, width, height, fg_color);
1340 			break;
1341 		case ZoomIn:
1342 			/* fallthrough */
1343 		case ZoomOut:
1344 			/* fallthrough */
1345 		case ZoomFull:
1346 			icon_zoom (cr, icon, width, height, fg_color);
1347 			break;
1348 		case ZoomExpand:
1349 			icon_zoom_expand (cr, width, height);
1350 			break;
1351 		case TimeAxisShrink:
1352 			icon_tav_shrink (cr, width, height);
1353 			break;
1354 		case TimeAxisExpand:
1355 			icon_tav_expand (cr, width, height);
1356 			break;
1357 		case ToolRange:
1358 			/* similar to icon_strip_width() but with outline */
1359 			icon_tool_range (cr, width, height);
1360 			break;
1361 		case ToolGrab:
1362 			icon_tool_grab (cr, width, height);
1363 			break;
1364 		case ToolCut:
1365 			icon_tool_cut (cr, width, height);
1366 			break;
1367 		case ToolStretch:
1368 			icon_tool_stretch (cr, width, height);
1369 			break;
1370 		case ToolAudition:
1371 			icon_tool_audition (cr, width, height);
1372 			break;
1373 		case ToolDraw:
1374 			icon_tool_draw (cr, width, height);
1375 			break;
1376 		case ToolContent:
1377 			icon_tool_content (cr, width, height);
1378 			break;
1379 		case PsetAdd:
1380 			icon_add_sign (cr, width, height, fg_color);
1381 			break;
1382 		case PsetSave:
1383 			icon_save_arrow_box (cr, width, height, fg_color);
1384 			break;
1385 		case PsetDelete:
1386 			icon_no_parking (cr, width, height, fg_color);
1387 			break;
1388 		case PsetBrowse:
1389 			icon_list_browse (cr, width, height, fg_color);
1390 			break;
1391 		case PluginReset:
1392 			icon_reset_knob (cr, width, height, fg_color);
1393 			break;
1394 		case PluginBypass:
1395 			icon_bypass (cr, width, height, fg_color);
1396 			break;
1397 		case PluginPinout:
1398 			icon_pcb_via (cr, width, height, fg_color);
1399 			break;
1400 		case Config: /* unused */
1401 			icon_config_wheel (cr, width, height, fg_color, 0);
1402 			break;
1403 		case ConfigReset: /* unused */
1404 			icon_config_wheel (cr, width, height, fg_color, -1);
1405 			break;
1406 		case PowerOnOff: /* unused */
1407 			icon_on_off (cr, width, height, fg_color);
1408 			break;
1409 		case LatencyClock: /* unused */
1410 			icon_latency_clock (cr, width, height, fg_color);
1411 			break;
1412 		case NoIcon:
1413 			rv = false;
1414 			break;
1415 	}
1416 	cairo_restore (cr);
1417 	return rv;
1418 }
1419 
1420 bool
expose(GdkEventExpose * ev,Gtk::Widget * w,const enum ArdourIcon::Icon icon)1421 ArdourWidgets::ArdourIcon::expose (GdkEventExpose* ev, Gtk::Widget* w, const enum ArdourIcon::Icon icon)
1422 {
1423 	Glib::RefPtr<Gdk::Window> win (w->get_window());
1424   cairo_t* cr = gdk_cairo_create (win->gobj());
1425 	gdk_cairo_rectangle (cr, &ev->area);
1426 	cairo_clip (cr);
1427 
1428 	Glib::RefPtr<Gtk::Style> style = w->get_style();
1429 	Gdk::Color fg (style->get_fg (Gtk::STATE_NORMAL));
1430 
1431 	ArdourIcon::render (cr, icon, win->get_width (), win->get_height (), Gtkmm2ext::ExplicitActive,
1432 	                    RGBA_TO_UINT (fg.get_red() / 255., fg.get_green() / 255, fg.get_blue() / 255, 255));
1433 	cairo_destroy (cr);
1434 
1435   return true;
1436 }
1437