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-2013, 2016 johannes hanika.
4 Copyright (C) 2010-2011 Henrik Andersson.
5 Copyright (C) 2010, 2012-2014, 2016, 2018 Tobias Ellinghaus.
6 Copyright (C) 2011 Jochen Schroeder.
7 Copyright (C) 2011 Robert Bieber.
8 Copyright (C) 2012 Richard Wonka.
9 Copyright (C) 2014, 2016 Roman Lebedev.
10 Copyright (C) 2018-2020, 2025 Aurélien PIERRE.
11 Copyright (C) 2019 Andreas Schneider.
12 Copyright (C) 2019 Edgardo Hoszowski.
13 Copyright (C) 2019 Heiko Bauke.
14 Copyright (C) 2019 Jakub Filipowicz.
15 Copyright (C) 2019-2020, 2022 Pascal Obry.
16 Copyright (C) 2019 Philippe Weyland.
17 Copyright (C) 2020, 2022 Chris Elston.
18 Copyright (C) 2020-2021 Dan Torop.
19 Copyright (C) 2020 Ralf Brown.
20 Copyright (C) 2022 Aldric Renaudin.
21 Copyright (C) 2022 Martin Bařinka.
22 Copyright (C) 2025 Alynx Zhou.
23 Copyright (C) 2026 Guillaume Stutin.
24
25 darktable is free software: you can redistribute it and/or modify
26 it under the terms of the GNU General Public License as published by
27 the Free Software Foundation, either version 3 of the License, or
28 (at your option) any later version.
29
30 darktable is distributed in the hope that it will be useful,
31 but WITHOUT ANY WARRANTY; without even the implied warranty of
32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 GNU General Public License for more details.
34
35 You should have received a copy of the GNU General Public License
36 along with darktable. If not, see <http://www.gnu.org/licenses/>.
37*/
38
39#ifndef DT_WIDGETS_DRAW_H
40#define DT_WIDGETS_DRAW_H
41
42/* Cairo drawing shared across the application: grids, histograms, mask overlay shapes, and
43 * the spline sampler the tone-curve widgets draw from.
44 *
45 * This is a leaf header on purpose. Everything it paints with -- the overlay tint, the theme
46 * palette, the DPI scale, the mouse hit radius -- is read through widgets/widget_settings.h,
47 * which the application pushes into. Nothing here reaches for a global, so no drawing code
48 * has to drag in gui/ or develop/ to put a line on screen. The one develop/ type it mentions,
49 * dt_develop_t, is an opaque pointer threaded through to shape callbacks and never
50 * dereferenced.
51 */
52
53#include "common/curve_tools.h"
54#include "math/splines.h"
55#include "system/mem_alloc.h"
56#include "system/openmp.h" // __OMP_DECLARE_SIMD__, __OMP_PARALLEL_FOR_SIMD__
57#include "widgets/paint.h" // DTGTKCairoPaintIconFunc
58#include "widgets/stroke_raster.h" // dt_stroke_raster_path()
60
61#include <cairo.h>
62#include <glib.h>
63#include <gtk/gtk.h>
64#include <math.h>
65#include <stdint.h>
66#include <stdlib.h>
67
68#ifdef __cplusplus
69extern "C" {
70#endif
71
72struct dt_develop_t;
73
74#ifndef M_PI
75#define M_PI 3.141592654
76#endif
77
78// TODO: enter directly the values applied to this factor in each following macro later once
79// we're happy with it.
80#define DT_DRAW_SIZE_GLOBAL_FACTOR 0.75f
81
83#define DT_DRAW_SIZE_LINE DT_PIXEL_APPLY_DPI_DPP(1.5f * DT_DRAW_SIZE_GLOBAL_FACTOR)
84#define DT_DRAW_SIZE_LINE_SELECTED DT_PIXEL_APPLY_DPI_DPP(3.0f * DT_DRAW_SIZE_GLOBAL_FACTOR)
85#define DT_DRAW_SIZE_LINE_HIGHLIGHT (DT_PIXEL_APPLY_DPI_DPP(4.0f * DT_DRAW_SIZE_GLOBAL_FACTOR) + DT_DRAW_SIZE_LINE)
86#define DT_DRAW_SIZE_LINE_HIGHLIGHT_SELECTED (DT_PIXEL_APPLY_DPI_DPP(5.0f * DT_DRAW_SIZE_GLOBAL_FACTOR) + DT_DRAW_SIZE_LINE_SELECTED)
87#define DT_DRAW_SIZE_CROSS DT_PIXEL_APPLY_DPI_DPP(7.0f * DT_DRAW_SIZE_GLOBAL_FACTOR)
88
90#define DT_DRAW_SCALE_DASH DT_PIXEL_APPLY_DPI_DPP(12.0f * DT_DRAW_SIZE_GLOBAL_FACTOR)
91#define DT_DRAW_SCALE_ARROW DT_PIXEL_APPLY_DPI_DPP(18.0f * DT_DRAW_SIZE_GLOBAL_FACTOR)
92
93// radius/width of node (handles are set to be 3/4 of a node size)
94#define DT_DRAW_RADIUS_NODE DT_PIXEL_APPLY_DPI_DPP(5.0f * DT_DRAW_SIZE_GLOBAL_FACTOR)
95#define DT_DRAW_RADIUS_NODE_SELECTED (1.25f * DT_DRAW_RADIUS_NODE)
96
97/***** PRIMITIVES */
98
100static inline void dt_draw_star(cairo_t *cr, float x, float y, float r1, float r2)
101{
102 const float d = 2.0 * M_PI * 0.1f;
103 const float dx[10] = { sinf(0.0), sinf(d), sinf(2 * d), sinf(3 * d), sinf(4 * d),
104 sinf(5 * d), sinf(6 * d), sinf(7 * d), sinf(8 * d), sinf(9 * d) };
105 const float dy[10] = { cosf(0.0), cosf(d), cosf(2 * d), cosf(3 * d), cosf(4 * d),
106 cosf(5 * d), cosf(6 * d), cosf(7 * d), cosf(8 * d), cosf(9 * d) };
107
108 cairo_move_to(cr, x + r1 * dx[0], y - r1 * dy[0]);
109 for(int k = 1; k < 10; k++)
110 if(k & 1)
111 cairo_line_to(cr, x + r2 * dx[k], y - r2 * dy[k]);
112 else
113 cairo_line_to(cr, x + r1 * dx[k], y - r1 * dy[k]);
114 cairo_close_path(cr);
115}
116
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
125static inline void set_color(cairo_t *cr, GdkRGBA color)
126{
127 cairo_set_source_rgba(cr, color.red, color.green, color.blue, color.alpha);
128}
129
130
138
145
147static inline void dt_draw_set_color_overlay(cairo_t *cr, gboolean bright, double alpha)
148{
150 const double amt = bright ? 0.5 + overlay->contrast * 0.5
151 : (1.0 - overlay->contrast) * 0.5;
152
153 cairo_set_source_rgba(cr, overlay->red * amt, overlay->green * amt, overlay->blue * amt, alpha);
154}
155
156
157
158static inline void dt_draw_grid(cairo_t *cr, const int num, const int left, const int top, const int right,
159 const int bottom)
160{
161 float width = right - left;
162 float height = bottom - top;
163
164 for(int k = 1; k < num; k++)
165 {
166 dt_draw_line(cr, left + k / (float)num * width, top, left + k / (float)num * width, bottom);
167 cairo_stroke(cr);
168 dt_draw_line(cr, left, top + k / (float)num * height, right, top + k / (float)num * height);
169 cairo_stroke(cr);
170 }
171}
172
173static inline float dt_curve_to_mouse(const float x, const float zoom_factor, const float offset)
174{
175 return (x - offset) * zoom_factor;
176}
177
178/* left, right, top, bottom are in curve coordinates [0..1] */
179static inline void dt_draw_grid_zoomed(cairo_t *cr, const int num, const float left, const float top,
180 const float right, const float bottom, const float width,
181 const float height, const float zoom_factor, const float zoom_offset_x,
182 const float zoom_offset_y)
183{
184 for(int k = 1; k < num; k++)
185 {
186 dt_draw_line(cr, dt_curve_to_mouse(left + k / (float)num, zoom_factor, zoom_offset_x) * width,
187 dt_curve_to_mouse(top, zoom_factor, zoom_offset_y) * -height,
188 dt_curve_to_mouse(left + k / (float)num, zoom_factor, zoom_offset_x) * width,
189 dt_curve_to_mouse(bottom, zoom_factor, zoom_offset_y) * -height);
190 cairo_stroke(cr);
191
192 dt_draw_line(cr, dt_curve_to_mouse(left, zoom_factor, zoom_offset_x) * width,
193 dt_curve_to_mouse(top + k / (float)num, zoom_factor, zoom_offset_y) * -height,
194 dt_curve_to_mouse(right, zoom_factor, zoom_offset_x) * width,
195 dt_curve_to_mouse(top + k / (float)num, zoom_factor, zoom_offset_y) * -height);
196 cairo_stroke(cr);
197 }
198}
199
200__OMP_DECLARE_SIMD__(uniform(base))
201static inline float dt_log_scale_axis(const float x, const float base)
202{
203 return logf(x * (base - 1.0f) + 1.f) / logf(base);
204}
205
206static inline void dt_draw_loglog_grid(cairo_t *cr, const int num, const int left, const int top, const int right,
207 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 + x * width, top, left + x * 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
222static inline void dt_draw_semilog_x_grid(cairo_t *cr, const int num, const int left, const int top,
223 const int right, const int bottom, const float base)
224{
225 float width = right - left;
226 float height = bottom - top;
227
228 for(int k = 1; k < num; k++)
229 {
230 const float x = dt_log_scale_axis(k / (float)num, base);
231 dt_draw_line(cr, left + x * width, top, left + x * width, bottom);
232 cairo_stroke(cr);
233 dt_draw_line(cr, left, top + k / (float)num * height, right, top + k / (float)num * height);
234 cairo_stroke(cr);
235 }
236}
237
238static inline void dt_draw_semilog_y_grid(cairo_t *cr, const int num, const int left, const int top,
239 const int right, const int bottom, const float base)
240{
241 float width = right - left;
242 float height = bottom - top;
243
244 for(int k = 1; k < num; k++)
245 {
246 const float x = dt_log_scale_axis(k / (float)num, base);
247 dt_draw_line(cr, left + k / (float)num * width, top, left + k / (float)num * width, bottom);
248 cairo_stroke(cr);
249 dt_draw_line(cr, left, top + x * height, right, top + x * height);
250 cairo_stroke(cr);
251 }
252}
253
254
255static inline void dt_draw_vertical_lines(cairo_t *cr, const int num, const int left, const int top,
256 const int right, const int bottom)
257{
258 float width = right - left;
259
260 for(int k = 1; k < num; k++)
261 {
262 cairo_move_to(cr, left + k / (float)num * width, top);
263 cairo_line_to(cr, left + k / (float)num * width, bottom);
264 cairo_stroke(cr);
265 }
266}
267
268static inline void dt_draw_horizontal_lines(cairo_t *cr, const int num, const int left, const int top,
269 const int right, const int bottom)
270{
271 float height = bottom - top;
272
273 for(int k = 1; k < num; k++)
274 {
275 cairo_move_to(cr, left, top + k / (float)num * height);
276 cairo_line_to(cr, right, top + k / (float)num * height);
277 cairo_stroke(cr);
278 }
279}
280
281static inline dt_draw_curve_t *dt_draw_curve_new(const float min, const float max, unsigned int type)
282{
283 dt_draw_curve_t *c = (dt_draw_curve_t *)malloc(sizeof(dt_draw_curve_t));
284 c->csample.m_samplingRes = 0x10000;
285 c->csample.m_outputRes = 0x10000;
286 c->csample.m_Samples = (uint16_t *)malloc(sizeof(uint16_t) * 0x10000);
287
288 c->c.m_spline_type = type;
289 c->c.m_numAnchors = 0;
290 c->c.m_min_x = 0.0;
291 c->c.m_max_x = 1.0;
292 c->c.m_min_y = 0.0;
293 c->c.m_max_y = 1.0;
294 return c;
295}
296
298{
299 dt_free(c->csample.m_Samples);
300 dt_free(c);
301}
302
303static inline void dt_draw_curve_set_point(dt_draw_curve_t *c, const int num, const float x, const float y)
304{
305 c->c.m_anchors[num].x = x;
306 c->c.m_anchors[num].y = y;
307}
308
309static inline void dt_draw_curve_smaple_values(dt_draw_curve_t *c, const float min, const float max, const int res,
310 float *x, float *y)
311{
312 if(x)
313 {
315 for(int k = 0; k < res; k++) x[k] = k * (1.0f / res);
316 }
317 if(y)
318 {
320 for(int k = 0; k < res; k++) y[k] = min + (max - min) * c->csample.m_Samples[k] * (1.0f / 0x10000);
321 }
322}
323
324static inline void dt_draw_curve_calc_values(dt_draw_curve_t *c, const float min, const float max, const int res,
325 float *x, float *y)
326{
327 c->csample.m_samplingRes = res;
328 c->csample.m_outputRes = 0x10000;
329 CurveDataSample(&c->c, &c->csample);
331}
332
333static inline void dt_draw_curve_calc_values_V2_nonperiodic(dt_draw_curve_t *c, const float min, const float max,
334 const int res, float *x, float *y)
335{
336 c->csample.m_samplingRes = res;
337 c->csample.m_outputRes = 0x10000;
338 CurveDataSampleV2(&c->c, &c->csample);
340}
341
342static inline void dt_draw_curve_calc_values_V2_periodic(dt_draw_curve_t *c, const float min, const float max,
343 const int res, float *x, float *y)
344{
345 c->csample.m_samplingRes = res;
346 c->csample.m_outputRes = 0x10000;
347 CurveDataSampleV2Periodic(&c->c, &c->csample);
349}
350
351static inline void dt_draw_curve_calc_values_V2(dt_draw_curve_t *c, const float min, const float max,
352 const int res, float *x, float *y, const gboolean periodic)
353{
354 if(periodic)
356 else
358 }
359
360static inline float dt_draw_curve_calc_value(dt_draw_curve_t *c, const float x)
361{
362 float xa[20], ya[20];
363 float val = 0.f;
364 float *ypp = NULL;
365 for(int i = 0; i < c->c.m_numAnchors; i++)
366 {
367 xa[i] = c->c.m_anchors[i].x;
368 ya[i] = c->c.m_anchors[i].y;
369 }
370 ypp = interpolate_set(c->c.m_numAnchors, xa, ya, c->c.m_spline_type);
371 if(ypp)
372 {
373 val = interpolate_val(c->c.m_numAnchors, xa, x, ya, ypp, c->c.m_spline_type);
374 dt_free(ypp);
375 }
376 return MIN(MAX(val, c->c.m_min_y), c->c.m_max_y);
377}
378
379static inline int dt_draw_curve_add_point(dt_draw_curve_t *c, const float x, const float y)
380{
381 c->c.m_anchors[c->c.m_numAnchors].x = x;
382 c->c.m_anchors[c->c.m_numAnchors].y = y;
383 c->c.m_numAnchors++;
384 return 0;
385}
386
387// linear x linear y
388static inline void dt_draw_histogram_8_linxliny(cairo_t *cr, const uint32_t *hist, int32_t channels,
389 int32_t channel)
390{
391 cairo_move_to(cr, 0, 0);
392 for(int k = 0; k < 256; k++) cairo_line_to(cr, k, hist[channels * k + channel]);
393 cairo_line_to(cr, 255, 0);
394 cairo_close_path(cr);
395 cairo_fill(cr);
396}
397
398static inline void dt_draw_histogram_8_zoomed(cairo_t *cr, const uint32_t *hist, int32_t channels, int32_t channel,
399 const float zoom_factor, const float zoom_offset_x,
400 const float zoom_offset_y, gboolean linear)
401{
402 cairo_move_to(cr, -zoom_offset_x, -zoom_offset_y);
403 for(int k = 0; k < 256; k++)
404 {
405 const float value = ((float)hist[channels * k + channel] - zoom_offset_y) * zoom_factor;
406 const float hist_value = value < 0 ? 0.f : value;
407 cairo_line_to(cr, ((float)k - zoom_offset_x) * zoom_factor, linear ? hist_value : logf(1.0f + hist_value));
408 }
409 cairo_line_to(cr, (255.f - zoom_offset_x), -zoom_offset_y * zoom_factor);
410 cairo_close_path(cr);
411 cairo_fill(cr);
412}
413
414// log x (scalable) & linear y
415static inline void dt_draw_histogram_8_logxliny(cairo_t *cr, const uint32_t *hist, int32_t channels,
416 int32_t channel, float base_log)
417{
418 cairo_move_to(cr, 0, 0);
419 for(int k = 0; k < 256; k++)
420 {
421 const float x = logf((float)k / 255.0f * (base_log - 1.0f) + 1.0f) / logf(base_log) * 255.0f;
422 const float y = hist[channels * k + channel];
423 cairo_line_to(cr, x, y);
424 }
425 cairo_line_to(cr, 255, 0);
426 cairo_close_path(cr);
427 cairo_fill(cr);
428}
429
430// log x (scalable) & log y
431static inline void dt_draw_histogram_8_logxlogy(cairo_t *cr, const uint32_t *hist, int32_t channels,
432 int32_t channel, float base_log)
433{
434 cairo_move_to(cr, 0, 0);
435 for(int k = 0; k < 256; k++)
436 {
437 const float x = logf((float)k / 255.0f * (base_log - 1.0f) + 1.0f) / logf(base_log) * 255.0f;
438 const float y = logf(1.0 + hist[channels * k + channel]);
439 cairo_line_to(cr, x, y);
440 }
441 cairo_line_to(cr, 255, 0);
442 cairo_close_path(cr);
443 cairo_fill(cr);
444}
445
446// linear x log y
447static inline void dt_draw_histogram_8_linxlogy(cairo_t *cr, const uint32_t *hist, int32_t channels,
448 int32_t channel)
449{
450 cairo_move_to(cr, 0, 0);
451 for(int k = 0; k < 256; k++) cairo_line_to(cr, k, logf(1.0 + hist[channels * k + channel]));
452 cairo_line_to(cr, 255, 0);
453 cairo_close_path(cr);
454 cairo_fill(cr);
455}
456
457// log x (scalable)
458static inline void dt_draw_histogram_8_log_base(cairo_t *cr, const uint32_t *hist, int32_t channels,
459 int32_t channel, const gboolean linear, float base_log)
460{
461
462 if(linear) // linear y
463 dt_draw_histogram_8_logxliny(cr, hist, channels, channel, base_log);
464 else // log y
465 dt_draw_histogram_8_logxlogy(cr, hist, channels, channel, base_log);
466}
467
468// linear x
469static inline void dt_draw_histogram_8(cairo_t *cr, const uint32_t *hist, int32_t channels, int32_t channel,
470 const gboolean linear)
471{
472 if(linear) // linear y
473 dt_draw_histogram_8_linxliny(cr, hist, channels, channel);
474 else // log y
475 dt_draw_histogram_8_linxlogy(cr, hist, channels, channel);
476}
477
479static inline void dt_draw_cairo_to_gdk_pixbuf(uint8_t *data, unsigned int width, unsigned int height)
480{
481 for(uint32_t y = 0; y < height; y++)
482 for(uint32_t x = 0; x < width; x++)
483 {
484 uint8_t *r, *g, *b, *a, tmp;
485 r = &data[(y * width + x) * 4 + 0];
486 g = &data[(y * width + x) * 4 + 1];
487 b = &data[(y * width + x) * 4 + 2];
488 a = &data[(y * width + x) * 4 + 3];
489
490 // switch r and b
491 tmp = *r;
492 *r = *b;
493 *b = tmp;
494
495 // cairo uses premultiplied alpha, reverse that
496 if(*a != 0)
497 {
498 float inv_a = 255.0 / *a;
499 *r *= inv_a;
500 *g *= inv_a;
501 *b *= inv_a;
502 }
503 }
504}
505
506static inline void dt_cairo_perceptual_gradient(cairo_pattern_t *grad, double alpha)
507{
508 // Create a linear gradient from black to white
509 cairo_pattern_add_color_stop_rgba(grad, 0.0, 0.0, 0.0, 0.0, alpha);
510 cairo_pattern_add_color_stop_rgba(grad, 1.0, 1.0, 1.0, 1.0, alpha);
511}
512
513static inline GdkPixbuf *dt_draw_paint_to_pixbuf
514 (GtkWidget *widget, const guint pixbuf_size, const int flags,
515 void (*dtgtk_cairo_paint_fct)(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data))
516{
517 GdkRGBA fg_color;
518 GtkStyleContext *context = gtk_widget_get_style_context(widget);
519 GtkStateFlags state = gtk_widget_get_state_flags(widget);
520 gtk_style_context_get_color(context, state, &fg_color);
521
522 const int dim = DT_PIXEL_APPLY_DPI(pixbuf_size);
523 cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dim, dim);
524 cairo_t *cr = cairo_create(cst);
525 gdk_cairo_set_source_rgba(cr, &fg_color);
526 (*dtgtk_cairo_paint_fct)(cr, 0, 0, dim, dim, flags, NULL);
527 cairo_destroy(cr);
528 uint8_t *data = cairo_image_surface_get_data(cst);
529 dt_draw_cairo_to_gdk_pixbuf(data, dim, dim);
530 const size_t size = (size_t)dim * dim * 4;
531 uint8_t *buf = (uint8_t *)malloc(size);
532 memcpy(buf, data, size);
533 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data(buf, GDK_COLORSPACE_RGB, TRUE, 8, dim, dim, dim * 4,
534 (GdkPixbufDestroyNotify)free, NULL);
535 cairo_surface_destroy(cst);
536 return pixbuf;
537}
538
541static inline void dt_draw_rounded_rectangle_path(cairo_t *cr, float x, float y, float width, float height,
542 float radius)
543{
544 const float degrees = M_PI / 180.0;
545 cairo_new_sub_path(cr);
546 cairo_arc(cr, x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees);
547 cairo_arc(cr, x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees);
548 cairo_arc(cr, x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees);
549 cairo_arc(cr, x + radius, y + radius, radius, 180 * degrees, 270 * degrees);
550 cairo_close_path(cr);
551}
552
554static inline void dt_gui_draw_rounded_rectangle(cairo_t *cr, float width, float height, float x, float y)
555{
557 cairo_fill(cr);
558}
559
562static inline void dt_draw_plus_sign(cairo_t *cr, float x, float y, float size, float line_width_scale)
563{
564 const float base_line_width = cairo_get_line_width(cr);
565 cairo_set_line_width(cr, base_line_width * line_width_scale);
566
567 cairo_move_to(cr, x, y - size);
568 cairo_line_to(cr, x, y + size);
569 cairo_move_to(cr, x - size, y);
570 cairo_line_to(cr, x + size, y);
571
572 cairo_stroke(cr);
573 cairo_set_line_width(cr, base_line_width);
574}
575
576/***** SHAPES */
577
578// Helper that fills the current path with CAIRO_OPERATOR_CLEAR,
579// effectively erasing all drawings below,
580// but preserving the path for further drawing.
581static void _draw_fill_clear(cairo_t *cr, gboolean preserve)
582{
583 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
584 if(preserve)
585 cairo_fill_preserve(cr);
586 else
587 cairo_fill(cr);
588 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
589}
590
591static void _fill_clear(cairo_t *cr)
592{
594}
595
596static void _fill_clear_preserve(cairo_t *cr)
597{
599}
600
602static inline void dt_draw_dash_lengths(const dt_draw_dash_type_t type, const float zoom_scale, double *on, double *off)
603{
604 *on = 0.0;
605 *off = 0.0;
606 switch(type)
607 {
609 *on = DT_DRAW_SCALE_DASH / zoom_scale;
610 *off = DT_DRAW_SCALE_DASH / zoom_scale;
611 break;
613 *on = (DT_DRAW_SCALE_DASH * 0.25f) / zoom_scale;
614 *off = DT_DRAW_SCALE_DASH / zoom_scale;
615 break;
616 default:
617 break;
618 }
619}
620
621static inline void dt_draw_set_dash_style(cairo_t *cr, dt_draw_dash_type_t type, float zoom_scale)
622{
623 // return early if no dash is needed
625 {
626 cairo_set_dash(cr, NULL, 0, 0);
627 return;
628 }
629
630 double pattern[2];
631
632 switch(type)
633 {
634 case DT_MASKS_NO_DASH:
635 pattern[0] = 0.0f;
636 pattern[1] = 0.0f;
637 break;
638
640 pattern[0] = DT_DRAW_SCALE_DASH / zoom_scale;
641 pattern[1] = DT_DRAW_SCALE_DASH / zoom_scale;
642 break;
643
645 pattern[0] = (DT_DRAW_SCALE_DASH * 0.25f) / zoom_scale;
646 pattern[1] = (DT_DRAW_SCALE_DASH) / zoom_scale;
647 break;
648
649 default:
650 cairo_set_dash(cr, NULL, 0, 0);
651 return;
652
653 }
654 const int pattern_len = 2;
655 cairo_set_dash(cr, pattern, pattern_len, 0);
656}
657
669static 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)
670{
671 cairo_save(cr);
672
673 // See dt_draw_rounded_rectangle_path() for the same guard: cairo_arc() appends a line from
674 // whatever current point a caller's unrelated, unclosed path left behind. cairo_new_sub_path(),
675 // not cairo_new_path(): starts fresh without discarding a path a caller may still be building.
676 cairo_new_sub_path(cr);
677
678 const float node_width = (selected || point_action) ? DT_DRAW_RADIUS_NODE_SELECTED / zoom_scale : DT_DRAW_RADIUS_NODE / zoom_scale;
679 // square for corner nodes, circle for others (curve)
680 if(square)
681 {
682 const float pos = node_width * 0.7071f; // radius * sin(45°) to have the same diagonal as the circle
683 cairo_rectangle(cr, x - pos, y - pos, node_width * 2.f, node_width * 2.f);
684 }
685 else
686 cairo_arc(cr, x, y, node_width * 1.2f, 0.0, 2.0 * M_PI);
687
688 // Erase all drawings below
690
691 const float line_width = (point_action && selected) ? DT_DRAW_SIZE_LINE_SELECTED / zoom_scale
692 : DT_DRAW_SIZE_LINE / zoom_scale;
693
694 cairo_set_line_width(cr, line_width);
695 dt_draw_set_color_overlay(cr, TRUE, selected || point_action ? 1 : 0.8);
696 cairo_fill_preserve(cr);
697
698 // draw dark border
699 cairo_set_line_width(cr, (selected && !point_action) ? line_width * 2. : line_width);
701 cairo_stroke(cr);
702
704 {
705 const float debug_radius = DT_GUI_MOUSE_EFFECT_RADIUS;
706 cairo_arc(cr, x, y, debug_radius, 0.0, 2.0 * M_PI);
707 cairo_set_line_width(cr, line_width);
708 cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 1.0);
709 cairo_stroke(cr);
710 }
711
712 cairo_restore(cr);
713}
714
725static inline void dt_draw_handle(cairo_t *cr, const float pt[2], const float zoom_scale,
726 const float handle[2], const gboolean selected, const gboolean square)
727{
728 cairo_save(cr);
729
730
731 // Draw only if the line is long enough
732 // and shorten the line by the size of the nodes so it does not overlap with them
733 //float shorten = 0; //(DT_DRAW_RADIUS_NODE / zoom_scale) * 0.5f;
734 //float f = shorten / tail_len;
735 if(pt)
736 {
737 float delta_x = handle[0] - pt[0];
738 float delta_y = handle[1] - pt[1];
739 float start_x = pt[0] + delta_x;
740 float start_y = pt[1] + delta_y;
741 float end_x = handle[0] - delta_x;
742 float end_y = handle[1] - delta_y;
743 cairo_move_to(cr, start_x, start_y);
744 cairo_line_to(cr, end_x, end_y);
745
746 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE_HIGHLIGHT * 0.6 / zoom_scale);
748 cairo_stroke_preserve(cr);
749 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE * 0.6 / zoom_scale);
751 cairo_stroke(cr);
752 }
753
754 // Draw the control handle (1/4 smaller than a node)
755 const float handle_radius = 0.75 * (selected ? DT_DRAW_RADIUS_NODE_SELECTED / zoom_scale
756 : DT_DRAW_RADIUS_NODE / zoom_scale);
757
758 // Same guard as dt_draw_node(): when pt is NULL the tail above is skipped, so nothing has
759 // cleared a caller's dangling current point yet before this cairo_arc(). See there for why.
760 cairo_new_sub_path(cr);
761
762 if(square)
763 {
764 const float square_width = handle_radius * 0.7071f; // handle_radius * sin(45°) to have the same diagonal as the circle
765 cairo_rectangle(cr, handle[0] - square_width, handle[1] - square_width, square_width * 2.f, square_width * 2.f);
766 }
767 else
768 cairo_arc(cr, handle[0], handle[1], handle_radius, 0, 2.0 * M_PI);
769
770 const float line_width_dark = selected
772 : (DT_DRAW_SIZE_LINE_HIGHLIGHT / zoom_scale);
773 const float line_width_bright = selected
774 ? (DT_DRAW_SIZE_LINE_SELECTED / zoom_scale)
775 : (DT_DRAW_SIZE_LINE / zoom_scale);
776
777 // OUTLINE (dark)
778 cairo_set_line_width(cr, line_width_dark * 1.125);
780 cairo_stroke_preserve(cr);
781 // NORMAL (bright)
782 cairo_set_line_width(cr, line_width_bright * 1.5);
784 cairo_stroke_preserve(cr);
785 // Erase all drawings below
786 _fill_clear(cr);
787
788
789 // uncomment this part if you want to see "real" control points
790 /*cairo_move_to(cr, gpt->points[n*6+2],gpt->points[n*6+3]);
791 cairo_line_to(cr, gpt->points[n*6],gpt->points[n*6+1]);
792 cairo_stroke(cr);
793 cairo_move_to(cr, gpt->points[n*6+2],gpt->points[n*6+3]);
794 cairo_line_to(cr, gpt->points[n*6+4],gpt->points[n*6+5]);
795 cairo_stroke(cr);*/
796
797 cairo_restore(cr);
798}
799
800// dev is the develop instance owning the shape being drawn. It is threaded explicitly so shape
801// drawing code never has to reach for the darktable.develop global (which would couple every
802// shape file to the whole application and hide which instance is read).
803//
804// skips/skip_count are the shape's EXCLUSION LIST: the spans of the outline that must not be
805// drawn, because the offset curve doubles back on itself there. They travel alongside the buffer
806// rather than inside it -- the alternative, and what this replaced, was blanking those samples to
807// NaN and having every walker test for it. That encoding hides in a buffer of plain floats, has
808// to be re-learned by each new consumer, and is silently wrong for any consumer that forgets:
809// see the entry in masks_types.h for the two bugs it hosted. A shape with nothing to exclude
810// passes NULL and 0.
811//
812// Declared as a struct tag so this header stays free of masks_types.h -- a widget helper has no
813// business inheriting the masks vocabulary.
815typedef void (*shape_draw_function_t)(struct dt_develop_t *dev, cairo_t *cr, const float *points, const int points_count, const int nb, const gboolean border, const gboolean source,
816 const struct dt_masks_skip_range_t *skips, const int skip_count);
817
831static inline void dt_draw_shape_lines(struct dt_develop_t *dev, const dt_draw_dash_type_t dash_type, const gboolean source, cairo_t *cr, const int nb, const gboolean selected,
832 const float zoom_scale, const float *points, const int points_count, const shape_draw_function_t *draw_shape_func, const cairo_line_cap_t line_cap,
833 const struct dt_masks_skip_range_t *skips, const int skip_count)
834{
835 cairo_save(cr);
836
837 /* An overlay is guide lines about a pixel wide, not artwork: cairo's best-quality analytic
838 * coverage buys nothing visible here and costs about half the time of drawing them. Measured
839 * per shape per frame at fit zoom on issue #1313's raw: 2.05 -> 1.20 ms for the brush's border,
840 * 1.39 -> 0.78 ms for polygon #2's. Scoped by the cairo_save() above, so nothing else -- the
841 * node handles in particular, which are small filled discs where the difference would show --
842 * inherits it. */
843 cairo_set_antialias(cr, CAIRO_ANTIALIAS_FAST);
844
845 cairo_set_line_cap(cr, line_cap);
846 // Are we drawing a border ?
847 const gboolean border = (dash_type != DT_MASKS_NO_DASH);
848
849 // Draw the shape from the integrated function if any
850 if(points && points_count >= 2 && draw_shape_func)
851 (*draw_shape_func)(dev, cr, points, points_count, nb, border, FALSE, skips, skip_count);
852
853 const dt_draw_dash_type_t dash = (dash_type && !source)
854 ? dash_type : DT_MASKS_NO_DASH;
855
856 dt_draw_set_dash_style(cr, dash, zoom_scale);
857
858 const float line_width_dark = selected
860 : DT_DRAW_SIZE_LINE_HIGHLIGHT / zoom_scale;
861 const float line_width_bright = selected
862 ? DT_DRAW_SIZE_LINE_SELECTED / zoom_scale
863 : DT_DRAW_SIZE_LINE / zoom_scale;
864
865 float alpha = dash_type ? 0.3f : 0.9f;
866 if(source) alpha *= 0.5f;
867 const float alpha_bright = source ? 0.4f : 0.8f;
868
869 /* The path is pixels already: the outline was sampled at the resolution it is drawn at.
870 * Paint it as such wherever the surface allows -- the overlay's own canvas, any image
871 * surface, the group cairo pushed on one -- and keep the cairo strokes below for every other
872 * target. The rasteriser reproduces exactly these: the same two passes, widths, colours,
873 * dashes and caps. */
874 dt_stroke_style_t style = { 0 };
876 const double dark_amount = (1.0 - overlay->contrast) * 0.5;
877 const double bright_amount = 0.5 + overlay->contrast * 0.5;
878 style.dark = (dt_stroke_pass_t){ .width = line_width_dark,
879 .red = overlay->red * dark_amount,
880 .green = overlay->green * dark_amount,
881 .blue = overlay->blue * dark_amount,
882 .alpha = alpha };
883 style.bright = (dt_stroke_pass_t){ .width = line_width_bright,
884 .red = overlay->red * bright_amount,
885 .green = overlay->green * bright_amount,
886 .blue = overlay->blue * bright_amount,
887 .alpha = alpha_bright };
888 dt_draw_dash_lengths(dash, zoom_scale, &style.dash_on, &style.dash_off);
889 style.round_caps = (line_cap == CAIRO_LINE_CAP_ROUND);
890 if(dt_stroke_raster_path(cr, &style))
891 {
892 cairo_restore(cr);
893 return;
894 }
895
896 // OUTLINE (dark)
897 cairo_set_line_width(cr, line_width_dark);
899 cairo_stroke_preserve(cr);
900
901 // NORMAL (bright)
902 cairo_set_line_width(cr, line_width_bright);
903 dt_draw_set_color_overlay(cr, TRUE, alpha_bright);
904 cairo_stroke(cr);
905
906 cairo_restore(cr);
907}
908
931static inline double dt_draw_min_emit_step(cairo_t *cr)
932{
933 /* ONE device pixel, not half of one.
934 *
935 * Nothing an overlay draws is finer than the 1 px line it is drawn with, so a chord shorter
936 * than a pixel cannot show: the deviation a straight chord makes from the curve it replaces is
937 * step^2 / 8R, which for a 1 px chord is under an eighth of a pixel for any curve of radius
938 * 1 px or more. What it costs is real -- measured on issue #1313's brush at fit zoom, the
939 * dashed border went from 2163 segments and 2.05 ms per frame to 1098 and 1.85 ms with the
940 * default antialiasing, and 1.20 -> 0.76 ms with ANTIALIAS_FAST below.
941 *
942 * Do NOT read that as "coarser is always better". The cost is not per-segment: the same
943 * polyline split into 1, 11 or 57 separately stroked pieces measures 4.9, 3.8 and 3.7 ms, so
944 * batching strokes buys nothing and the per-segment styling that costs is free. What the step
945 * buys is fewer edges for the rasteriser, and it stops paying well before it starts to show. */
946 double dx = 1.0, dy = 1.0;
947 cairo_device_to_user_distance(cr, &dx, &dy);
948 const double step = fmin(fabs(dx), fabs(dy));
949 return isfinite(step) ? step : 0.0;
950}
951
952static inline void dt_draw_stroke_line(const dt_draw_dash_type_t dash_type, const gboolean source, cairo_t *cr,
953 const gboolean selected, const float zoom_scale, const cairo_line_cap_t line_cap)
954{
955 dt_draw_shape_lines(NULL, dash_type, source, cr, 0, selected, zoom_scale, NULL, 0, NULL, line_cap, NULL, 0);
956}
957
958static void _draw_arrow_head(cairo_t *cr, const float arrow[2], const float arrow_x_a, const float arrow_y_a,
959 const float arrow_x_b, const float arrow_y_b)
960{
961 //draw the arrow head
962 cairo_move_to(cr, arrow_x_a, arrow_y_a);
963 cairo_line_to(cr, arrow[0], arrow[1]);
964 cairo_line_to(cr, arrow_x_b, arrow_y_b);
965 // close the arrow head
966 cairo_close_path(cr);
967}
968
969static void _draw_arrow_tail(cairo_t *cr, const float arrow_bud_x, const float arrow_bud_y,
970 const float tail[2], const gboolean draw_tail)
971{
972 if(draw_tail) dt_draw_line(cr, arrow_bud_x, arrow_bud_y, tail[0], tail[1]);
973}
974
988static inline void dt_draw_arrow(cairo_t *cr, const float zoom_scale,const gboolean selected, const gboolean draw_tail,
989 const dt_draw_dash_type_t dash_style, const float arrow[2], const float tail[2], const float angle)
990{
991 // calculate the coordinates of the two base points of the arrow head
992 const float arrow_x_a = arrow[0] + (DT_DRAW_SCALE_ARROW / zoom_scale) * cosf(angle + (0.4f));
993 const float arrow_y_a = arrow[1] + (DT_DRAW_SCALE_ARROW / zoom_scale) * sinf(angle + (0.4f));
994 const float arrow_x_b = arrow[0] + (DT_DRAW_SCALE_ARROW / zoom_scale) * cosf(angle - (0.4f));
995 const float arrow_y_b = arrow[1] + (DT_DRAW_SCALE_ARROW / zoom_scale) * sinf(angle - (0.4f));
996 // Calculate the coordinates of the arrow base's midpoint
997 const float arrow_bud_x = (arrow_x_a + arrow_x_b) * 0.5f;
998 const float arrow_bud_y = (arrow_y_a + arrow_y_b) * 0.5f;
999
1000 cairo_save(cr);
1001 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
1002
1003 // we need to draw the arrow head and tail in two passes to get the dark and bright effect correctly
1004
1005 // dark
1006 {
1007 // arrow head
1008 _draw_arrow_head(cr, arrow, arrow_x_a, arrow_y_a, arrow_x_b, arrow_y_b);
1009 // Erase all drawings below
1011
1014
1015 if(selected)
1016 cairo_set_line_width(cr, 0.8f * DT_DRAW_SIZE_LINE_HIGHLIGHT_SELECTED / zoom_scale);
1017 else
1018 cairo_set_line_width(cr, 0.8f * DT_DRAW_SIZE_LINE_HIGHLIGHT / zoom_scale);
1019 cairo_stroke(cr);
1020
1021 // arrow tail
1022 _draw_arrow_tail(cr, arrow_bud_x, arrow_bud_y, tail, draw_tail);
1023 dt_draw_set_dash_style(cr, dash_style, zoom_scale);
1025 if(selected)
1026 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE_HIGHLIGHT_SELECTED / zoom_scale);
1027 else
1028 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE_HIGHLIGHT / zoom_scale);
1029 cairo_stroke(cr);
1030 }
1031
1032 // bright
1033 {
1034 // arrow head
1035 _draw_arrow_head(cr, arrow, arrow_x_a, arrow_y_a, arrow_x_b, arrow_y_b);
1036 // erase all drawings below
1037 cairo_set_source_rgba(cr, 0., 0., 0., 0.);
1038 cairo_fill_preserve(cr);
1039
1042 if(selected)
1043 cairo_set_line_width(cr, (2 * DT_DRAW_SIZE_LINE) / zoom_scale);
1044 else
1045 cairo_set_line_width(cr, (DT_DRAW_SIZE_LINE) / zoom_scale);
1046 cairo_stroke(cr);
1047
1048 // arrow tail
1049 _draw_arrow_tail(cr, arrow_bud_x, arrow_bud_y, tail, draw_tail);
1050 dt_draw_set_dash_style(cr, dash_style, zoom_scale);
1052 if(selected)
1053 cairo_set_line_width(cr, (3 * DT_DRAW_SIZE_LINE) / zoom_scale);
1054 else
1055 cairo_set_line_width(cr, (2 * DT_DRAW_SIZE_LINE) / zoom_scale);
1056 cairo_stroke(cr);
1057 }
1058 cairo_restore(cr);
1059}
1060
1061static inline void dt_draw_cross(cairo_t *cr, const float zoom_scale, const float x, const float y)
1062{
1063 const float dx = DT_DRAW_SIZE_CROSS / zoom_scale;
1064 const float dy = DT_DRAW_SIZE_CROSS / zoom_scale;
1065 cairo_save(cr);
1066
1067 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
1069 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE_HIGHLIGHT / zoom_scale);
1071
1072 cairo_move_to(cr, x + dx, y);
1073 cairo_line_to(cr, x - dx, y);
1074 cairo_move_to(cr, x, y + dy);
1075 cairo_line_to(cr, x, y - dy);
1076 cairo_stroke_preserve(cr);
1077
1078 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE / zoom_scale);
1080 cairo_stroke(cr);
1081
1082 cairo_restore(cr);
1083}
1084
1085static inline void dt_draw_source_shape(struct dt_develop_t *dev, cairo_t *cr, const float zoom_scale, const gboolean selected,
1086 const float *source_pts, const int source_pts_count, const int nodes_nb, const shape_draw_function_t *draw_shape_func)
1087{
1088 cairo_save(cr);
1089
1090 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
1092
1093 if(draw_shape_func)
1094 /* a source outline is a copy of the shape placed elsewhere; it carries no cuts */
1095 (*draw_shape_func)(dev, cr, source_pts, source_pts_count, nodes_nb, FALSE, TRUE, NULL, 0);
1096
1097 //dark line
1098 if(selected)
1099 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE_HIGHLIGHT_SELECTED / zoom_scale);
1100 else
1101 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE_HIGHLIGHT / zoom_scale);
1103 cairo_stroke_preserve(cr);
1104
1105 //bright line
1106 if(selected)
1107 cairo_set_line_width(cr, DT_DRAW_SIZE_LINE_SELECTED / zoom_scale);
1108 else
1109 cairo_set_line_width(cr, (1.5f * DT_DRAW_SIZE_LINE) / zoom_scale);
1111 cairo_stroke(cr);
1112
1113 cairo_restore(cr);
1114}
1115
1116static inline GdkPixbuf *dt_draw_get_pixbuf_from_cairo(DTGTKCairoPaintIconFunc paint, const int width, const int height)
1117{
1118 cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
1119 cairo_t *cr = cairo_create(cst);
1121 paint(cr, 0, 0, width, height, 0, NULL);
1122 cairo_destroy(cr);
1123
1124 guchar *data = cairo_image_surface_get_data(cst);
1126 const int stride = cairo_image_surface_get_stride(cst);
1127 const size_t size = (size_t)stride * height;
1128 guchar *buf = (guchar *)malloc(size);
1129 memcpy(buf, data, size);
1130 cairo_surface_destroy(cst);
1131
1132 return gdk_pixbuf_new_from_data(buf, GDK_COLORSPACE_RGB, TRUE, 8, width, height,
1133 stride, (GdkPixbufDestroyNotify)free, NULL);
1134}
1135
1136#ifdef __cplusplus
1137}
1138#endif
1139
1140#endif // DT_WIDGETS_DRAW_H
1141
1142// clang-format off
1143// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1144// vim: shiftwidth=2 expandtab tabstop=2 cindent
1145// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1146// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
static const float x
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
static const float const float const float min
const float max
const float top
float * interpolate_set(int n, float x[], float y[], unsigned int type)
int CurveDataSample(CurveData *curve, CurveSample *sample)
float interpolate_val(int n, float x[], float xval, float y[], float tangents[], unsigned int type)
GHashTable * selected
set of checked row labels, mirrored to conf on every change
static float dt_curve_to_mouse(const float x, const float zoom_factor, const float offset)
Definition draw.h:173
#define DT_DRAW_SCALE_DASH
Definition draw.h:90
#define DT_DRAW_SIZE_LINE
Definition draw.h:83
static void _draw_fill_clear(cairo_t *cr, gboolean preserve)
Definition draw.h:581
#define DT_DRAW_RADIUS_NODE_SELECTED
Definition draw.h:95
static void dt_draw_set_dash_style(cairo_t *cr, dt_draw_dash_type_t type, float zoom_scale)
Definition draw.h:621
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:514
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:324
static void dt_draw_stroke_line(const dt_draw_dash_type_t dash_type, const gboolean source, cairo_t *cr, const gboolean selected, const float zoom_scale, const cairo_line_cap_t line_cap)
Definition draw.h:952
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:268
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:398
static void dt_draw_rounded_rectangle_path(cairo_t *cr, float x, float y, float width, float height, float radius)
Definition draw.h:541
static void dt_draw_handle(cairo_t *cr, const float pt[2], const float zoom_scale, const float handle[2], const gboolean selected, const gboolean square)
Draw a control handle attached to a point with a tail between the node and the handle.
Definition draw.h:725
#define DT_DRAW_SIZE_LINE_HIGHLIGHT
Definition draw.h:85
static void dt_draw_cross(cairo_t *cr, const float zoom_scale, const float x, const float y)
Definition draw.h:1061
#define DT_DRAW_SIZE_LINE_SELECTED
Definition draw.h:84
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:431
void(* shape_draw_function_t)(struct dt_develop_t *dev, cairo_t *cr, const float *points, const int points_count, const int nb, const gboolean border, const gboolean source, const struct dt_masks_skip_range_t *skips, const int skip_count)
Definition draw.h:815
static void dt_draw_cairo_to_gdk_pixbuf(uint8_t *data, unsigned int width, unsigned int height)
Definition draw.h:479
static void dt_draw_plus_sign(cairo_t *cr, float x, float y, float size, float line_width_scale)
Definition draw.h:562
static void dt_draw_histogram_8_linxlogy(cairo_t *cr, const uint32_t *hist, int32_t channels, int32_t channel)
Definition draw.h:447
static float dt_log_scale_axis(const float x, const float base)
Definition draw.h:201
static double dt_draw_min_emit_step(cairo_t *cr)
Stroke a line with style.
Definition draw.h:931
static void _fill_clear_preserve(cairo_t *cr)
Definition draw.h:596
static void dt_draw_dash_lengths(const dt_draw_dash_type_t type, const float zoom_scale, double *on, double *off)
Definition draw.h:602
static void dt_draw_set_color_overlay(cairo_t *cr, gboolean bright, double alpha)
Definition draw.h:147
static void dt_draw_line(cairo_t *cr, float left, float top, float right, float bottom)
Definition draw.h:118
static void dt_draw_source_shape(struct dt_develop_t *dev, cairo_t *cr, const float zoom_scale, const gboolean selected, const float *source_pts, const int source_pts_count, const int nodes_nb, const shape_draw_function_t *draw_shape_func)
Definition draw.h:1085
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:309
static void dt_draw_histogram_8_linxliny(cairo_t *cr, const uint32_t *hist, int32_t channels, int32_t channel)
Definition draw.h:388
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:255
static void set_color(cairo_t *cr, GdkRGBA color)
Definition draw.h:125
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:158
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:238
static float dt_draw_curve_calc_value(dt_draw_curve_t *c, const float x)
Definition draw.h:360
static void dt_cairo_perceptual_gradient(cairo_pattern_t *grad, double alpha)
Definition draw.h:506
dt_draw_dash_type_t
Definition draw.h:133
@ DT_MASKS_DASH_STICK
Definition draw.h:135
@ DT_MASKS_DASH_ROUND
Definition draw.h:136
@ DT_MASKS_NO_DASH
Definition draw.h:134
static void dt_draw_star(cairo_t *cr, float x, float y, float r1, float r2)
Definition draw.h:100
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:333
#define DT_DRAW_SCALE_ARROW
Definition draw.h:91
static void dt_draw_curve_destroy(dt_draw_curve_t *c)
Definition draw.h:297
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:351
#define DT_DRAW_SIZE_CROSS
Definition draw.h:87
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:458
#define DT_DRAW_RADIUS_NODE
Definition draw.h:94
static void dt_draw_curve_set_point(dt_draw_curve_t *c, const int num, const float x, const float y)
Definition draw.h:303
static void dt_gui_draw_rounded_rectangle(cairo_t *cr, float width, float height, float x, float y)
Definition draw.h:554
static void dt_draw_arrow(cairo_t *cr, const float zoom_scale, const gboolean selected, const gboolean draw_tail, const dt_draw_dash_type_t dash_style, const float arrow[2], const float tail[2], const float angle)
Draw an arrow with head and, if needed, tail. The length of the arrow head is defined by DT_DRAW_SCAL...
Definition draw.h:988
static int dt_draw_curve_add_point(dt_draw_curve_t *c, const float x, const float y)
Definition draw.h:379
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:415
static GdkPixbuf * dt_draw_get_pixbuf_from_cairo(DTGTKCairoPaintIconFunc paint, const int width, const int height)
Definition draw.h:1116
static void dt_draw_shape_lines(struct dt_develop_t *dev, const dt_draw_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, const cairo_line_cap_t line_cap, const struct dt_masks_skip_range_t *skips, const int skip_count)
Draw the lines of a mask shape.
Definition draw.h:831
static void _fill_clear(cairo_t *cr)
Definition draw.h:591
#define DT_DRAW_SIZE_LINE_HIGHLIGHT_SELECTED
Definition draw.h:86
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:222
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:469
static dt_draw_curve_t * dt_draw_curve_new(const float min, const float max, unsigned int type)
Definition draw.h:281
#define M_PI
Definition draw.h:75
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:206
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:958
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:342
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:179
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:669
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:969
const int res
Definition dtpthread.h:351
GdkRGBA color[]
Definition geotagging.c:541
@ linear
Definition lightroom.c:369
_lib_location_type_t type
Definition location.c:1
float *const restrict const size_t k
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
size_t size
Definition mipmap_cache.c:3
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
#define __OMP_DECLARE_SIMD__(...)
Definition openmp.h:100
#define __OMP_PARALLEL_FOR_SIMD__(...)
Definition openmp.h:96
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
int CurveDataSampleV2Periodic(CurveData *curve, CurveSample *sample)
Definition splines.cpp:847
int CurveDataSampleV2(CurveData *curve, CurveSample *sample)
Definition splines.cpp:751
const float uint32_t state[4]
const float r
gboolean dt_stroke_raster_path(cairo_t *cr, const dt_stroke_style_t *style)
CurveSample csample
Definition draw.h:143
CurveData c
Definition draw.h:142
One cut in a shape's border outline: while walking the border buffer forward, on reaching index jump_...
dt_stroke_pass_t dark
dt_stroke_pass_t bright
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29
void dt_widget_set_source_rgba(cairo_t *cr, dt_gui_color_t color, float opacity_coef)
gboolean dt_widget_debug_overlays(void)
const dt_widget_overlay_color_t * dt_widget_overlay_color(void)
@ DT_GUI_COLOR_BUTTON_FG
#define DT_GUI_MOUSE_EFFECT_RADIUS
#define DT_PIXEL_APPLY_DPI(value)
void(* DTGTKCairoPaintIconFunc)(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)