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