Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
draw.h
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2022 darktable developers.
4
5 darktable 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 3 of the License, or
8 (at your option) any later version.
9
10 darktable 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
16 along with darktable. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#pragma once
20
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "common/curve_tools.h"
28#include "common/darktable.h"
29#include "common/splines.h"
30#include "control/conf.h"
31#include "develop/develop.h"
32#include <cairo.h>
33#include <glib.h>
34#include <math.h>
35#include <stdint.h>
36#include <stdlib.h>
37#include <gui/gtk.h>
38
39#ifdef __cplusplus
40extern "C" {
41#endif
42
43#ifndef M_PI
44#define M_PI 3.141592654
45#endif
46
47
49#define DT_DRAW_SIZE_LINE DT_PIXEL_APPLY_DPI(1.5f)
50#define DT_DRAW_SIZE_LINE_SELECTED DT_PIXEL_APPLY_DPI(3.0f)
51#define DT_DRAW_SIZE_LINE_HIGHLIGHT (DT_PIXEL_APPLY_DPI(4.0f) + DT_DRAW_SIZE_LINE)
52#define DT_DRAW_SIZE_LINE_HIGHLIGHT_SELECTED (DT_PIXEL_APPLY_DPI(5.0f) + DT_DRAW_SIZE_LINE_SELECTED)
53#define DT_DRAW_SIZE_CROSS DT_PIXEL_APPLY_DPI(7.0f)
54
56#define DT_DRAW_SCALE_DASH DT_PIXEL_APPLY_DPI(12.0f)
57#define DT_DRAW_SCALE_ARROW DT_PIXEL_APPLY_DPI(18.0f)
58
59// radius/width of a handle & node
60#define DT_DRAW_RADIUS_NODE DT_PIXEL_APPLY_DPI(5.0f)
61#define DT_DRAW_RADIUS_NODE_SELECTED (1.5f * DT_DRAW_RADIUS_NODE)
62
63// mouse radius to change overlay elements
64#define DT_DRAW_SELECTION_RADIUS_NO_UPSCALE(dev) (2.0f * DT_DRAW_RADIUS_NODE / dt_dev_get_zoom_level((dt_develop_t *)dev))
65#define DT_DRAW_SELECTION_RADIUS(dev) (DT_DRAW_SELECTION_RADIUS_NO_UPSCALE((dt_develop_t*)dev) * darktable.gui->ppd)
66
67// used to detect the area where rotation of a shape is possible
68#define DT_DRAW_SELECTION_ROTATION_AREA DT_PIXEL_APPLY_DPI(50.0f)
69#define DT_DRAW_SELECTION_ROTATION_RADIUS(dev) (DT_DRAW_SELECTION_ROTATION_AREA / dt_dev_get_zoom_level((dt_develop_t *)dev))
70
78
85
87static inline void dt_draw_set_color_overlay(cairo_t *cr, gboolean bright, double alpha)
88{
89 double amt;
90
91 if(bright)
92 amt = 0.5 + darktable.gui->overlay_contrast * 0.5;
93 else
94 amt = (1.0 - darktable.gui->overlay_contrast) * 0.5;
95
96 cairo_set_source_rgba(cr, darktable.gui->overlay_red * amt, darktable.gui->overlay_green * amt, darktable.gui->overlay_blue * amt, alpha);
97}
98
101static inline void dt_draw_star(cairo_t *cr, float x, float y, float r1, float r2)
102{
103 const float d = 2.0 * M_PI * 0.1f;
104 const float dx[10] = { sinf(0.0), sinf(d), sinf(2 * d), sinf(3 * d), sinf(4 * d),
105 sinf(5 * d), sinf(6 * d), sinf(7 * d), sinf(8 * d), sinf(9 * d) };
106 const float dy[10] = { cosf(0.0), cosf(d), cosf(2 * d), cosf(3 * d), cosf(4 * d),
107 cosf(5 * d), cosf(6 * d), cosf(7 * d), cosf(8 * d), cosf(9 * d) };
108
109 cairo_move_to(cr, x + r1 * dx[0], y - r1 * dy[0]);
110 for(int k = 1; k < 10; k++)
111 if(k & 1)
112 cairo_line_to(cr, x + r2 * dx[k], y - r2 * dy[k]);
113 else
114 cairo_line_to(cr, x + r1 * dx[k], y - r1 * dy[k]);
115 cairo_close_path(cr);
116}
117
118static inline void dt_draw_line(cairo_t *cr, float left, float top, float right, float bottom)
119{
120 cairo_move_to(cr, left, top);
121 cairo_line_to(cr, right, bottom);
122}
123
124static inline void dt_draw_grid(cairo_t *cr, const int num, const int left, const int top, const int right,
125 const int bottom)
126{
127 float width = right - left;
128 float height = bottom - top;
129
130 for(int k = 1; k < num; k++)
131 {
132 dt_draw_line(cr, left + k / (float)num * width, top, left + k / (float)num * width, bottom);
133 cairo_stroke(cr);
134 dt_draw_line(cr, left, top + k / (float)num * height, right, top + k / (float)num * height);
135 cairo_stroke(cr);
136 }
137}
138
139static inline float dt_curve_to_mouse(const float x, const float zoom_factor, const float offset)
140{
141 return (x - offset) * zoom_factor;
142}
143
144/* left, right, top, bottom are in curve coordinates [0..1] */
145static inline void dt_draw_grid_zoomed(cairo_t *cr, const int num, const float left, const float top,
146 const float right, const float bottom, const float width,
147 const float height, const float zoom_factor, const float zoom_offset_x,
148 const float zoom_offset_y)
149{
150 for(int k = 1; k < num; k++)
151 {
152 dt_draw_line(cr, dt_curve_to_mouse(left + k / (float)num, zoom_factor, zoom_offset_x) * width,
153 dt_curve_to_mouse(top, zoom_factor, zoom_offset_y) * -height,
154 dt_curve_to_mouse(left + k / (float)num, zoom_factor, zoom_offset_x) * width,
155 dt_curve_to_mouse(bottom, zoom_factor, zoom_offset_y) * -height);
156 cairo_stroke(cr);
157
158 dt_draw_line(cr, dt_curve_to_mouse(left, zoom_factor, zoom_offset_x) * width,
159 dt_curve_to_mouse(top + k / (float)num, zoom_factor, zoom_offset_y) * -height,
160 dt_curve_to_mouse(right, zoom_factor, zoom_offset_x) * width,
161 dt_curve_to_mouse(top + k / (float)num, zoom_factor, zoom_offset_y) * -height);
162 cairo_stroke(cr);
163 }
164}
165
166#ifdef _OPENMP
167#pragma omp declare simd uniform(base)
168#endif
169static inline float dt_log_scale_axis(const float x, const float base)
170{
171 return logf(x * (base - 1.0f) + 1.f) / logf(base);
172}
173
174static inline void dt_draw_loglog_grid(cairo_t *cr, const int num, const int left, const int top, const int right,
175 const int bottom, const float base)
176{
177 float width = right - left;
178 float height = bottom - top;
179
180 for(int k = 1; k < num; k++)
181 {
182 const float x = dt_log_scale_axis(k / (float)num, base);
183 dt_draw_line(cr, left + x * width, top, left + x * width, bottom);
184 cairo_stroke(cr);
185 dt_draw_line(cr, left, top + x * height, right, top + x * height);
186 cairo_stroke(cr);
187 }
188}
189
190static inline void dt_draw_semilog_x_grid(cairo_t *cr, const int num, const int left, const int top,
191 const int right, const int bottom, const float base)
192{
193 float width = right - left;
194 float height = bottom - top;
195
196 for(int k = 1; k < num; k++)
197 {
198 const float x = dt_log_scale_axis(k / (float)num, base);
199 dt_draw_line(cr, left + x * width, top, left + x * width, bottom);
200 cairo_stroke(cr);
201 dt_draw_line(cr, left, top + k / (float)num * height, right, top + k / (float)num * height);
202 cairo_stroke(cr);
203 }
204}
205
206static inline void dt_draw_semilog_y_grid(cairo_t *cr, const int num, const int left, const int top,
207 const int right, const int bottom, const float base)
208{
209 float width = right - left;
210 float height = bottom - top;
211
212 for(int k = 1; k < num; k++)
213 {
214 const float x = dt_log_scale_axis(k / (float)num, base);
215 dt_draw_line(cr, left + k / (float)num * width, top, left + k / (float)num * width, bottom);
216 cairo_stroke(cr);
217 dt_draw_line(cr, left, top + x * height, right, top + x * height);
218 cairo_stroke(cr);
219 }
220}
221
222
223static inline void dt_draw_vertical_lines(cairo_t *cr, const int num, const int left, const int top,
224 const int right, const int bottom)
225{
226 float width = right - left;
227
228 for(int k = 1; k < num; k++)
229 {
230 cairo_move_to(cr, left + k / (float)num * width, top);
231 cairo_line_to(cr, left + k / (float)num * width, bottom);
232 cairo_stroke(cr);
233 }
234}
235
236static inline void dt_draw_horizontal_lines(cairo_t *cr, const int num, const int left, const int top,
237 const int right, const int bottom)
238{
239 float height = bottom - top;
240
241 for(int k = 1; k < num; k++)
242 {
243 cairo_move_to(cr, left, top + k / (float)num * height);
244 cairo_line_to(cr, right, top + k / (float)num * height);
245 cairo_stroke(cr);
246 }
247}
248
249static inline dt_draw_curve_t *dt_draw_curve_new(const float min, const float max, unsigned int type)
250{
251 dt_draw_curve_t *c = (dt_draw_curve_t *)malloc(sizeof(dt_draw_curve_t));
252 c->csample.m_samplingRes = 0x10000;
253 c->csample.m_outputRes = 0x10000;
254 c->csample.m_Samples = (uint16_t *)malloc(sizeof(uint16_t) * 0x10000);
255
256 c->c.m_spline_type = type;
257 c->c.m_numAnchors = 0;
258 c->c.m_min_x = 0.0;
259 c->c.m_max_x = 1.0;
260 c->c.m_min_y = 0.0;
261 c->c.m_max_y = 1.0;
262 return c;
263}
264
266{
267 free(c->csample.m_Samples);
268 free(c);
269}
270
271static inline void dt_draw_curve_set_point(dt_draw_curve_t *c, const int num, const float x, const float y)
272{
273 c->c.m_anchors[num].x = x;
274 c->c.m_anchors[num].y = y;
275}
276
277static inline void dt_draw_curve_smaple_values(dt_draw_curve_t *c, const float min, const float max, const int res,
278 float *x, float *y)
279{
280 if(x)
281 {
282#ifdef _OPENMP
283#pragma omp parallel for SIMD() default(none) dt_omp_firstprivate(res) shared(x) schedule(static)
284#endif
285 for(int k = 0; k < res; k++) x[k] = k * (1.0f / res);
286 }
287 if(y)
288 {
289#ifdef _OPENMP
290#pragma omp parallel for SIMD() default(none) dt_omp_firstprivate(min, max, res) shared(y, c) schedule(static)
291#endif
292 for(int k = 0; k < res; k++) y[k] = min + (max - min) * c->csample.m_Samples[k] * (1.0f / 0x10000);
293 }
294}
295
296static inline void dt_draw_curve_calc_values(dt_draw_curve_t *c, const float min, const float max, const int res,
297 float *x, float *y)
298{
299 c->csample.m_samplingRes = res;
300 c->csample.m_outputRes = 0x10000;
301 CurveDataSample(&c->c, &c->csample);
302 dt_draw_curve_smaple_values(c, min, max, res, x, y);
303}
304
305static inline void dt_draw_curve_calc_values_V2_nonperiodic(dt_draw_curve_t *c, const float min, const float max,
306 const int res, float *x, float *y)
307{
308 c->csample.m_samplingRes = res;
309 c->csample.m_outputRes = 0x10000;
310 CurveDataSampleV2(&c->c, &c->csample);
311 dt_draw_curve_smaple_values(c, min, max, res, x, y);
312}
313
314static inline void dt_draw_curve_calc_values_V2_periodic(dt_draw_curve_t *c, const float min, const float max,
315 const int res, float *x, float *y)
316{
317 c->csample.m_samplingRes = res;
318 c->csample.m_outputRes = 0x10000;
319 CurveDataSampleV2Periodic(&c->c, &c->csample);
320 dt_draw_curve_smaple_values(c, min, max, res, x, y);
321}
322
323static inline void dt_draw_curve_calc_values_V2(dt_draw_curve_t *c, const float min, const float max,
324 const int res, float *x, float *y, const gboolean periodic)
325{
326 if(periodic)
327 dt_draw_curve_calc_values_V2_periodic(c, min, max, res, x, y);
328 else
329 dt_draw_curve_calc_values_V2_nonperiodic(c, min, max, res, x, y);
330 }
331
332static inline float dt_draw_curve_calc_value(dt_draw_curve_t *c, const float x)
333{
334 float xa[20], ya[20];
335 float val = 0.f;
336 float *ypp = NULL;
337 for(int i = 0; i < c->c.m_numAnchors; i++)
338 {
339 xa[i] = c->c.m_anchors[i].x;
340 ya[i] = c->c.m_anchors[i].y;
341 }
342 ypp = interpolate_set(c->c.m_numAnchors, xa, ya, c->c.m_spline_type);
343 if(ypp)
344 {
345 val = interpolate_val(c->c.m_numAnchors, xa, x, ya, ypp, c->c.m_spline_type);
346 free(ypp);
347 }
348 return MIN(MAX(val, c->c.m_min_y), c->c.m_max_y);
349}
350
351static inline int dt_draw_curve_add_point(dt_draw_curve_t *c, const float x, const float y)
352{
353 c->c.m_anchors[c->c.m_numAnchors].x = x;
354 c->c.m_anchors[c->c.m_numAnchors].y = y;
355 c->c.m_numAnchors++;
356 return 0;
357}
358
359// linear x linear y
360static inline void dt_draw_histogram_8_linxliny(cairo_t *cr, const uint32_t *hist, int32_t channels,
361 int32_t channel)
362{
363 cairo_move_to(cr, 0, 0);
364 for(int k = 0; k < 256; k++) cairo_line_to(cr, k, hist[channels * k + channel]);
365 cairo_line_to(cr, 255, 0);
366 cairo_close_path(cr);
367 cairo_fill(cr);
368}
369
370static inline void dt_draw_histogram_8_zoomed(cairo_t *cr, const uint32_t *hist, int32_t channels, int32_t channel,
371 const float zoom_factor, const float zoom_offset_x,
372 const float zoom_offset_y, gboolean linear)
373{
374 cairo_move_to(cr, -zoom_offset_x, -zoom_offset_y);
375 for(int k = 0; k < 256; k++)
376 {
377 const float value = ((float)hist[channels * k + channel] - zoom_offset_y) * zoom_factor;
378 const float hist_value = value < 0 ? 0.f : value;
379 cairo_line_to(cr, ((float)k - zoom_offset_x) * zoom_factor, linear ? hist_value : logf(1.0f + hist_value));
380 }
381 cairo_line_to(cr, (255.f - zoom_offset_x), -zoom_offset_y * zoom_factor);
382 cairo_close_path(cr);
383 cairo_fill(cr);
384}
385
386// log x (scalable) & linear y
387static inline void dt_draw_histogram_8_logxliny(cairo_t *cr, const uint32_t *hist, int32_t channels,
388 int32_t channel, float base_log)
389{
390 cairo_move_to(cr, 0, 0);
391 for(int k = 0; k < 256; k++)
392 {
393 const float x = logf((float)k / 255.0f * (base_log - 1.0f) + 1.0f) / logf(base_log) * 255.0f;
394 const float y = hist[channels * k + channel];
395 cairo_line_to(cr, x, y);
396 }
397 cairo_line_to(cr, 255, 0);
398 cairo_close_path(cr);
399 cairo_fill(cr);
400}
401
402// log x (scalable) & log y
403static inline void dt_draw_histogram_8_logxlogy(cairo_t *cr, const uint32_t *hist, int32_t channels,
404 int32_t channel, float base_log)
405{
406 cairo_move_to(cr, 0, 0);
407 for(int k = 0; k < 256; k++)
408 {
409 const float x = logf((float)k / 255.0f * (base_log - 1.0f) + 1.0f) / logf(base_log) * 255.0f;
410 const float y = logf(1.0 + hist[channels * k + channel]);
411 cairo_line_to(cr, x, y);
412 }
413 cairo_line_to(cr, 255, 0);
414 cairo_close_path(cr);
415 cairo_fill(cr);
416}
417
418// linear x log y
419static inline void dt_draw_histogram_8_linxlogy(cairo_t *cr, const uint32_t *hist, int32_t channels,
420 int32_t channel)
421{
422 cairo_move_to(cr, 0, 0);
423 for(int k = 0; k < 256; k++) cairo_line_to(cr, k, logf(1.0 + hist[channels * k + channel]));
424 cairo_line_to(cr, 255, 0);
425 cairo_close_path(cr);
426 cairo_fill(cr);
427}
428
429// log x (scalable)
430static inline void dt_draw_histogram_8_log_base(cairo_t *cr, const uint32_t *hist, int32_t channels,
431 int32_t channel, const gboolean linear, float base_log)
432{
433
434 if(linear) // linear y
435 dt_draw_histogram_8_logxliny(cr, hist, channels, channel, base_log);
436 else // log y
437 dt_draw_histogram_8_logxlogy(cr, hist, channels, channel, base_log);
438}
439
440// linear x
441static inline void dt_draw_histogram_8(cairo_t *cr, const uint32_t *hist, int32_t channels, int32_t channel,
442 const gboolean linear)
443{
444 if(linear) // linear y
445 dt_draw_histogram_8_linxliny(cr, hist, channels, channel);
446 else // log y
447 dt_draw_histogram_8_linxlogy(cr, hist, channels, channel);
448}
449
451static inline void dt_draw_cairo_to_gdk_pixbuf(uint8_t *data, unsigned int width, unsigned int height)
452{
453 for(uint32_t y = 0; y < height; y++)
454 for(uint32_t x = 0; x < width; x++)
455 {
456 uint8_t *r, *g, *b, *a, tmp;
457 r = &data[(y * width + x) * 4 + 0];
458 g = &data[(y * width + x) * 4 + 1];
459 b = &data[(y * width + x) * 4 + 2];
460 a = &data[(y * width + x) * 4 + 3];
461
462 // switch r and b
463 tmp = *r;
464 *r = *b;
465 *b = tmp;
466
467 // cairo uses premultiplied alpha, reverse that
468 if(*a != 0)
469 {
470 float inv_a = 255.0 / *a;
471 *r *= inv_a;
472 *g *= inv_a;
473 *b *= inv_a;
474 }
475 }
476}
477
478static inline void dt_cairo_perceptual_gradient(cairo_pattern_t *grad, double alpha)
479{
480 // Create a linear gradient from black to white
481 cairo_pattern_add_color_stop_rgba(grad, 0.0, 0.0, 0.0, 0.0, alpha);
482 cairo_pattern_add_color_stop_rgba(grad, 1.0, 1.0, 1.0, 1.0, alpha);
483}
484
485static inline GdkPixbuf *dt_draw_paint_to_pixbuf
486 (GtkWidget *widget, const guint pixbuf_size, const int flags,
487 void (*dtgtk_cairo_paint_fct)(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data))
488{
489 GdkRGBA fg_color;
490 GtkStyleContext *context = gtk_widget_get_style_context(widget);
491 GtkStateFlags state = gtk_widget_get_state_flags(widget);
492 gtk_style_context_get_color(context, state, &fg_color);
493
494 const int dim = DT_PIXEL_APPLY_DPI(pixbuf_size);
495 cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dim, dim);
496 cairo_t *cr = cairo_create(cst);
497 gdk_cairo_set_source_rgba(cr, &fg_color);
498 (*dtgtk_cairo_paint_fct)(cr, 0, 0, dim, dim, flags, NULL);
499 cairo_destroy(cr);
500 uint8_t *data = cairo_image_surface_get_data(cst);
501 dt_draw_cairo_to_gdk_pixbuf(data, dim, dim);
502 const size_t size = (size_t)dim * dim * 4;
503 uint8_t *buf = (uint8_t *)malloc(size);
504 memcpy(buf, data, size);
505 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data(buf, GDK_COLORSPACE_RGB, TRUE, 8, dim, dim, dim * 4,
506 (GdkPixbufDestroyNotify)free, NULL);
507 cairo_surface_destroy(cst);
508 return pixbuf;
509}
510
511/***** SHAPES */
512
513static inline void dt_draw_set_dash_style(cairo_t *cr, dt_masks_dash_type_t type, float zoom_scale)
514{
515 // return early if no dash is needed
517 {
518 cairo_set_dash(cr, NULL, 0, 0);
519 return;
520 }
521
522 double pattern[2];
523
524 switch(type)
525 {
526 case DT_MASKS_NO_DASH:
527 pattern[0] = 0.0f;
528 pattern[1] = 0.0f;
529 break;
530
532 pattern[0] = DT_DRAW_SCALE_DASH / zoom_scale;
533 pattern[1] = DT_DRAW_SCALE_DASH / zoom_scale;
534 break;
535
537 pattern[0] = (DT_DRAW_SCALE_DASH * 0.25f) / zoom_scale;
538 pattern[1] = DT_DRAW_SCALE_DASH / zoom_scale;
539 break;
540
541 default:
542 cairo_set_dash(cr, NULL, 0, 0);
543 return;
544
545 }
546 const int pattern_len = 2;
547 cairo_set_dash(cr, pattern, pattern_len, 0);
548}
549
561static inline void dt_draw_node(cairo_t *cr, const gboolean square, const gboolean point_action, const gboolean selected, const float zoom_scale, const float x, const float y)
562{
563 cairo_save(cr);
564
565 const float node_width = DT_DRAW_RADIUS_NODE / zoom_scale;
566
567 // square for corner nodes, circle for others (curve)
568 if(square)
569 {
570 const float pos = node_width;
571 cairo_rectangle(cr, x - pos, y - pos, node_width * 2.f, node_width * 2.f);
572 }
573 else
574 cairo_arc(cr, x, y, node_width * 1.2f, 0.0, 2.0 * G_PI);
575
576 cairo_fill_preserve(cr); // erase all drawings below
577
578 const float line_width = (point_action && selected) ? DT_DRAW_SIZE_LINE_SELECTED / zoom_scale
579 : DT_DRAW_SIZE_LINE / zoom_scale;
580
581 cairo_set_line_width(cr, line_width);
582 //if(selected) cairo_set_source_rgba(cr, 1., 1., 1., 0.8);
583 //else dt_draw_set_color_overlay(cr, TRUE, 0.8);
584 dt_draw_set_color_overlay(cr, TRUE, selected ? 1 : 0.8);
585
586 cairo_fill_preserve(cr);
587
588 // draw dark border
589 cairo_set_line_width(cr, (selected && !point_action) ? line_width * 2. : line_width);
591 cairo_stroke(cr);
592
593 cairo_restore(cr);
594}
595
609static inline void dt_draw_handle(cairo_t *cr, const float pt_x, const float pt_y, const float zoom_scale,
610 const float handle_x, const float handle_y, const gboolean selected)
611{
612 cairo_save(cr);
613
614 // draw handle's tail
615 float delta_x = handle_x - pt_x;
616 float delta_y = handle_y - pt_y;
617 float tail_len = sqrtf(delta_x * delta_x + delta_y * delta_y);
618 // Draw only if the line is long enough
619 // and shorten the line by the size of the nodes so it does not overlap with them
620 float shorten = (DT_DRAW_RADIUS_NODE / zoom_scale) * 0.5f;
621 if(tail_len > (2 * shorten))
622 {
623 float start_x = pt_x + delta_x * (shorten / tail_len);
624 float start_y = pt_y + delta_y * (shorten / tail_len);
625 float end_x = handle_x - delta_x * (shorten / tail_len);
626 float end_y = handle_y - delta_y * (shorten / tail_len);
627 cairo_move_to(cr, start_x, start_y);
628 cairo_line_to(cr, end_x, end_y);
629 }
630
631 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE_HIGHLIGHT * 0.6 / zoom_scale);
633 cairo_stroke_preserve(cr);
634 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE * 0.6 / zoom_scale);
636 cairo_stroke(cr);
637
638 cairo_restore(cr);
639 cairo_save(cr);
640
641 //draw the control handle
642 float handle_radius = 0.0f;
643 float line_width = 0.0f;
644 if(selected)
645 {
646 handle_radius = DT_DRAW_RADIUS_NODE_SELECTED / zoom_scale;
647 line_width = (DT_DRAW_SIZE_LINE_HIGHLIGHT_SELECTED / zoom_scale) * 0.5f;
648 }
649 else
650 {
651 handle_radius = DT_DRAW_RADIUS_NODE / zoom_scale;
652 line_width = DT_DRAW_SIZE_LINE / zoom_scale;
653 }
654
655 cairo_arc(cr, handle_x, handle_y, handle_radius * 0.75f, 0, 2.0 * M_PI);
656 // Erase all drawings below
657 cairo_fill_preserve(cr);
658
659 cairo_set_line_width(cr, line_width);
661 cairo_stroke_preserve(cr);
663 cairo_fill(cr);
664
665 // uncomment this part if you want to see "real" control points
666 /*cairo_move_to(cr, gpt->points[n*6+2],gpt->points[n*6+3]);
667 cairo_line_to(cr, gpt->points[n*6],gpt->points[n*6+1]);
668 cairo_stroke(cr);
669 cairo_move_to(cr, gpt->points[n*6+2],gpt->points[n*6+3]);
670 cairo_line_to(cr, gpt->points[n*6+4],gpt->points[n*6+5]);
671 cairo_stroke(cr);*/
672
673 cairo_restore(cr);
674}
675
676typedef void (*shape_draw_function_t)(cairo_t *cr, const float *points, const int points_count, const int nb, const gboolean border, const gboolean source);
677
691static inline void dt_draw_shape_lines(const dt_masks_dash_type_t dash_type, const gboolean source, cairo_t *cr, const int nb, const gboolean selected,
692 const float zoom_scale, const float *points, const int points_count, const shape_draw_function_t *draw_shape_func)
693{
694 cairo_save(cr);
695
696 // are we drawing a border ?
697 const gboolean border = dash_type != DT_MASKS_NO_DASH;
698 // draw the shape from the integrated function if any
699 if(draw_shape_func && points && points_count >= 2)
700 {
701 (*draw_shape_func)(cr, points, points_count, nb, border, FALSE);
702 }
703
704 if(dash_type)
705 {
706 // Trick: fill with a transparent color to get only the outer shape
707 // because when using varying widths on nodes, there are self-intersecting border lines
708 cairo_set_source_rgba(cr, 0., 0., 0., 0.);
709 cairo_fill_preserve(cr);
710 }
711
712 // dashed ?
713 if(dash_type && !source)
714 dt_draw_set_dash_style(cr, dash_type, zoom_scale);
715 else
717
718 // HIGHLIGHT (dark)
719 if(selected)
720 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE_HIGHLIGHT_SELECTED / zoom_scale);
721 else
722 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE_HIGHLIGHT / zoom_scale);
723 dt_draw_set_color_overlay(cr, FALSE, dash_type ? 0.3f : 0.9f);
724 cairo_stroke_preserve(cr);
725
726 // NORMAL (bright)
727 if(selected)
728 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE_SELECTED / zoom_scale);
729 else
730 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE / zoom_scale);
732 cairo_stroke(cr);
733
734 cairo_restore(cr);
735}
736
746static inline void dt_draw_stroke_line(const dt_masks_dash_type_t dash_type, const gboolean source, cairo_t *cr,
747 const gboolean selected, const float zoom_scale)
748{
749 dt_draw_shape_lines(dash_type, source, cr, 0, selected, zoom_scale, NULL, 0, NULL);
750}
751
752static void _draw_arrow_head(cairo_t *cr, const float arrow[2], const float arrow_x_a, const float arrow_y_a,
753 const float arrow_x_b, const float arrow_y_b)
754{
755 //draw the arrow head
756 cairo_move_to(cr, arrow_x_a, arrow_y_a);
757 cairo_line_to(cr, arrow[0], arrow[1]);
758 cairo_line_to(cr, arrow_x_b, arrow_y_b);
759 // close the arrow head
760 cairo_close_path(cr);
761}
762
763static void _draw_arrow_tail(cairo_t *cr, const float arrow_bud_x, const float arrow_bud_y,
764 const float tail[2], const gboolean draw_tail)
765{
766 if(draw_tail) dt_draw_line(cr, arrow_bud_x, arrow_bud_y, tail[0], tail[1]);
767}
768
782static inline void dt_draw_arrow(cairo_t *cr, const float zoom_scale,const gboolean selected, const gboolean draw_tail,
783 const dt_masks_dash_type_t dash_style, const float arrow[2], const float tail[2])
784{
785 // calculate the angle of the segment from tail to arrow
786 float delta_x = tail[0] - arrow[0];
787 float delta_y = tail[1] - arrow[1];
788 float angle = atan2f(delta_y, delta_x);
789
790 // calculate the coordinates of the two base points of the arrow head
791 const float arrow_x_a = arrow[0] + (DT_DRAW_SCALE_ARROW / zoom_scale) * cosf(angle + (0.4f));
792 const float arrow_y_a = arrow[1] + (DT_DRAW_SCALE_ARROW / zoom_scale) * sinf(angle + (0.4f));
793 const float arrow_x_b = arrow[0] + (DT_DRAW_SCALE_ARROW / zoom_scale) * cosf(angle - (0.4f));
794 const float arrow_y_b = arrow[1] + (DT_DRAW_SCALE_ARROW / zoom_scale) * sinf(angle - (0.4f));
795 // Calculate the coordinates of the arrow base's midpoint
796 const float arrow_bud_x = (arrow_x_a + arrow_x_b) * 0.5f;
797 const float arrow_bud_y = (arrow_y_a + arrow_y_b) * 0.5f;
798
799 cairo_save(cr);
800 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
801
802 // we need to draw the arrow head and tail in two passes to get the dark and bright effect correctly
803
804 // dark
805 {
806 // arrow head
807 _draw_arrow_head(cr, arrow, arrow_x_a, arrow_y_a, arrow_x_b, arrow_y_b);
808 // erase all drawings below
809 cairo_fill_preserve(cr);
810
813 /*if(selected)
814 cairo_set_line_width(cr, (4 * DT_DRAW_SIZE_LINE) / zoom_scale);
815 else
816 cairo_set_line_width(cr, (2 * DT_DRAW_SIZE_LINE) / zoom_scale);
817 */
818 if(selected)
819 cairo_set_line_width(cr, 0.8f * DT_DRAW_SIZE_LINE_HIGHLIGHT_SELECTED / zoom_scale);
820 else
821 cairo_set_line_width(cr, 0.8f * DT_DRAW_SIZE_LINE_HIGHLIGHT / zoom_scale);
822 cairo_stroke(cr);
823
824 // arrow tail
825 _draw_arrow_tail(cr, arrow_bud_x, arrow_bud_y, tail, draw_tail);
826 dt_draw_set_dash_style(cr, dash_style, zoom_scale);
828 if(selected)
829 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE_HIGHLIGHT_SELECTED / zoom_scale);
830 else
831 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE_HIGHLIGHT / zoom_scale);
832 cairo_stroke(cr);
833 }
834
835 // bright
836 {
837 // arrow head
838 _draw_arrow_head(cr, arrow, arrow_x_a, arrow_y_a, arrow_x_b, arrow_y_b);
839 // erase all drawings below
840 cairo_set_source_rgba(cr, 0., 0., 0., 0.);
841 cairo_fill_preserve(cr);
842
845 /*if(selected)
846 cairo_set_line_width(cr, (DT_DRAW_SIZE_LINE_SELECTED) / zoom_scale);
847 else
848 cairo_set_line_width(cr, (DT_DRAW_SIZE_LINE) / zoom_scale);
849 */
850 if(selected)
851 cairo_set_line_width(cr, (2 * DT_DRAW_SIZE_LINE) / zoom_scale);
852 else
853 cairo_set_line_width(cr, (DT_DRAW_SIZE_LINE) / zoom_scale);
854 cairo_stroke(cr);
855
856 // arrow tail
857 _draw_arrow_tail(cr, arrow_bud_x, arrow_bud_y, tail, draw_tail);
858 dt_draw_set_dash_style(cr, dash_style, zoom_scale);
860 if(selected)
861 cairo_set_line_width(cr, (3 * DT_DRAW_SIZE_LINE) / zoom_scale);
862 else
863 cairo_set_line_width(cr, (2 * DT_DRAW_SIZE_LINE) / zoom_scale);
864 cairo_stroke(cr);
865 }
866}
867
868
869#ifdef __cplusplus
870}
871#endif
872
873// clang-format off
874// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
875// vim: shiftwidth=2 expandtab tabstop=2 cindent
876// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
877// clang-format on
#define TRUE
Definition ashift_lsd.c:151
#define FALSE
Definition ashift_lsd.c:147
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
int type
Definition common/metadata.c:42
float * interpolate_set(int n, float x[], float y[], unsigned int type)
Definition curve_tools.c:502
int CurveDataSample(CurveData *curve, CurveSample *sample)
Definition curve_tools.c:665
float interpolate_val(int n, float x[], float xval, float y[], float tangents[], unsigned int type)
Definition curve_tools.c:507
darktable_t darktable
Definition darktable.c:111
static void dt_draw_arrow(cairo_t *cr, const float zoom_scale, const gboolean selected, const gboolean draw_tail, const dt_masks_dash_type_t dash_style, const float arrow[2], const float tail[2])
Draw an arrow with head and, if needed, tail. The length of the arrow head is defined by DT_DRAW_SCAL...
Definition draw.h:782
dt_masks_dash_type_t
Definition draw.h:73
@ DT_MASKS_DASH_STICK
Definition draw.h:75
@ DT_MASKS_DASH_ROUND
Definition draw.h:76
@ DT_MASKS_NO_DASH
Definition draw.h:74
static float dt_curve_to_mouse(const float x, const float zoom_factor, const float offset)
Definition draw.h:139
#define DT_DRAW_SCALE_DASH
Definition draw.h:56
#define DT_DRAW_SIZE_LINE
Definition draw.h:49
#define DT_DRAW_RADIUS_NODE_SELECTED
Definition draw.h:61
static void dt_draw_set_dash_style(cairo_t *cr, dt_masks_dash_type_t type, float zoom_scale)
Definition draw.h:513
static GdkPixbuf * dt_draw_paint_to_pixbuf(GtkWidget *widget, const guint pixbuf_size, const int flags, void(*dtgtk_cairo_paint_fct)(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data))
Definition draw.h:486
static void dt_draw_curve_calc_values(dt_draw_curve_t *c, const float min, const float max, const int res, float *x, float *y)
Definition draw.h:296
static void dt_draw_horizontal_lines(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom)
Definition draw.h:236
static void dt_draw_histogram_8_zoomed(cairo_t *cr, const uint32_t *hist, int32_t channels, int32_t channel, const float zoom_factor, const float zoom_offset_x, const float zoom_offset_y, gboolean linear)
Definition draw.h:370
#define DT_DRAW_SIZE_LINE_HIGHLIGHT
Definition draw.h:51
#define DT_DRAW_SIZE_LINE_SELECTED
Definition draw.h:50
static void dt_draw_histogram_8_logxlogy(cairo_t *cr, const uint32_t *hist, int32_t channels, int32_t channel, float base_log)
Definition draw.h:403
static void dt_draw_cairo_to_gdk_pixbuf(uint8_t *data, unsigned int width, unsigned int height)
Definition draw.h:451
static void dt_draw_histogram_8_linxlogy(cairo_t *cr, const uint32_t *hist, int32_t channels, int32_t channel)
Definition draw.h:419
static float dt_log_scale_axis(const float x, const float base)
Definition draw.h:169
static void dt_draw_handle(cairo_t *cr, const float pt_x, const float pt_y, const float zoom_scale, const float handle_x, const float handle_y, const gboolean selected)
Draw & control handle of a point with a tail bet.
Definition draw.h:609
static void dt_draw_set_color_overlay(cairo_t *cr, gboolean bright, double alpha)
Definition draw.h:87
static void dt_draw_line(cairo_t *cr, float left, float top, float right, float bottom)
Definition draw.h:118
static void dt_draw_curve_smaple_values(dt_draw_curve_t *c, const float min, const float max, const int res, float *x, float *y)
Definition draw.h:277
static void dt_draw_histogram_8_linxliny(cairo_t *cr, const uint32_t *hist, int32_t channels, int32_t channel)
Definition draw.h:360
static void dt_draw_vertical_lines(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom)
Definition draw.h:223
static void dt_draw_grid(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom)
Definition draw.h:124
static void dt_draw_semilog_y_grid(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom, const float base)
Definition draw.h:206
static float dt_draw_curve_calc_value(dt_draw_curve_t *c, const float x)
Definition draw.h:332
static void dt_cairo_perceptual_gradient(cairo_pattern_t *grad, double alpha)
Definition draw.h:478
static void dt_draw_star(cairo_t *cr, float x, float y, float r1, float r2)
Definition draw.h:101
static void dt_draw_curve_calc_values_V2_nonperiodic(dt_draw_curve_t *c, const float min, const float max, const int res, float *x, float *y)
Definition draw.h:305
#define DT_DRAW_SCALE_ARROW
Definition draw.h:57
static void dt_draw_curve_destroy(dt_draw_curve_t *c)
Definition draw.h:265
static void dt_draw_curve_calc_values_V2(dt_draw_curve_t *c, const float min, const float max, const int res, float *x, float *y, const gboolean periodic)
Definition draw.h:323
static void dt_draw_histogram_8_log_base(cairo_t *cr, const uint32_t *hist, int32_t channels, int32_t channel, const gboolean linear, float base_log)
Definition draw.h:430
#define DT_DRAW_RADIUS_NODE
Definition draw.h:60
static void dt_draw_curve_set_point(dt_draw_curve_t *c, const int num, const float x, const float y)
Definition draw.h:271
static int dt_draw_curve_add_point(dt_draw_curve_t *c, const float x, const float y)
Definition draw.h:351
static void dt_draw_histogram_8_logxliny(cairo_t *cr, const uint32_t *hist, int32_t channels, int32_t channel, float base_log)
Definition draw.h:387
static void dt_draw_stroke_line(const dt_masks_dash_type_t dash_type, const gboolean source, cairo_t *cr, const gboolean selected, const float zoom_scale)
Stroke a line with style.
Definition draw.h:746
#define DT_DRAW_SIZE_LINE_HIGHLIGHT_SELECTED
Definition draw.h:52
static void dt_draw_semilog_x_grid(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom, const float base)
Definition draw.h:190
static void dt_draw_histogram_8(cairo_t *cr, const uint32_t *hist, int32_t channels, int32_t channel, const gboolean linear)
Definition draw.h:441
static dt_draw_curve_t * dt_draw_curve_new(const float min, const float max, unsigned int type)
Definition draw.h:249
#define M_PI
Definition draw.h:44
void(* shape_draw_function_t)(cairo_t *cr, const float *points, const int points_count, const int nb, const gboolean border, const gboolean source)
Definition draw.h:676
static void dt_draw_loglog_grid(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom, const float base)
Definition draw.h:174
static void _draw_arrow_head(cairo_t *cr, const float arrow[2], const float arrow_x_a, const float arrow_y_a, const float arrow_x_b, const float arrow_y_b)
Definition draw.h:752
static void dt_draw_curve_calc_values_V2_periodic(dt_draw_curve_t *c, const float min, const float max, const int res, float *x, float *y)
Definition draw.h:314
static void dt_draw_shape_lines(const dt_masks_dash_type_t dash_type, const gboolean source, cairo_t *cr, const int nb, const gboolean selected, const float zoom_scale, const float *points, const int points_count, const shape_draw_function_t *draw_shape_func)
Draw the lines of a mask shape.
Definition draw.h:691
static void dt_draw_grid_zoomed(cairo_t *cr, const int num, const float left, const float top, const float right, const float bottom, const float width, const float height, const float zoom_factor, const float zoom_offset_x, const float zoom_offset_y)
Definition draw.h:145
static void dt_draw_node(cairo_t *cr, const gboolean square, const gboolean point_action, const gboolean selected, const float zoom_scale, const float x, const float y)
Draw an node point of a mask.
Definition draw.h:561
static void _draw_arrow_tail(cairo_t *cr, const float arrow_bud_x, const float arrow_bud_y, const float tail[2], const gboolean draw_tail)
Definition draw.h:763
#define DT_PIXEL_APPLY_DPI(value)
Definition gtk.h:38
@ linear
Definition lightroom.c:388
size_t size
Definition mipmap_cache.c:3
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
int CurveDataSampleV2Periodic(CurveData *curve, CurveSample *sample)
Definition splines.cpp:845
int CurveDataSampleV2(CurveData *curve, CurveSample *sample)
Definition splines.cpp:749
Definition curve_tools.h:56
Definition curve_tools.h:76
struct dt_gui_gtk_t * gui
Definition darktable.h:541
Definition draw.h:81
CurveSample csample
Definition draw.h:83
CurveData c
Definition draw.h:82
double overlay_contrast
Definition gtk.h:115
double overlay_red
Definition gtk.h:115
double overlay_green
Definition gtk.h:115
double overlay_blue
Definition gtk.h:115
#define MIN(a, b)
Definition thinplate.c:23
#define MAX(a, b)
Definition thinplate.c:20