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