1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpcanvas-style.c
5  * Copyright (C) 2010  Michael Natterer <mitch@gimp.org>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include <gegl.h>
24 #include <gtk/gtk.h>
25 
26 #include "libgimpcolor/gimpcolor.h"
27 #include "libgimpwidgets/gimpwidgets.h"
28 
29 #include "display-types.h"
30 
31 #include "core/gimp-cairo.h"
32 #include "core/gimpgrid.h"
33 #include "core/gimplayer.h"
34 
35 #include "gimpcanvas-style.h"
36 
37 /* Styles for common and custom guides. */
38 static const GimpRGB guide_normal_fg         = { 0.0, 0.0, 0.0, 1.0 };
39 static const GimpRGB guide_normal_bg         = { 0.0, 0.8, 1.0, 1.0 };
40 static const GimpRGB guide_active_fg         = { 0.0, 0.0, 0.0, 1.0 };
41 static const GimpRGB guide_active_bg         = { 1.0, 0.0, 0.0, 1.0 };
42 
43 static const GimpRGB guide_mirror_normal_fg  = { 1.0, 1.0, 1.0, 1.0 };
44 static const GimpRGB guide_mirror_normal_bg  = { 0.0, 1.0, 0.0, 1.0 };
45 static const GimpRGB guide_mirror_active_fg  = { 0.0, 1.0, 0.0, 1.0 };
46 static const GimpRGB guide_mirror_active_bg  = { 1.0, 0.0, 0.0, 1.0 };
47 
48 static const GimpRGB guide_mandala_normal_fg = { 1.0, 1.0, 1.0, 1.0 };
49 static const GimpRGB guide_mandala_normal_bg = { 0.0, 1.0, 1.0, 1.0 };
50 static const GimpRGB guide_mandala_active_fg = { 0.0, 1.0, 1.0, 1.0 };
51 static const GimpRGB guide_mandala_active_bg = { 1.0, 0.0, 0.0, 1.0 };
52 
53 static const GimpRGB guide_split_normal_fg   = { 1.0, 1.0, 1.0, 1.0 };
54 static const GimpRGB guide_split_normal_bg   = { 1.0, 0.0, 1.0, 1.0 };
55 static const GimpRGB guide_split_active_fg   = { 1.0, 0.0, 1.0, 1.0 };
56 static const GimpRGB guide_split_active_bg   = { 1.0, 0.0, 0.0, 1.0 };
57 
58 /* Styles for other canvas items. */
59 static const GimpRGB sample_point_normal = { 0.0, 0.8, 1.0, 1.0 };
60 static const GimpRGB sample_point_active = { 1.0, 0.0, 0.0, 1.0 };
61 
62 static const GimpRGB layer_fg            = { 0.0, 0.0, 0.0, 1.0 };
63 static const GimpRGB layer_bg            = { 1.0, 1.0, 0.0, 1.0 };
64 
65 static const GimpRGB layer_group_fg      = { 0.0, 0.0, 0.0, 1.0 };
66 static const GimpRGB layer_group_bg      = { 0.0, 1.0, 1.0, 1.0 };
67 
68 static const GimpRGB layer_mask_fg       = { 0.0, 0.0, 0.0, 1.0 };
69 static const GimpRGB layer_mask_bg       = { 0.0, 1.0, 0.0, 1.0 };
70 
71 static const GimpRGB canvas_fg           = { 0.0, 0.0, 0.0, 1.0 };
72 static const GimpRGB canvas_bg           = { 1.0, 0.5, 0.0, 1.0 };
73 
74 static const GimpRGB selection_out_fg    = { 1.0, 1.0, 1.0, 1.0 };
75 static const GimpRGB selection_out_bg    = { 0.5, 0.5, 0.5, 1.0 };
76 
77 static const GimpRGB selection_in_fg     = { 0.0, 0.0, 0.0, 1.0 };
78 static const GimpRGB selection_in_bg     = { 1.0, 1.0, 1.0, 1.0 };
79 
80 static const GimpRGB vectors_normal_bg   = { 1.0, 1.0, 1.0, 0.6 };
81 static const GimpRGB vectors_normal_fg   = { 0.0, 0.0, 1.0, 0.8 };
82 
83 static const GimpRGB vectors_active_bg   = { 1.0, 1.0, 1.0, 0.6 };
84 static const GimpRGB vectors_active_fg   = { 1.0, 0.0, 0.0, 0.8 };
85 
86 static const GimpRGB outline_bg          = { 1.0, 1.0, 1.0, 0.6 };
87 static const GimpRGB outline_fg          = { 0.0, 0.0, 0.0, 0.8 };
88 
89 static const GimpRGB passe_partout       = { 0.0, 0.0, 0.0, 1.0 };
90 
91 static const GimpRGB tool_bg             = { 0.0, 0.0, 0.0, 0.4 };
92 static const GimpRGB tool_fg             = { 1.0, 1.0, 1.0, 0.8 };
93 static const GimpRGB tool_fg_highlight   = { 1.0, 0.8, 0.2, 0.8 };
94 
95 
96 /*  public functions  */
97 
98 void
gimp_canvas_set_guide_style(GtkWidget * canvas,cairo_t * cr,GimpGuideStyle style,gboolean active,gdouble offset_x,gdouble offset_y)99 gimp_canvas_set_guide_style (GtkWidget      *canvas,
100                              cairo_t        *cr,
101                              GimpGuideStyle  style,
102                              gboolean        active,
103                              gdouble         offset_x,
104                              gdouble         offset_y)
105 {
106   cairo_pattern_t *pattern;
107   GimpRGB          normal_fg;
108   GimpRGB          normal_bg;
109   GimpRGB          active_fg;
110   GimpRGB          active_bg;
111   gdouble          line_width;
112 
113   g_return_if_fail (GTK_IS_WIDGET (canvas));
114   g_return_if_fail (cr != NULL);
115 
116   switch (style)
117     {
118     case GIMP_GUIDE_STYLE_NORMAL:
119       normal_fg  = guide_normal_fg;
120       normal_bg  = guide_normal_bg;
121       active_fg  = guide_active_fg;
122       active_bg  = guide_active_bg;
123       line_width = 1.0;
124       break;
125 
126     case GIMP_GUIDE_STYLE_MIRROR:
127       normal_fg  = guide_mirror_normal_fg;
128       normal_bg  = guide_mirror_normal_bg;
129       active_fg  = guide_mirror_active_fg;
130       active_bg  = guide_mirror_active_bg;
131       line_width = 1.0;
132       break;
133 
134     case GIMP_GUIDE_STYLE_MANDALA:
135       normal_fg  = guide_mandala_normal_fg;
136       normal_bg  = guide_mandala_normal_bg;
137       active_fg  = guide_mandala_active_fg;
138       active_bg  = guide_mandala_active_bg;
139       line_width = 1.0;
140       break;
141 
142     case GIMP_GUIDE_STYLE_SPLIT_VIEW:
143       normal_fg  = guide_split_normal_fg;
144       normal_bg  = guide_split_normal_bg;
145       active_fg  = guide_split_active_fg;
146       active_bg  = guide_split_active_bg;
147       line_width = 1.0;
148       break;
149 
150     default: /* GIMP_GUIDE_STYLE_NONE */
151       /* This should not happen. */
152       g_return_if_reached ();
153     }
154 
155   cairo_set_line_width (cr, line_width);
156 
157   if (active)
158     pattern = gimp_cairo_pattern_create_stipple (&active_fg, &active_bg, 0,
159                                                  offset_x, offset_y);
160   else
161     pattern = gimp_cairo_pattern_create_stipple (&normal_fg, &normal_bg, 0,
162                                                  offset_x, offset_y);
163 
164   cairo_set_source (cr, pattern);
165   cairo_pattern_destroy (pattern);
166 }
167 
168 void
gimp_canvas_set_sample_point_style(GtkWidget * canvas,cairo_t * cr,gboolean active)169 gimp_canvas_set_sample_point_style (GtkWidget *canvas,
170                                     cairo_t   *cr,
171                                     gboolean   active)
172 {
173   g_return_if_fail (GTK_IS_WIDGET (canvas));
174   g_return_if_fail (cr != NULL);
175 
176   cairo_set_line_width (cr, 1.0);
177 
178   if (active)
179     gimp_cairo_set_source_rgb (cr, &sample_point_active);
180   else
181     gimp_cairo_set_source_rgb (cr, &sample_point_normal);
182 }
183 
184 void
gimp_canvas_set_grid_style(GtkWidget * canvas,cairo_t * cr,GimpGrid * grid,gdouble offset_x,gdouble offset_y)185 gimp_canvas_set_grid_style (GtkWidget *canvas,
186                             cairo_t   *cr,
187                             GimpGrid  *grid,
188                             gdouble    offset_x,
189                             gdouble    offset_y)
190 {
191   GimpRGB fg;
192   GimpRGB bg;
193 
194   g_return_if_fail (GTK_IS_WIDGET (canvas));
195   g_return_if_fail (cr != NULL);
196   g_return_if_fail (GIMP_IS_GRID (grid));
197 
198   cairo_set_line_width (cr, 1.0);
199 
200   gimp_grid_get_fgcolor (grid, &fg);
201 
202   switch (gimp_grid_get_style (grid))
203     {
204       cairo_pattern_t *pattern;
205 
206     case GIMP_GRID_ON_OFF_DASH:
207     case GIMP_GRID_DOUBLE_DASH:
208       if (grid->style == GIMP_GRID_DOUBLE_DASH)
209         {
210           gimp_grid_get_bgcolor (grid, &bg);
211 
212           pattern = gimp_cairo_pattern_create_stipple (&fg, &bg, 0,
213                                                        offset_x, offset_y);
214         }
215       else
216         {
217           gimp_rgba_set (&bg, 0.0, 0.0, 0.0, 0.0);
218 
219           pattern = gimp_cairo_pattern_create_stipple (&fg, &bg, 0,
220                                                        offset_x, offset_y);
221         }
222 
223       cairo_set_source (cr, pattern);
224       cairo_pattern_destroy (pattern);
225       break;
226 
227     case GIMP_GRID_DOTS:
228     case GIMP_GRID_INTERSECTIONS:
229     case GIMP_GRID_SOLID:
230       gimp_cairo_set_source_rgb (cr, &fg);
231       break;
232     }
233 }
234 
235 void
gimp_canvas_set_pen_style(GtkWidget * canvas,cairo_t * cr,const GimpRGB * color,gint width)236 gimp_canvas_set_pen_style (GtkWidget     *canvas,
237                            cairo_t       *cr,
238                            const GimpRGB *color,
239                            gint           width)
240 {
241   g_return_if_fail (GTK_IS_WIDGET (canvas));
242   g_return_if_fail (cr != NULL);
243   g_return_if_fail (color != NULL);
244 
245   cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
246   cairo_set_line_width (cr, width);
247   cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
248   cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
249 
250   gimp_cairo_set_source_rgb (cr, color);
251 }
252 
253 void
gimp_canvas_set_layer_style(GtkWidget * canvas,cairo_t * cr,GimpLayer * layer,gdouble offset_x,gdouble offset_y)254 gimp_canvas_set_layer_style (GtkWidget *canvas,
255                              cairo_t   *cr,
256                              GimpLayer *layer,
257                              gdouble    offset_x,
258                              gdouble    offset_y)
259 {
260   cairo_pattern_t *pattern;
261 
262   g_return_if_fail (GTK_IS_WIDGET (canvas));
263   g_return_if_fail (cr != NULL);
264   g_return_if_fail (GIMP_IS_LAYER (layer));
265 
266   cairo_set_line_width (cr, 1.0);
267   cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
268 
269   if (gimp_layer_get_mask (layer) &&
270       gimp_layer_get_edit_mask (layer))
271     {
272       pattern = gimp_cairo_pattern_create_stipple (&layer_mask_fg,
273                                                    &layer_mask_bg,
274                                                    0,
275                                                    offset_x, offset_y);
276     }
277   else if (gimp_viewable_get_children (GIMP_VIEWABLE (layer)))
278     {
279       pattern = gimp_cairo_pattern_create_stipple (&layer_group_fg,
280                                                    &layer_group_bg,
281                                                    0,
282                                                    offset_x, offset_y);
283     }
284   else
285     {
286       pattern = gimp_cairo_pattern_create_stipple (&layer_fg,
287                                                    &layer_bg,
288                                                    0,
289                                                    offset_x, offset_y);
290     }
291 
292   cairo_set_source (cr, pattern);
293   cairo_pattern_destroy (pattern);
294 }
295 
296 void
gimp_canvas_set_canvas_style(GtkWidget * canvas,cairo_t * cr,gdouble offset_x,gdouble offset_y)297 gimp_canvas_set_canvas_style (GtkWidget *canvas,
298                               cairo_t   *cr,
299                               gdouble    offset_x,
300                               gdouble    offset_y)
301 {
302   cairo_pattern_t *pattern;
303 
304   g_return_if_fail (GTK_IS_WIDGET (canvas));
305   g_return_if_fail (cr != NULL);
306 
307   cairo_set_line_width (cr, 1.0);
308   cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
309 
310   pattern = gimp_cairo_pattern_create_stipple (&canvas_fg,
311                                                &canvas_bg,
312                                                0,
313                                                offset_x, offset_y);
314 
315   cairo_set_source (cr, pattern);
316   cairo_pattern_destroy (pattern);
317 }
318 
319 void
gimp_canvas_set_selection_out_style(GtkWidget * canvas,cairo_t * cr,gdouble offset_x,gdouble offset_y)320 gimp_canvas_set_selection_out_style (GtkWidget *canvas,
321                                      cairo_t   *cr,
322                                      gdouble    offset_x,
323                                      gdouble    offset_y)
324 {
325   cairo_pattern_t *pattern;
326 
327   g_return_if_fail (GTK_IS_WIDGET (canvas));
328   g_return_if_fail (cr != NULL);
329 
330   cairo_set_line_width (cr, 1.0);
331   cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
332 
333   pattern = gimp_cairo_pattern_create_stipple (&selection_out_fg,
334                                                &selection_out_bg,
335                                                0,
336                                                offset_x, offset_y);
337   cairo_set_source (cr, pattern);
338   cairo_pattern_destroy (pattern);
339 }
340 
341 void
gimp_canvas_set_selection_in_style(GtkWidget * canvas,cairo_t * cr,gint index,gdouble offset_x,gdouble offset_y)342 gimp_canvas_set_selection_in_style (GtkWidget *canvas,
343                                     cairo_t   *cr,
344                                     gint       index,
345                                     gdouble    offset_x,
346                                     gdouble    offset_y)
347 {
348   cairo_pattern_t *pattern;
349 
350   g_return_if_fail (GTK_IS_WIDGET (canvas));
351   g_return_if_fail (cr != NULL);
352 
353   cairo_set_line_width (cr, 1.0);
354   cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
355 
356   pattern = gimp_cairo_pattern_create_stipple (&selection_in_fg,
357                                                &selection_in_bg,
358                                                index,
359                                                offset_x, offset_y);
360   cairo_set_source (cr, pattern);
361   cairo_pattern_destroy (pattern);
362 }
363 
364 void
gimp_canvas_set_vectors_bg_style(GtkWidget * canvas,cairo_t * cr,gboolean active)365 gimp_canvas_set_vectors_bg_style (GtkWidget *canvas,
366                                   cairo_t   *cr,
367                                   gboolean   active)
368 {
369   g_return_if_fail (GTK_IS_WIDGET (canvas));
370   g_return_if_fail (cr != NULL);
371 
372   cairo_set_line_width (cr, 3.0);
373 
374   if (active)
375     gimp_cairo_set_source_rgba (cr, &vectors_active_bg);
376   else
377     gimp_cairo_set_source_rgba (cr, &vectors_normal_bg);
378 }
379 
380 void
gimp_canvas_set_vectors_fg_style(GtkWidget * canvas,cairo_t * cr,gboolean active)381 gimp_canvas_set_vectors_fg_style (GtkWidget *canvas,
382                                   cairo_t   *cr,
383                                   gboolean   active)
384 {
385   g_return_if_fail (GTK_IS_WIDGET (canvas));
386   g_return_if_fail (cr != NULL);
387 
388   cairo_set_line_width (cr, 1.0);
389 
390   if (active)
391     gimp_cairo_set_source_rgba (cr, &vectors_active_fg);
392   else
393     gimp_cairo_set_source_rgba (cr, &vectors_normal_fg);
394 }
395 
396 void
gimp_canvas_set_outline_bg_style(GtkWidget * canvas,cairo_t * cr)397 gimp_canvas_set_outline_bg_style (GtkWidget *canvas,
398                                   cairo_t   *cr)
399 {
400   g_return_if_fail (GTK_IS_WIDGET (canvas));
401   g_return_if_fail (cr != NULL);
402 
403   cairo_set_line_width (cr, 1.0);
404   gimp_cairo_set_source_rgba (cr, &outline_bg);
405 }
406 
407 void
gimp_canvas_set_outline_fg_style(GtkWidget * canvas,cairo_t * cr)408 gimp_canvas_set_outline_fg_style (GtkWidget *canvas,
409                                   cairo_t   *cr)
410 {
411   static const double dashes[] = { 4.0, 4.0 };
412 
413   g_return_if_fail (GTK_IS_WIDGET (canvas));
414   g_return_if_fail (cr != NULL);
415 
416   cairo_set_line_width (cr, 1.0);
417   gimp_cairo_set_source_rgba (cr, &outline_fg);
418   cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes), 0);
419 }
420 
421 void
gimp_canvas_set_passe_partout_style(GtkWidget * canvas,cairo_t * cr)422 gimp_canvas_set_passe_partout_style (GtkWidget *canvas,
423                                      cairo_t   *cr)
424 {
425   g_return_if_fail (GTK_IS_WIDGET (canvas));
426   g_return_if_fail (cr != NULL);
427 
428   gimp_cairo_set_source_rgba (cr, &passe_partout);
429 }
430 
431 void
gimp_canvas_set_tool_bg_style(GtkWidget * canvas,cairo_t * cr)432 gimp_canvas_set_tool_bg_style (GtkWidget *canvas,
433                                cairo_t   *cr)
434 {
435   g_return_if_fail (GTK_IS_WIDGET (canvas));
436   g_return_if_fail (cr != NULL);
437 
438   cairo_set_line_width (cr, 3.0);
439   cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
440 
441   gimp_cairo_set_source_rgba (cr, &tool_bg);
442 }
443 
444 void
gimp_canvas_set_tool_fg_style(GtkWidget * canvas,cairo_t * cr,gboolean highlight)445 gimp_canvas_set_tool_fg_style (GtkWidget *canvas,
446                                cairo_t   *cr,
447                                gboolean   highlight)
448 {
449   g_return_if_fail (cr != NULL);
450 
451   cairo_set_line_width (cr, 1.0);
452   cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
453 
454   if (highlight)
455     gimp_cairo_set_source_rgba (cr, &tool_fg_highlight);
456   else
457     gimp_cairo_set_source_rgba (cr, &tool_fg);
458 }
459