36b0b3c38708d6f5e29449f8789b08cecd2cd99a
[ardour.git] / libs / gtkmm2ext / ardour_icon.cc
1 /*
2     Copyright (C) 2009 Paul Davis
3     Copyright (C) 2015 Robin Gareus <robin@gareus.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19 */
20
21 #include <math.h> // For M_PI
22 #include <algorithm>
23 #include "gtkmm2ext/ardour_icon.h"
24
25 // "canvas/types.h" Color == uint32_t
26 // from libs/canvas/utils.cc
27 static void ardour_canvas_set_source_rgba (cairo_t *cr, uint32_t color)
28 {
29         cairo_set_source_rgba ( cr,
30                         ((color >> 24) & 0xff) / 255.0,
31                         ((color >> 16) & 0xff) / 255.0,
32                         ((color >>  8) & 0xff) / 255.0,
33                         ((color >>  0) & 0xff) / 255.0
34                         );
35 }
36
37 bool
38 Gtkmm2ext::ArdourIcon::render (cairo_t *cr,
39                                const enum Gtkmm2ext::ArdourIcon::Icon icon,
40                                const int width, const int height,
41                                const Gtkmm2ext::ActiveState state,
42                                const uint32_t fg_color)
43 {
44
45 #define VECTORICONSTROKEFILL(fillalpha) \
46         cairo_set_line_width(cr, 1.5); \
47         cairo_set_source_rgba (cr, 0, 0, 0, 1.0); \
48         cairo_stroke_preserve(cr); \
49         cairo_set_source_rgba (cr, 1, 1, 1, (fillalpha)); \
50         cairo_fill(cr);
51
52 #define VECTORICONSTROKEOUTLINE() \
53         cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); \
54         cairo_set_line_width(cr, 3.0); \
55         cairo_set_source_rgba (cr, 0, 0, 0, 1.0); \
56         cairo_stroke_preserve(cr); \
57         ardour_canvas_set_source_rgba (cr, fg_color); \
58         cairo_set_line_width(cr, 1.5);  \
59         cairo_stroke(cr);
60
61
62         /* TODO separate these into dedicated class
63          * it may also be efficient to render them only once for every size (image-surface) */
64         switch (icon) {
65
66         case Gtkmm2ext::ArdourIcon::RecTapeMode:
67         {
68                 const double x = width * .5;
69                 const double y = height * .5;
70                 const double r = std::min(x, y) * .6;
71                 const double slit = .11 * M_PI;
72                 cairo_save(cr);
73                 cairo_translate(cr, x, y);
74
75                 cairo_arc (cr, 0, 0, r, 0, 2 * M_PI);
76                 if (state == Gtkmm2ext::ExplicitActive) {
77                         cairo_set_source_rgba (cr, .95, .1, .1, 1.);
78                 } else {
79                         cairo_set_source_rgba (cr, .95, .44, .44, 1.); // #f46f6f
80                 }
81                 cairo_fill_preserve(cr);
82                 cairo_set_source_rgba (cr, .0, .0, .0, .5);
83                 cairo_set_line_width(cr, 1);
84                 cairo_stroke(cr);
85
86                 cairo_save(cr);
87                 cairo_set_source_rgba (cr, .15, .07, .07, 1.0);
88
89                 cairo_rotate (cr, -.5 * M_PI);
90                 cairo_move_to(cr, 0, 0);
91                 cairo_arc (cr, 0, 0, r *.85, -slit, slit);
92                 cairo_line_to(cr, 0, 0);
93                 cairo_close_path(cr);
94
95                 cairo_fill(cr);
96                 cairo_rotate (cr, 2. * M_PI / 3.);
97
98                 cairo_move_to(cr, 0, 0);
99                 cairo_arc (cr, 0, 0, r *.85, -slit, slit);
100                 cairo_line_to(cr, 0, 0);
101                 cairo_close_path(cr);
102                 cairo_fill(cr);
103
104                 cairo_rotate (cr, 2. * M_PI / 3.);
105                 cairo_move_to(cr, 0, 0);
106                 cairo_arc (cr, 0, 0, r *.85, -slit, slit);
107                 cairo_line_to(cr, 0, 0);
108                 cairo_close_path(cr);
109                 cairo_fill(cr);
110
111                 cairo_restore(cr);
112
113                 cairo_arc (cr, 0, 0, r * .3, 0, 2 * M_PI);
114                 if (state == Gtkmm2ext::ExplicitActive)
115                         cairo_set_source_rgba (cr, .95, .1, .1, 1.);
116                 else
117                         cairo_set_source_rgba (cr, .95, .44, .44, 1.); // #f46f6f
118                 cairo_fill(cr);
119                 cairo_set_source_rgba (cr, .0, .0, .0, 1.0);
120                 cairo_arc (cr, 0, 0, r *.15, 0, 2 * M_PI); // hole in the middle
121                 cairo_fill(cr);
122
123                 cairo_restore(cr);
124         }
125         break;
126         case Gtkmm2ext::ArdourIcon::RecButton:
127         {
128                 const double x = width * .5;
129                 const double y = height * .5;
130                 const double r = std::min(x, y) * .55;
131                 cairo_arc (cr, x, y, r, 0, 2 * M_PI);
132                 if (state == Gtkmm2ext::ExplicitActive)
133                         cairo_set_source_rgba (cr, .95, .1, .1, 1.);
134                 else
135                         cairo_set_source_rgba (cr, .95, .44, .44, 1.); // #f46f6f
136                 cairo_fill_preserve(cr);
137                 cairo_set_source_rgba (cr, .0, .0, .0, .8);
138                 cairo_set_line_width(cr, 1);
139                 cairo_stroke(cr);
140         }
141         break;
142         case Gtkmm2ext::ArdourIcon::CloseCross:
143         {
144                 const double x = width * .5;
145                 const double y = height * .5;
146                 const double o = .5 + std::min(x, y) * .4;
147                 ardour_canvas_set_source_rgba (cr, fg_color);
148                 cairo_set_line_width(cr, 1);
149                 cairo_move_to(cr, x-o, y-o);
150                 cairo_line_to(cr, x+o, y+o);
151                 cairo_move_to(cr, x+o, y-o);
152                 cairo_line_to(cr, x-o, y+o);
153                 cairo_stroke(cr);
154         }
155         break;
156         case Gtkmm2ext::ArdourIcon::StripWidth:
157         {
158                 const double x0 = width  * .2;
159                 const double x1 = width  * .8;
160
161                 const double y0 = height * .25;
162                 const double y1= height  * .75;
163
164                 const double ym= height  * .5;
165
166                 // arrow
167                 const double xa0= height  * .39;
168                 const double xa1= height  * .61;
169                 const double ya0= height  * .35;
170                 const double ya1= height  * .65;
171
172                 ardour_canvas_set_source_rgba (cr, fg_color);
173                 cairo_set_line_width(cr, 1);
174
175                 // left + right
176                 cairo_move_to(cr, x0, y0);
177                 cairo_line_to(cr, x0, y1);
178                 cairo_move_to(cr, x1, y0);
179                 cairo_line_to(cr, x1, y1);
180
181                 // horiz center line
182                 cairo_move_to(cr, x0, ym);
183                 cairo_line_to(cr, x1, ym);
184
185                 // arrow left
186                 cairo_move_to(cr,  x0, ym);
187                 cairo_line_to(cr, xa0, ya0);
188                 cairo_move_to(cr,  x0, ym);
189                 cairo_line_to(cr, xa0, ya1);
190
191                 // arrow right
192                 cairo_move_to(cr,  x1,  ym);
193                 cairo_line_to(cr, xa1, ya0);
194                 cairo_move_to(cr,  x1,  ym);
195                 cairo_line_to(cr, xa1, ya1);
196                 cairo_stroke(cr);
197         }
198         break;
199         case Gtkmm2ext::ArdourIcon::DinMidi:
200         {
201                 const double x = width * .5;
202                 const double y = height * .5;
203                 const double r = std::min(x, y) * .75;
204                 ardour_canvas_set_source_rgba (cr, fg_color);
205                 cairo_set_line_width(cr, 1);
206                 cairo_arc (cr, x, y, r, .57 * M_PI, 2.43 * M_PI);
207                 cairo_stroke(cr);
208
209                 // pins equally spaced 45deg
210                 cairo_arc (cr, x, y * 0.5, r * .15, 0, 2 * M_PI);
211                 cairo_fill(cr);
212                 cairo_arc (cr, x * 0.5, y, r * .15, 0, 2 * M_PI);
213                 cairo_fill(cr);
214                 cairo_arc (cr, x * 1.5, y, r * .15, 0, 2 * M_PI);
215                 cairo_fill(cr);
216                 //  .5 + .5 * .5 * sin(45deg),  1.5 - .5 * .5 * cos(45deg)
217                 cairo_arc (cr, x * 0.677, y * .677, r * .15, 0, 2 * M_PI);
218                 cairo_fill(cr);
219                 cairo_arc (cr, x * 1.323, y * .677, r * .15, 0, 2 * M_PI);
220                 cairo_fill(cr);
221
222                 // bottom notch
223                 cairo_arc (cr, x, y+r, r * .26, 1.05 * M_PI, 1.95 * M_PI);
224                 cairo_stroke(cr);
225         }
226         break;
227         case Gtkmm2ext::ArdourIcon::TransportStop:
228         {
229                 const int wh = std::min (width, height);
230                 cairo_rectangle (cr,
231                                 (width - wh) * .5 + wh * .25,
232                                 (height - wh) * .5 + wh * .25,
233                                 wh * .5, wh * .5);
234
235                 VECTORICONSTROKEFILL(0.8);
236         }
237         break;
238         case Gtkmm2ext::ArdourIcon::TransportPlay:
239         {
240                 const int wh = std::min (width, height) * .5;
241                 const double y = height * .5;
242                 const double x = width - wh;
243
244                 const float tri = ceil(.577 * wh); // 1/sqrt(3)
245
246                 cairo_move_to (cr,  x + wh * .5, y);
247                 cairo_line_to (cr,  x - wh * .5, y - tri);
248                 cairo_line_to (cr,  x - wh * .5, y + tri);
249                 cairo_close_path (cr);
250
251                 VECTORICONSTROKEFILL(0.8);
252         }
253         break;
254         case Gtkmm2ext::ArdourIcon::TransportPanic:
255         {
256                 const int wh = std::min (width, height) * .1;
257                 const double xc = width * .5;
258                 const double yh = height;
259                 cairo_rectangle (cr,
260                                 xc - wh, yh *.19,
261                                 wh * 2,  yh *.41);
262                 VECTORICONSTROKEFILL(0.8);
263
264                 cairo_arc (cr, xc, yh *.75, wh, 0, 2 * M_PI);
265                 VECTORICONSTROKEFILL(0.8);
266         }
267         break;
268         case Gtkmm2ext::ArdourIcon::TransportStart:
269         case Gtkmm2ext::ArdourIcon::TransportEnd:
270         case Gtkmm2ext::ArdourIcon::TransportRange:
271         {
272                 // small play triangle
273                 int wh = std::min (width, height);
274                 const double y = height * .5;
275                 const double x = width - wh * .5;
276                 wh *= .18;
277                 const float tri = ceil(.577 * wh * 2); // 1/sqrt(3)
278
279                 const float ln = std::min (width, height) * .07;
280
281                 if (icon == Gtkmm2ext::ArdourIcon::TransportStart || icon == Gtkmm2ext::ArdourIcon::TransportRange) {
282                         cairo_rectangle (cr,
283                                         x - wh - ln, y  - tri * 1.7,
284                                         ln * 2,  tri * 3.4);
285
286                         VECTORICONSTROKEFILL(1.0);
287                 }
288
289                 if (icon == Gtkmm2ext::ArdourIcon::TransportEnd || icon == Gtkmm2ext::ArdourIcon::TransportRange) {
290                         cairo_rectangle (cr,
291                                         x + wh - ln, y  - tri * 1.7,
292                                         ln * 2,  tri * 3.4);
293
294                         VECTORICONSTROKEFILL(1.0);
295                 }
296
297                 if (icon == Gtkmm2ext::ArdourIcon::TransportStart) {
298                         cairo_move_to (cr,  x - wh, y);
299                         cairo_line_to (cr,  x + wh, y - tri);
300                         cairo_line_to (cr,  x + wh, y + tri);
301                 } else {
302                         cairo_move_to (cr,  x + wh, y);
303                         cairo_line_to (cr,  x - wh, y - tri);
304                         cairo_line_to (cr,  x - wh, y + tri);
305                 }
306
307                 cairo_close_path (cr);
308                 VECTORICONSTROKEFILL(1.0);
309         }
310         break;
311         case Gtkmm2ext::ArdourIcon::TransportLoop:
312         {
313                 const double x = width * .5;
314                 const double y = height * .5;
315                 const double r = std::min(x, y);
316
317                 cairo_arc          (cr, x, y, r * .62, 0, 2 * M_PI);
318                 cairo_arc_negative (cr, x, y, r * .35, 2 * M_PI, 0);
319
320                 VECTORICONSTROKEFILL(1.0);
321 #define ARCARROW(rad, ang) \
322                 x + (rad) * sin((ang) * 2.0 * M_PI), y + (rad) * cos((ang) * 2.0 * M_PI)
323
324                 cairo_move_to (cr, ARCARROW(r * .35, .72));
325                 cairo_line_to (cr, ARCARROW(r * .15, .72));
326                 cairo_line_to (cr, ARCARROW(r * .56, .60));
327                 cairo_line_to (cr, ARCARROW(r * .75, .72));
328                 cairo_line_to (cr, ARCARROW(r * .62, .72));
329
330                 cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
331                 cairo_stroke_preserve(cr);
332                 cairo_close_path (cr);
333                 cairo_set_source_rgba (cr, 1, 1, 1, 1.0);
334                 cairo_fill(cr);
335 #undef ARCARROW
336         }
337         break;
338         case Gtkmm2ext::ArdourIcon::TransportMetronom:
339         {
340                 const double x  = width * .5;
341                 const double y  = height * .5;
342                 const double wh = std::min(x, y);
343                 const double h  = wh * .85;
344                 const double w  = wh * .55;
345                 const double lw = w  * .34;
346
347                 cairo_rectangle (cr,
348                                 x - w * .7, y + h * .25,
349                                 w * 1.4, lw);
350
351                 VECTORICONSTROKEFILL(1.0);
352
353                 cairo_move_to (cr,  x - w,       y + h);
354                 cairo_line_to (cr,  x + w,       y + h);
355                 cairo_line_to (cr,  x + w * .35, y - h);
356                 cairo_line_to (cr,  x - w * .35, y - h);
357                 cairo_line_to (cr,  x - w,       y + h);
358
359                 cairo_move_to (cr,  x - w + lw,       y + h -lw);
360                 cairo_line_to (cr,  x - w * .35 + lw, y - h + lw);
361                 cairo_line_to (cr,  x + w * .35 - lw, y - h + lw);
362                 cairo_line_to (cr,  x + w - lw,       y + h -lw);
363                 cairo_line_to (cr,  x - w + lw,       y + h -lw);
364
365                 VECTORICONSTROKEFILL(1.0);
366
367                 // ddx = .70 w      = .75 * .5 wh              = .375 wh
368                 // ddy = .75 h - lw = .75 * .8 wh - wh .5 * .2 = .5 wh
369                 // ang = (ddx/ddy):
370                 // -> angle = atan (ang) = atan (375 / .5) ~= 36deg
371                 const double dx = lw * .2;  // 1 - cos(tan^-1(ang))
372                 const double dy = lw * .4;  // 1 - sin(tan^-1(ang))
373                 cairo_move_to (cr,  x - w * .3     , y + h * .25 + lw * .5);
374                 cairo_line_to (cr,  x - w + dx     , y - h + lw + dy);
375                 cairo_line_to (cr,  x - w + lw     , y - h + lw);
376                 cairo_line_to (cr,  x - w * .3 + lw, y + h * .25 + lw * .5);
377                 cairo_close_path (cr);
378
379                 VECTORICONSTROKEFILL(1.0);
380
381                 cairo_rectangle (cr,
382                                 x - w * .7, y + h * .25,
383                                 w * 1.4, lw);
384                 cairo_fill(cr);
385         }
386         break;
387         case Gtkmm2ext::ArdourIcon::NudgeLeft:
388         {
389                 const double x = width * .5;
390                 const double y = height * .5;
391                 const double wh = std::min (x, y);
392
393                 const double tri_x = .3 * wh;
394                 const double tri_y = .6 * wh;
395
396                 cairo_move_to (cr, x + tri_x, y - tri_y);
397                 cairo_line_to (cr, x - tri_x, y);
398                 cairo_line_to (cr, x + tri_x, y + tri_y);
399                 VECTORICONSTROKEOUTLINE();
400         }
401         break;
402         case Gtkmm2ext::ArdourIcon::NudgeRight:
403         {
404
405                 const double x = width * .5;
406                 const double y = height * .5;
407                 const double wh = std::min (x, y);
408
409                 const double tri_x = .3 * wh;
410                 const double tri_y = .6 * wh;
411
412                 cairo_move_to (cr, x - tri_x, y - tri_y);
413                 cairo_line_to (cr, x + tri_x, y);
414                 cairo_line_to (cr, x - tri_x, y + tri_y);
415                 VECTORICONSTROKEOUTLINE();
416
417         }
418         break;
419         default:
420                 return false;
421         } // end case(icon)
422
423 #undef VECTORICONSTROKEFILL
424 #undef VECTORICONSTROKEOUTLINE
425         return true;
426 }
427
428