1c6f7d88ba619ab2df1a3406417c36cb4159813d
[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> // M_PI
22 #include <algorithm> // std:min
23 #include "gtkmm2ext/ardour_icon.h"
24
25 using namespace Gtkmm2ext::ArdourIcon;
26
27 // from libs/canvas/utils.cc and  canvas/types.h: typedef uint32_t Color;
28 static void ardour_icon_set_source_rgba (cairo_t *cr, uint32_t color)
29 {
30         cairo_set_source_rgba (cr,
31                         ((color >> 24) & 0xff) / 255.0,
32                         ((color >> 16) & 0xff) / 255.0,
33                         ((color >>  8) & 0xff) / 255.0,
34                         ((color >>  0) & 0xff) / 255.0
35                         );
36 }
37
38 static void ardour_icon_set_source_inv_rgba (cairo_t *cr, uint32_t color)
39 {
40         cairo_set_source_rgba (cr,
41                         1.0 - ((color >> 24) & 0xff) / 255.0,
42                         1.0 - ((color >> 16) & 0xff) / 255.0,
43                         1.0 - ((color >>  8) & 0xff) / 255.0,
44                         ((color >>  0) & 0xff) / 255.0
45                         );
46 }
47
48 bool
49 Gtkmm2ext::ArdourIcon::render (cairo_t *cr,
50                                const enum Gtkmm2ext::ArdourIcon::Icon icon,
51                                const int width, const int height,
52                                const Gtkmm2ext::ActiveState state,
53                                const uint32_t fg_color)
54 {
55
56 #define VECTORICONSTROKEFILL(fillalpha) \
57         cairo_set_line_width(cr, 1.5); \
58         cairo_set_source_rgba (cr, 0, 0, 0, 1.0); \
59         cairo_stroke_preserve(cr); \
60         cairo_set_source_rgba (cr, 1, 1, 1, (fillalpha)); \
61         cairo_fill(cr);
62
63 #define VECTORICONSTROKEOUTLINE(LW, color) \
64         cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); \
65         cairo_set_line_width(cr, (LW) + 1.5); \
66         ardour_icon_set_source_inv_rgba (cr, color); \
67         cairo_stroke_preserve(cr); \
68         ardour_icon_set_source_rgba (cr, color); \
69         cairo_set_line_width(cr, (LW));  \
70         cairo_stroke(cr);
71
72         switch (icon) {
73
74         case RecTapeMode:
75         {
76                 const double x = width * .5;
77                 const double y = height * .5;
78                 const double r = std::min(x, y) * .6;
79                 const double slit = .11 * M_PI;
80                 cairo_save(cr);
81                 cairo_translate(cr, x, y);
82
83                 cairo_arc (cr, 0, 0, r, 0, 2 * M_PI);
84                 if (state == Gtkmm2ext::ExplicitActive) {
85                         cairo_set_source_rgba (cr, .95, .1, .1, 1.);
86                 } else {
87                         cairo_set_source_rgba (cr, .95, .44, .44, 1.); // #f46f6f
88                 }
89                 cairo_fill_preserve(cr);
90                 cairo_set_source_rgba (cr, .0, .0, .0, .5);
91                 cairo_set_line_width(cr, 1);
92                 cairo_stroke(cr);
93
94                 cairo_save(cr);
95                 cairo_set_source_rgba (cr, .15, .07, .07, 1.0);
96
97                 cairo_rotate (cr, -.5 * M_PI);
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
103                 cairo_fill(cr);
104                 cairo_rotate (cr, 2. * M_PI / 3.);
105
106                 cairo_move_to(cr, 0, 0);
107                 cairo_arc (cr, 0, 0, r *.85, -slit, slit);
108                 cairo_line_to(cr, 0, 0);
109                 cairo_close_path(cr);
110                 cairo_fill(cr);
111
112                 cairo_rotate (cr, 2. * M_PI / 3.);
113                 cairo_move_to(cr, 0, 0);
114                 cairo_arc (cr, 0, 0, r *.85, -slit, slit);
115                 cairo_line_to(cr, 0, 0);
116                 cairo_close_path(cr);
117                 cairo_fill(cr);
118
119                 cairo_restore(cr);
120
121                 cairo_arc (cr, 0, 0, r * .3, 0, 2 * M_PI);
122                 if (state == Gtkmm2ext::ExplicitActive)
123                         cairo_set_source_rgba (cr, .95, .1, .1, 1.);
124                 else
125                         cairo_set_source_rgba (cr, .95, .44, .44, 1.); // #f46f6f
126                 cairo_fill(cr);
127                 cairo_set_source_rgba (cr, .0, .0, .0, 1.0);
128                 cairo_arc (cr, 0, 0, r *.15, 0, 2 * M_PI); // hole in the middle
129                 cairo_fill(cr);
130
131                 cairo_restore(cr);
132         }
133         break;
134         case RecButton:
135         {
136                 const double x = width * .5;
137                 const double y = height * .5;
138                 const double r = std::min(x, y) * .55;
139                 cairo_arc (cr, x, y, r, 0, 2 * M_PI);
140                 if (state == Gtkmm2ext::ExplicitActive)
141                         cairo_set_source_rgba (cr, .95, .1, .1, 1.);
142                 else
143                         cairo_set_source_rgba (cr, .95, .44, .44, 1.); // #f46f6f
144                 cairo_fill_preserve(cr);
145                 cairo_set_source_rgba (cr, .0, .0, .0, .8);
146                 cairo_set_line_width(cr, 1);
147                 cairo_stroke(cr);
148         }
149         break;
150         case CloseCross:
151         {
152                 const double x = width * .5;
153                 const double y = height * .5;
154                 const double o = .5 + std::min(x, y) * .4;
155                 ardour_icon_set_source_rgba (cr, fg_color);
156                 cairo_set_line_width(cr, 1);
157                 cairo_move_to(cr, x-o, y-o);
158                 cairo_line_to(cr, x+o, y+o);
159                 cairo_move_to(cr, x+o, y-o);
160                 cairo_line_to(cr, x-o, y+o);
161                 cairo_stroke(cr);
162         }
163         break;
164         case StripWidth:
165         {
166                 const double x0 = width  * .2;
167                 const double x1 = width  * .8;
168
169                 const double y0 = height * .25;
170                 const double y1= height  * .75;
171
172                 const double ym= height  * .5;
173
174                 // arrow
175                 const double xa0= height  * .39;
176                 const double xa1= height  * .61;
177                 const double ya0= height  * .35;
178                 const double ya1= height  * .65;
179
180                 ardour_icon_set_source_rgba (cr, fg_color);
181                 cairo_set_line_width(cr, 1);
182
183                 // left + right
184                 cairo_move_to(cr, x0, y0);
185                 cairo_line_to(cr, x0, y1);
186                 cairo_move_to(cr, x1, y0);
187                 cairo_line_to(cr, x1, y1);
188
189                 // horiz center line
190                 cairo_move_to(cr, x0, ym);
191                 cairo_line_to(cr, x1, ym);
192
193                 // arrow left
194                 cairo_move_to(cr,  x0, ym);
195                 cairo_line_to(cr, xa0, ya0);
196                 cairo_move_to(cr,  x0, ym);
197                 cairo_line_to(cr, xa0, ya1);
198
199                 // arrow right
200                 cairo_move_to(cr,  x1,  ym);
201                 cairo_line_to(cr, xa1, ya0);
202                 cairo_move_to(cr,  x1,  ym);
203                 cairo_line_to(cr, xa1, ya1);
204                 cairo_stroke(cr);
205         }
206         break;
207         case DinMidi:
208         {
209                 const double x = width * .5;
210                 const double y = height * .5;
211                 const double r = std::min(x, y) * .75;
212                 ardour_icon_set_source_rgba (cr, fg_color);
213                 cairo_set_line_width(cr, 1);
214                 cairo_arc (cr, x, y, r, .57 * M_PI, 2.43 * M_PI);
215                 cairo_stroke(cr);
216
217                 // pins equally spaced 45deg
218                 cairo_arc (cr, x, y * 0.5, r * .15, 0, 2 * M_PI);
219                 cairo_fill(cr);
220                 cairo_arc (cr, x * 0.5, y, r * .15, 0, 2 * M_PI);
221                 cairo_fill(cr);
222                 cairo_arc (cr, x * 1.5, y, r * .15, 0, 2 * M_PI);
223                 cairo_fill(cr);
224                 //  .5 + .5 * .5 * sin(45deg),  1.5 - .5 * .5 * cos(45deg)
225                 cairo_arc (cr, x * 0.677, y * .677, r * .15, 0, 2 * M_PI);
226                 cairo_fill(cr);
227                 cairo_arc (cr, x * 1.323, y * .677, r * .15, 0, 2 * M_PI);
228                 cairo_fill(cr);
229
230                 // bottom notch
231                 cairo_arc (cr, x, y+r, r * .26, 1.05 * M_PI, 1.95 * M_PI);
232                 cairo_stroke(cr);
233         }
234         break;
235         case TransportStop:
236         {
237                 const int wh = std::min (width, height);
238                 cairo_rectangle (cr,
239                                 (width - wh) * .5 + wh * .25,
240                                 (height - wh) * .5 + wh * .25,
241                                 wh * .5, wh * .5);
242
243                 VECTORICONSTROKEFILL(0.8);
244         }
245         break;
246         case TransportPlay:
247         {
248                 const int wh = std::min (width, height) * .5;
249                 const double y = height * .5;
250                 const double x = width - wh;
251
252                 const float tri = ceil(.577 * wh); // 1/sqrt(3)
253
254                 cairo_move_to (cr,  x + wh * .5, y);
255                 cairo_line_to (cr,  x - wh * .5, y - tri);
256                 cairo_line_to (cr,  x - wh * .5, y + tri);
257                 cairo_close_path (cr);
258
259                 VECTORICONSTROKEFILL(0.8);
260         }
261         break;
262         case TransportPanic:
263         {
264                 const int wh = std::min (width, height) * .1;
265                 const double xc = width * .5;
266                 const double yh = height;
267                 cairo_rectangle (cr,
268                                 xc - wh, yh *.19,
269                                 wh * 2,  yh *.41);
270                 VECTORICONSTROKEFILL(0.8);
271
272                 cairo_arc (cr, xc, yh *.75, wh, 0, 2 * M_PI);
273                 VECTORICONSTROKEFILL(0.8);
274         }
275         break;
276         case TransportStart:
277         case TransportEnd:
278         case TransportRange:
279         {
280                 // small play triangle
281                 int wh = std::min (width, height);
282                 const double y = height * .5;
283                 const double x = width - wh * .5;
284                 wh *= .18;
285                 const float tri = ceil(.577 * wh * 2); // 1/sqrt(3)
286
287                 const float ln = std::min (width, height) * .07;
288
289                 if (icon == TransportStart || icon == 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 == TransportEnd || icon == TransportRange) {
298                         cairo_rectangle (cr,
299                                         x + wh - ln, y  - tri * 1.7,
300                                         ln * 2,  tri * 3.4);
301
302                         VECTORICONSTROKEFILL(1.0);
303                 }
304
305                 if (icon == TransportStart) {
306                         cairo_move_to (cr,  x - wh, y);
307                         cairo_line_to (cr,  x + wh, y - tri);
308                         cairo_line_to (cr,  x + wh, y + tri);
309                 } else {
310                         cairo_move_to (cr,  x + wh, y);
311                         cairo_line_to (cr,  x - wh, y - tri);
312                         cairo_line_to (cr,  x - wh, y + tri);
313                 }
314
315                 cairo_close_path (cr);
316                 VECTORICONSTROKEFILL(1.0);
317         }
318         break;
319         case TransportLoop:
320         {
321                 const double x = width * .5;
322                 const double y = height * .5;
323                 const double r = std::min(x, y);
324
325                 cairo_arc          (cr, x, y, r * .62, 0, 2 * M_PI);
326                 cairo_arc_negative (cr, x, y, r * .35, 2 * M_PI, 0);
327
328                 VECTORICONSTROKEFILL(1.0);
329 #define ARCARROW(rad, ang) \
330                 x + (rad) * sin((ang) * 2.0 * M_PI), y + (rad) * cos((ang) * 2.0 * M_PI)
331
332                 cairo_move_to (cr, ARCARROW(r * .35, .72));
333                 cairo_line_to (cr, ARCARROW(r * .15, .72));
334                 cairo_line_to (cr, ARCARROW(r * .56, .60));
335                 cairo_line_to (cr, ARCARROW(r * .75, .72));
336                 cairo_line_to (cr, ARCARROW(r * .62, .72));
337
338                 cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
339                 cairo_stroke_preserve(cr);
340                 cairo_close_path (cr);
341                 cairo_set_source_rgba (cr, 1, 1, 1, 1.0);
342                 cairo_fill(cr);
343 #undef ARCARROW
344         }
345         break;
346         case TransportMetronom:
347         {
348                 const double x  = width * .5;
349                 const double y  = height * .5;
350                 const double wh = std::min(x, y);
351                 const double h  = wh * .85;
352                 const double w  = wh * .55;
353                 const double lw = w  * .34;
354
355                 cairo_rectangle (cr,
356                                 x - w * .7, y + h * .25,
357                                 w * 1.4, lw);
358
359                 VECTORICONSTROKEFILL(1.0);
360
361                 cairo_move_to (cr,  x - w,       y + h);
362                 cairo_line_to (cr,  x + w,       y + h);
363                 cairo_line_to (cr,  x + w * .35, y - h);
364                 cairo_line_to (cr,  x - w * .35, y - h);
365                 cairo_line_to (cr,  x - w,       y + h);
366
367                 cairo_move_to (cr,  x - w + lw,       y + h -lw);
368                 cairo_line_to (cr,  x - w * .35 + lw, y - h + lw);
369                 cairo_line_to (cr,  x + w * .35 - lw, y - h + lw);
370                 cairo_line_to (cr,  x + w - lw,       y + h -lw);
371                 cairo_line_to (cr,  x - w + lw,       y + h -lw);
372
373                 VECTORICONSTROKEFILL(1.0);
374
375                 // ddx = .70 w      = .75 * .5 wh              = .375 wh
376                 // ddy = .75 h - lw = .75 * .8 wh - wh .5 * .2 = .5 wh
377                 // ang = (ddx/ddy):
378                 // -> angle = atan (ang) = atan (375 / .5) ~= 36deg
379                 const double dx = lw * .2;  // 1 - cos(tan^-1(ang))
380                 const double dy = lw * .4;  // 1 - sin(tan^-1(ang))
381                 cairo_move_to (cr,  x - w * .3     , y + h * .25 + lw * .5);
382                 cairo_line_to (cr,  x - w + dx     , y - h + lw + dy);
383                 cairo_line_to (cr,  x - w + lw     , y - h + lw);
384                 cairo_line_to (cr,  x - w * .3 + lw, y + h * .25 + lw * .5);
385                 cairo_close_path (cr);
386
387                 VECTORICONSTROKEFILL(1.0);
388
389                 cairo_rectangle (cr,
390                                 x - w * .7, y + h * .25,
391                                 w * 1.4, lw);
392                 cairo_fill(cr);
393         }
394         break;
395         case NudgeLeft:
396         {
397                 const double x = width * .5;
398                 const double y = height * .5;
399                 const double wh = std::min (x, y);
400
401                 const double tri_x = .3 * wh;
402                 const double tri_y = .6 * wh;
403
404                 cairo_move_to (cr, x + tri_x, y - tri_y);
405                 cairo_line_to (cr, x - tri_x, y);
406                 cairo_line_to (cr, x + tri_x, y + tri_y);
407                 VECTORICONSTROKEOUTLINE(1.5, fg_color);
408         }
409         break;
410         case NudgeRight:
411         {
412
413                 const double x = width * .5;
414                 const double y = height * .5;
415                 const double wh = std::min (x, y);
416
417                 const double tri_x = .3 * wh;
418                 const double tri_y = .6 * wh;
419
420                 cairo_move_to (cr, x - tri_x, y - tri_y);
421                 cairo_line_to (cr, x + tri_x, y);
422                 cairo_line_to (cr, x - tri_x, y + tri_y);
423                 VECTORICONSTROKEOUTLINE(1.5, fg_color);
424
425         }
426         break;
427         case ZoomIn:
428         case ZoomOut:
429         case ZoomFull:
430         {
431                 const double x = width * .5;
432                 const double y = height * .5;
433                 const double r = std::min (x, y) * .7;
434                 const double wh = std::min (x, y) * .45;
435
436                 // draw handle first
437 #define LINE45DEG(rad) \
438                 x + r * (rad) * .707, y + r * (rad) * .707 // sin(45deg) = cos(45deg) = .707
439                 cairo_move_to (cr, LINE45DEG(.9));
440                 cairo_line_to (cr, LINE45DEG(1.3));
441                 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
442                 cairo_set_line_width (cr, 3.0);
443                 cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
444                 cairo_stroke (cr);
445 #undef LINE45DEG
446
447                 // lens
448                 ardour_icon_set_source_rgba (cr, fg_color);
449                 cairo_arc (cr, x, y, r, 0, 2 * M_PI);
450                 cairo_fill_preserve (cr);
451
452                 // add a lens gradient
453                 cairo_pattern_t *lens;
454                 lens = cairo_pattern_create_radial (x - r, y - r, r * .5, x - r, y - r, r * 2);
455                 cairo_pattern_add_color_stop_rgba (lens, 0, 1, 1, 1, .4);
456                 cairo_pattern_add_color_stop_rgba (lens, 1, 0, 0, 0, .4);
457                 cairo_set_source (cr, lens);
458                 cairo_fill_preserve (cr);
459                 cairo_pattern_destroy (lens);
460
461                 // outline
462                 cairo_set_line_width (cr, 1.5);
463                 //ardour_icon_set_source_inv_rgba (cr, fg_color); // alpha
464                 cairo_set_source_rgba (cr, .0, .0, .0, .8);
465                 cairo_stroke (cr);
466
467                 // add "+", "-" or "[]"
468                 cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
469                 cairo_set_line_width (cr, 1.5);
470                 ardour_icon_set_source_inv_rgba (cr, fg_color);
471
472                 if (icon == ZoomIn || icon == ZoomOut) {
473                         cairo_move_to (cr, x - wh, y);
474                         cairo_line_to (cr, x + wh, y);
475                         cairo_stroke (cr);
476                 }
477                 if (icon == ZoomIn) {
478                         cairo_move_to (cr, x, y - wh);
479                         cairo_line_to (cr, x, y + wh);
480                         cairo_stroke (cr);
481                 }
482                 if (icon == ZoomFull) {
483                         const double br0 = std::min (x, y) * .1;
484                         const double br1 = std::min (x, y) * .3;
485                         const double bry = std::min (x, y) * .3;
486                         cairo_move_to (cr, x - br0, y - bry);
487                         cairo_line_to (cr, x - br1, y - bry);
488                         cairo_line_to (cr, x - br1, y + bry);
489                         cairo_line_to (cr, x - br0, y + bry);
490                         cairo_stroke (cr);
491
492                         cairo_move_to (cr, x + br0, y - bry);
493                         cairo_line_to (cr, x + br1, y - bry);
494                         cairo_line_to (cr, x + br1, y + bry);
495                         cairo_line_to (cr, x + br0, y + bry);
496                         cairo_stroke (cr);
497                 }
498         }
499         break;
500         case TimeAxisShrink:
501         {
502                 const double x = width * .5;
503                 const double y = height * .5;
504                 const double wh = std::min (x, y) * .66;
505                 const double ar = std::min (x, y) * .15;
506                 const double tri = .7 * (wh - ar);
507
508                 cairo_rectangle (cr, x - wh, y - ar, 2 * wh, 2 * ar);
509                 VECTORICONSTROKEFILL(.75);
510
511                 cairo_set_line_width(cr, 1.0);
512
513                 cairo_move_to (cr, x,       y - ar - 0.5);
514                 cairo_line_to (cr, x - tri, y - wh + 0.5);
515                 cairo_line_to (cr, x + tri, y - wh + 0.5);
516                 cairo_close_path (cr);
517
518                 cairo_set_source_rgba (cr, 1, 1, 1, .75);
519                 cairo_stroke_preserve(cr);
520                 cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
521                 cairo_fill(cr);
522
523                 cairo_move_to (cr, x,       y + ar + 0.5);
524                 cairo_line_to (cr, x - tri, y + wh - 0.5);
525                 cairo_line_to (cr, x + tri, y + wh - 0.5);
526                 cairo_close_path (cr);
527
528                 cairo_set_source_rgba (cr, 1, 1, 1, .75);
529                 cairo_stroke_preserve(cr);
530                 cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
531                 cairo_fill(cr);
532         }
533         break;
534         case TimeAxisExpand:
535         {
536                 const double x = width * .5;
537                 const double y = height * .5;
538                 const double wh = std::min (x, y) * .66;
539                 const double ar = std::min (x, y) * .15;
540                 const double tri = .7 * (wh - ar);
541
542                 cairo_rectangle (cr, x - wh, y - wh, 2 * wh, 2 * wh);
543                 VECTORICONSTROKEFILL(.75);
544
545                 cairo_set_line_width(cr, 1.0);
546
547                 cairo_move_to (cr, x,       y - wh + 0.5);
548                 cairo_line_to (cr, x - tri, y - ar - 0.5);
549                 cairo_line_to (cr, x + tri, y - ar - 0.5);
550                 cairo_close_path (cr);
551
552                 cairo_set_source_rgba (cr, 1, 1, 1, .5);
553                 cairo_stroke_preserve(cr);
554                 cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
555                 cairo_fill(cr);
556
557                 cairo_move_to (cr, x      , y + wh - 0.5);
558                 cairo_line_to (cr, x - tri, y + ar + 0.5);
559                 cairo_line_to (cr, x + tri, y + ar + 0.5);
560                 cairo_close_path (cr);
561
562                 cairo_set_source_rgba (cr, 1, 1, 1, .5);
563                 cairo_stroke_preserve(cr);
564                 cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
565                 cairo_fill(cr);
566         }
567         break;
568         case ToolRange:
569         {
570                 const double x  = width * .5;
571                 const double y  = height * .5;
572                 const double wh = std::min (x, y) * .6;
573                 const double lw = wh / 6.0; // line width (1px with 20x20 button)
574                 const double ar = wh * .5; // arrow
575                 const double ym = rint (y - wh * .1) + .5; // slightly to the top, on a px
576
577                 const double x0 = x - wh;
578                 const double x1 = x + wh;
579
580                 cairo_rectangle (cr,
581                                 x - wh - lw,
582                                 y - wh,
583                                 lw,  2 * wh);
584
585                 VECTORICONSTROKEFILL(1.0);
586
587                 cairo_rectangle (cr,
588                                 x + wh,
589                                 y - wh,
590                                 lw,  2 * wh);
591
592                 VECTORICONSTROKEFILL(1.0);
593
594                 cairo_save (cr);
595
596                 // don't draw outline inside the boxes
597                 cairo_rectangle (cr, x0, y - wh,
598                                 2 * wh, 2 * wh);
599                 cairo_clip (cr);
600
601                 // arrow
602                 cairo_move_to (cr, x0 + ar, ym - ar);
603                 cairo_line_to (cr, x0, ym);
604                 cairo_line_to (cr, x0 + ar, ym + ar);
605
606                 cairo_move_to (cr, x1 - ar, ym - ar);
607                 cairo_line_to (cr, x1, ym);
608                 cairo_line_to (cr, x1 - ar, ym + ar);
609
610                 cairo_move_to (cr, x0, ym);
611                 cairo_line_to (cr, x1, ym);
612                 VECTORICONSTROKEOUTLINE(lw, 0xffffffff);
613
614                 cairo_restore (cr);
615         }
616         break;
617         case ToolGrab:
618         {
619                 const double x  = width * .5;
620                 const double y  = height * .5;
621                 const double em = std::min (x, y) * .15; // 3px at 20x20
622
623                 // 6x8em hand, with 'em' wide index finger.
624 #define EM_POINT(X,Y) \
625                 x + (X) * em, y + (Y) * em
626
627                 // wrist
628                 cairo_move_to (cr, EM_POINT( 2.0,  4.0));
629                 cairo_line_to (cr, EM_POINT(-1.5,  4.0));
630                 cairo_line_to (cr, EM_POINT(-2.5,  2.0));
631                 // thumb
632                 cairo_line_to (cr, EM_POINT(-3.0,  1.0));
633
634                 // index finger
635                 cairo_line_to (cr, EM_POINT(-2.0,  0.0));
636                 cairo_line_to (cr, EM_POINT(-2.1, -4.0));
637                 cairo_line_to (cr, EM_POINT(-1.5, -4.5));
638                 cairo_line_to (cr, EM_POINT(-1.1, -4.0));
639                 cairo_line_to (cr, EM_POINT(-1.0,  0.1));
640
641                 // middle finger knuckle
642                 cairo_line_to (cr, EM_POINT(-0.8,  0.0));
643                 cairo_line_to (cr, EM_POINT( 0.3, -0.4));
644                 cairo_line_to (cr, EM_POINT( 0.4, -0.6));
645                 cairo_line_to (cr, EM_POINT( 0.5, -0.4));
646                 cairo_line_to (cr, EM_POINT( 0.5,  0.1));
647
648                 // ring finger knuckle
649                 cairo_line_to (cr, EM_POINT( 1.0,  0.2));
650                 cairo_line_to (cr, EM_POINT( 1.4, -0.3));
651                 cairo_line_to (cr, EM_POINT( 1.5, -0.5));
652                 cairo_line_to (cr, EM_POINT( 1.6, -0.3));
653                 cairo_line_to (cr, EM_POINT( 1.6,  0.3));
654
655                 // pinky
656                 cairo_line_to (cr, EM_POINT( 2.0,  0.5));
657                 cairo_line_to (cr, EM_POINT( 2.5,  0.1));
658                 cairo_line_to (cr, EM_POINT( 2.6,  0.0));
659                 cairo_line_to (cr, EM_POINT( 2.7,  0.1));
660                 cairo_line_to (cr, EM_POINT( 3.0,  1.0));
661
662                 // wrist
663                 cairo_line_to (cr, EM_POINT( 3.0,  1.5));
664                 cairo_line_to (cr, EM_POINT( 2.0,  4.0));
665
666                 cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
667                 cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
668                 VECTORICONSTROKEFILL(1.0);
669         }
670         break;
671         default:
672                 return false;
673         } // end switch (icon)
674
675 #undef VECTORICONSTROKEFILL
676 #undef VECTORICONSTROKEOUTLINE
677         return true;
678 }