Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
navigation.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2012, 2016, 2018 johannes hanika.
4 Copyright (C) 2010-2012 Henrik Andersson.
5 Copyright (C) 2012 Richard Wonka.
6 Copyright (C) 2012-2014, 2016-2017 Tobias Ellinghaus.
7 Copyright (C) 2013, 2015, 2019-2020 Aldric Renaudin.
8 Copyright (C) 2013 Josef Wells.
9 Copyright (C) 2013 Pascal de Bruijn.
10 Copyright (C) 2013-2016 Roman Lebedev.
11 Copyright (C) 2014 parafin.
12 Copyright (C) 2014-2015 Ulrich Pegelow.
13 Copyright (C) 2016 Asma.
14 Copyright (C) 2018 Maurizio Paglia.
15 Copyright (C) 2018-2021 Pascal Obry.
16 Copyright (C) 2018 rawfiner.
17 Copyright (C) 2018 Sam Smith.
18 Copyright (C) 2019 Alexis Mousset.
19 Copyright (C) 2019, 2023, 2025-2026 Aurélien PIERRE.
20 Copyright (C) 2019 Edgardo Hoszowski.
21 Copyright (C) 2019 yuri1969.
22 Copyright (C) 2020 Chris Elston.
23 Copyright (C) 2020 Hubert Kowalski.
24 Copyright (C) 2021 Dan Torop.
25 Copyright (C) 2021-2022 Diederik Ter Rahe.
26 Copyright (C) 2021 Hanno Schwalm.
27 Copyright (C) 2021 Paolo DePetrillo.
28 Copyright (C) 2022 Martin Bařinka.
29 Copyright (C) 2023 Alynx Zhou.
30 Copyright (C) 2025-2026 Guillaume Stutin.
31
32 darktable is free software: you can redistribute it and/or modify
33 it under the terms of the GNU General Public License as published by
34 the Free Software Foundation, either version 3 of the License, or
35 (at your option) any later version.
36
37 darktable is distributed in the hope that it will be useful,
38 but WITHOUT ANY WARRANTY; without even the implied warranty of
39 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40 GNU General Public License for more details.
41
42 You should have received a copy of the GNU General Public License
43 along with darktable. If not, see <http://www.gnu.org/licenses/>.
44*/
45
46#include "widgets/bauhaus.h"
47#include "system/macros.h"
49#include "common/times.h"
50#include "control/control.h"
53#include "develop/develop.h"
54
55#include "libs/lib.h"
56#include "libs/lib_api.h"
57#include "gui/window_manager.h"
58#include "widgets/popup.h"
59#include "widgets/scroll_wrap.h"
60#include "gui/screen_metrics.h"
61#include "control/signal.h"
62
63DT_MODULE(1)
64
65#define DT_NAVIGATION_INSET 5
66
67typedef struct dt_lib_navigation_t
68{
69 GtkWidget *area; // the drawing area (self->widget is the resizable wrapper around it)
71 int zoom_w, zoom_h; // size of the zoom button
72 cairo_surface_t *image_surface;
75
90
91
92/* expose function for navigation module */
93static gboolean _lib_navigation_draw_callback(GtkWidget *widget, cairo_t *crf, gpointer user_data);
94/* motion notify callback handler*/
95static gboolean _lib_navigation_motion_notify_callback(GtkWidget *widget, GdkEventMotion *event,
96 gpointer user_data);
97/* button press callback */
98static gboolean _lib_navigation_button_press_callback(GtkWidget *widget, GdkEventButton *event,
99 gpointer user_data);
100/* button release callback */
101static gboolean _lib_navigation_button_release_callback(GtkWidget *widget, GdkEventButton *event,
102 gpointer user_data);
103/* leave notify callback */
104static gboolean _lib_navigation_leave_notify_callback(GtkWidget *widget, GdkEventCrossing *event,
105 gpointer user_data);
106
107/* helper function for position set */
108static void _lib_navigation_set_position(struct dt_lib_module_t *self, double x, double y, int alloc_wd, int alloc_ht);
109
110const char *name(struct dt_lib_module_t *self)
111{
112 return _("navigation");
113}
114
115const char **views(dt_lib_module_t *self)
116{
117 static const char *v[] = {"darkroom", NULL};
118 return v;
119}
120
122{
124}
125
127{
128 return 0;
129}
130
132{
133 return 1001;
134}
135
136
137static void _lib_navigation_control_redraw_callback(gpointer instance, gpointer user_data)
138{
139 (void)instance;
140 dt_lib_module_t *self = (dt_lib_module_t *)user_data;
143}
144
145static void _lib_navigation_restart_cache_wait(gpointer user_data)
146{
147 dt_lib_module_t *self = (dt_lib_module_t *)user_data;
148 if(IS_NULL_PTR(self)) return;
151}
152
153static void _lib_navigation_history_resync_callback(gpointer instance, gpointer user_data)
154{
155 (void)instance;
156
157 dt_lib_module_t *self = (dt_lib_module_t *)user_data;
160 if(IS_NULL_PTR(d) || IS_NULL_PTR(dev) || IS_NULL_PTR(dev->preview_pipe)) return;
161
162 dt_dev_pixelpipe_cache_wait_set_owner(&d->preview_wait, "navigation-preview", self);
163 if(dt_dev_pixelpipe_cache_peek_gui(dev->preview_pipe, NULL, NULL, NULL, &d->preview_wait,
166}
167
168
170{
171 /* initialize ui widgets */
173 self->data = (void *)d;
174 d->image_surface = NULL;
175
176 /* create drawingarea */
177 d->area = gtk_drawing_area_new();
178 gtk_widget_set_events(d->area, GDK_EXPOSURE_MASK | GDK_ENTER_NOTIFY_MASK
179 | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK
180 | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK);
181
182 /* connect callbacks */
183 gtk_widget_set_app_paintable(d->area, TRUE);
184 g_signal_connect(G_OBJECT(d->area), "draw", G_CALLBACK(_lib_navigation_draw_callback), self);
185 g_signal_connect(G_OBJECT(d->area), "button-press-event",
186 G_CALLBACK(_lib_navigation_button_press_callback), self);
187 g_signal_connect(G_OBJECT(d->area), "button-release-event",
189 g_signal_connect(G_OBJECT(d->area), "motion-notify-event",
191 g_signal_connect(G_OBJECT(d->area), "leave-notify-event",
192 G_CALLBACK(_lib_navigation_leave_notify_callback), self);
193
194 gtk_widget_set_name(GTK_WIDGET(d->area), "navigation-module");
195
196 /* make the navigation preview vertically resizable, persisting its height */
197 self->widget = dt_ui_resizable_drawing_area(d->area, "plugins/darkroom/navigation/height", 175, 100);
198
199 /* connect redraw callbacks to targeted preview cache publication and explicit redraw requests */
204
205 dt_lib_get_global()->proxy.navigation.module = self;
206}
207
209{
210 if(IS_NULL_PTR(self->data)) return;
212
213 /* disconnect from signal */
216 dt_dev_pixelpipe_cache_wait_cleanup(&d->preview_wait, "navigation-gui-cleanup");
217
218 if(!IS_NULL_PTR(d->image_surface)) cairo_surface_destroy(d->image_surface);
219 d->image_surface = NULL;
220
221 dt_free(self->data);
222}
223
225{
227 if(!IS_NULL_PTR(d->image_surface)) cairo_surface_destroy(d->image_surface);
228 d->image_surface = NULL;
229}
230
231static gboolean _lib_navigation_draw_callback(GtkWidget *widget, cairo_t *crf, gpointer user_data)
232{
233 dt_times_t start;
234 dt_get_times(&start);
235
237 dt_lib_module_t *self = (dt_lib_module_t *)user_data;
239
240 const gboolean has_preview_image = dt_dev_pixelpipe_is_backbufer_valid(dev->preview_pipe);
241
242 static uint64_t image_hash = -1;
243 static int wd = 0;
244 static int ht = 0;
245 static float scale = 1.f;
246 static int32_t imgid = UNKNOWN_IMAGE;
247
248 GtkAllocation allocation;
249 gtk_widget_get_allocation(widget, &allocation);
250 static int width = 0;
251 static int height = 0;
252 gboolean changed = (width != allocation.width) || (height != allocation.height);
253 width = allocation.width;
254 height = allocation.height;
255
256 cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
257 cairo_t *cr = cairo_create(cst);
258 GtkStyleContext *context = gtk_widget_get_style_context(widget);
259 gtk_render_background(context, cr, 0, 0, allocation.width, allocation.height);
260 cairo_save(cr);
261
262 if(has_preview_image
263 && (!d->image_surface || image_hash != dt_dev_backbuf_get_hash(&dev->preview_pipe->backbuf) || changed))
264 {
265 if(d->image_surface) cairo_surface_destroy(d->image_surface);
266 d->image_surface = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
267
268 // Fetch the backbuffer. The preview pipe backbuffer already owns the cache keepalive ref:
269 // navigation only needs a short read-only critical section while it copies into its own cairo surface.
270 struct dt_pixel_cache_entry_t *cache_entry = NULL;
271 void *data = NULL;
272 dt_dev_pixelpipe_cache_wait_set_owner(&d->preview_wait, "navigation-preview", self);
273 if(!dt_dev_pixelpipe_cache_peek_gui(dev->preview_pipe, NULL, &data, &cache_entry, &d->preview_wait,
275 return TRUE;
276
278
279 /* One read of the publication: the cacheline just resolved and the shape its pixels are in
280 * have to come from the same frame, or the stride below is computed from the next frame's
281 * width and this paints diagonal striping. See dt_backbuf_t. */
283 wd = published.width;
284 ht = published.height;
286
287 /* Can this cacheline hold an image of those dimensions at all?
288 *
289 * The centre view asks the same question before it paints (dt_dev_lock_pipe_surface); this
290 * widget did not, and handed cairo a buffer to walk with a stride computed from a width the
291 * data need not have. When they disagree the thumbnail is striped diagonally, and the read
292 * runs past the allocation whenever the recorded dimensions are the larger pair.
293 *
294 * The way they came to disagree -- a hash resolved from one publication paired with
295 * dimensions from the next -- is closed by the snapshot above. This stays because it answers
296 * a different question: whether the cacheline this hash names is big enough at all, which
297 * neither the snapshot nor the cache can tell. Keep the previous thumbnail and come back on
298 * the next expose rather than draw garbage. */
299 const size_t required_size = (size_t)stride * (size_t)ht;
300 if(wd <= 0 || ht <= 0 || dt_pixel_cache_entry_get_size(cache_entry) < required_size
301 || dt_pixel_cache_entry_get_data(cache_entry) != data)
302 {
304 return TRUE;
305 }
306
307 scale = fminf(width / (float)wd, height / (float)ht);
309
310 image_hash = published.hash;
311
312 cairo_t *cri = cairo_create(d->image_surface);
314 cairo_translate(cri, width / 2., height / 2.);
315 cairo_scale(cri, scale, scale);
316 cairo_translate(cri, -wd / 2., -ht / 2.);
321
323
324 imgid = dev->image_storage.id;
325 }
326 else
327 {
330 }
331
332 if(d->image_surface && imgid == dev->image_storage.id)
333 {
334 cairo_rectangle(cr, 0, 0, width, height);
336 cairo_set_source_surface(cr, d->image_surface, 0, 0);
337 cairo_fill(cr);
338 }
339
340 cairo_translate(cr, width / 2., height / 2.);
341 cairo_scale(cr, scale, scale);
342 cairo_translate(cr, -wd / 2., -ht / 2.);
343
344 // Calculate the thickness in user space (not affected by scale)
345 double line_width = DT_PIXEL_APPLY_DPI(1);
346 {
347 double dx = line_width, dy = 0;
348 cairo_device_to_user_distance(cr, &dx, &dy);
349 line_width = dx;
350 }
351
352 // draw box where we are
353 if(dt_dev_viewport_scaling(dev) > 1.f)
354 {
355 // Add a dark overlay on the picture to make it fade
356 cairo_rectangle(cr, 0, 0, wd, ht);
357 cairo_set_source_rgba(cr, 0, 0, 0, 0.5);
358
359 // clip dimensions to navigation area
360 float boxw = 1, boxh = 1;
361 // Reads the box; the centre clamp it also performed is kept, because removing a
362 // mutation from a paint handler is a behaviour change that belongs with the setter work,
363 // not with the relocation.
368 const float roi_w = MIN(boxw * wd, wd);
369 const float roi_h = MIN(boxh * ht, ht);
370 const float roi_x = dt_dev_viewport_center_x(dev) * wd - roi_w * 0.5f;
371 const float roi_y = dt_dev_viewport_center_y(dev) * ht - roi_h * 0.5f;
372 cairo_rectangle(cr, roi_x - 1, roi_y - 1, roi_w + 2, roi_h + 2);
373
374 /* Use even–odd rule to punch the hole */
376 cairo_fill(cr);
377
379
380 // Paint the external border in black
381 cairo_set_source_rgb(cr, 0., 0., 0.);
383 cairo_stroke(cr);
384
385 // Paint the internal border in white
386 cairo_set_source_rgb(cr, 1., 1., 1.);
387 cairo_rectangle(cr, roi_x, roi_y, roi_w, roi_h);
388 cairo_stroke(cr);
389 }
390 else
391 {
392 // draw a simple border
393 cairo_set_source_rgb(cr, 1., 1., 1.);
395 cairo_rectangle(cr, 0.5, 0.5, wd - 1, ht - 1);
396 cairo_stroke(cr);
397 }
398
399 cairo_restore(cr);
400
401 /* Zoom % */
402 PangoLayout *layout;
403 PangoRectangle logic;
406 layout = pango_cairo_create_layout(cr);
407 const float fontsize = DT_PIXEL_APPLY_DPI(14);
410
411 // translate to left bottom corner
412 cairo_translate(cr, 0, height);
413 cairo_set_source_rgba(cr, 1., 1., 1., 0.5);
415
416 gchar *zoomline;
417 {
418 gchar *fit = NULL;
419 if(dt_dev_viewport_scaling(dev) == 1.f)
420 fit = g_strdup(_("Fit"));
421
423 if(fit)
424 {
425 dt_free(fit);
426 }
427 }
428
429 pango_layout_set_text(layout, zoomline, -1);
432 d->zoom_h = logic.height;
433 d->zoom_w = logic.width;
434 const double h = d->zoom_h;
435 const double w = d->zoom_w;
436 const int xp = width - w - h - logic.x;
437 const int yp = - logic.height;
438
439 cairo_move_to(cr, xp, yp);
440 cairo_save(cr);
442
443 GdkRGBA *color;
444 gtk_style_context_get(context, gtk_widget_get_state_flags(widget), "background-color", &color, NULL);
445
447 pango_cairo_layout_path(cr, layout);
449 cairo_set_source_rgb(cr, 0.8, 0.8, 0.8);
450 cairo_fill(cr);
451
452 cairo_restore(cr);
453
456 g_object_unref(layout);
457
458 const float arrow_h = fontsize;
459
460 /* draw the drop-down arrow for zoom menu */
461 cairo_move_to(cr, width - 0.95 * arrow_h, -0.9 * arrow_h - 2);
462 cairo_line_to(cr, width - 0.05 * arrow_h, -0.9 * arrow_h - 2);
463 cairo_line_to(cr, width - 0.5 * arrow_h, -0.1 * arrow_h - 2);
464 cairo_fill(cr);
465
466 /* blit memsurface into widget */
467 cairo_destroy(cr);
468 cairo_set_source_surface(crf, cst, 0, 0);
471
472 dt_show_times_f(&start, "[navigation]", "redraw");
473
474 return TRUE;
475}
476
477static void _lib_navigation_set_position(dt_lib_module_t *self, double x, double y, int alloc_wd, int alloc_ht)
478{
480 const dt_lib_navigation_t *d = (const dt_lib_navigation_t *)self->data;
481 if(!(dev && d->dragging && dt_dev_viewport_scaling(dev) > 1.f)) return;
482
483 // Compute size of navigation ROI in widget coordinates
484 int proc_wd, proc_ht;
486 const float nav_img_scale = fminf(alloc_wd / (float)proc_wd, alloc_ht / (float)proc_ht);
487 const int nav_img_w = (int)((float)proc_wd * nav_img_scale);
488 const int nav_img_h = (int)((float)proc_ht * nav_img_scale);
489
490 // Correct widget coordinates for margins
491 float fx = x - (alloc_wd - nav_img_w) * 0.5f;
492 float fy = y - (alloc_ht - nav_img_h) * 0.5f;
493
494 // Convert widget coordinates to relative coordinates within navigation ROI
495 // and commit relative coordinates of the ROI center
496 fx /= (float)nav_img_w;
497 fy /= (float)nav_img_h;
499
501
502 /* redraw myself */
504
505 /* redraw pipe */
507}
508
510 gpointer user_data)
511{
512 dt_lib_module_t *self = (dt_lib_module_t *)user_data;
513 GtkAllocation allocation;
514 gtk_widget_get_allocation(widget, &allocation);
515 _lib_navigation_set_position(self, event->x, event->y, allocation.width, allocation.height);
516 return TRUE;
517}
518
520{
522 if(IS_NULL_PTR(dev)) return;
523
524 switch(zoom)
525 {
526 default:
528 break;
529 case LIB_ZOOM_SMALL:
531 break;
532 case LIB_ZOOM_FIT:
534 break;
535 case LIB_ZOOM_25:
537 break;
538 case LIB_ZOOM_33:
540 break;
541 case LIB_ZOOM_50:
543 break;
544 case LIB_ZOOM_100:
546 break;
547 case LIB_ZOOM_200:
549 break;
550 case LIB_ZOOM_400:
552 break;
553 case LIB_ZOOM_800:
555 break;
556 case LIB_ZOOM_1600:
558 break;
559 }
560
561 // Actual pixelpipe scaling is dt_dev_viewport_scaling(dev) * dt_dev_roi_request_natural_scale(dev),
562 // where dt_dev_roi_request_natural_scale(dev) ensures the image fits within the viewport.
564
567}
568
569static void _zoom_preset_callback(GtkButton *button, gpointer user_data)
570{
572}
573
575 gpointer user_data)
576{
577 dt_lib_module_t *self = (dt_lib_module_t *)user_data;
579
580 GtkAllocation allocation;
581 gtk_widget_get_allocation(widget, &allocation);
582 int w = allocation.width;
583 int h = allocation.height;
584 if(event->x >= w - DT_NAVIGATION_INSET - d->zoom_h - d->zoom_w
585 && event->y >= h - DT_NAVIGATION_INSET - d->zoom_h)
586 {
587 // we show the zoom menu
589 GtkWidget *item;
590
591 item = gtk_menu_item_new_with_label(_("Small"));
593 gtk_menu_shell_append(menu, item);
594
595 item = gtk_menu_item_new_with_label(_("Fit to screen"));
597 gtk_menu_shell_append(menu, item);
598
599 item = gtk_menu_item_new_with_label(_("25%"));
601 gtk_menu_shell_append(menu, item);
602
603 item = gtk_menu_item_new_with_label(_("33%"));
605 gtk_menu_shell_append(menu, item);
606
607 item = gtk_menu_item_new_with_label(_("50%"));
609 gtk_menu_shell_append(menu, item);
610
611 item = gtk_menu_item_new_with_label(_("100%"));
613 gtk_menu_shell_append(menu, item);
614
615 item = gtk_menu_item_new_with_label(_("200%"));
617 gtk_menu_shell_append(menu, item);
618
619 item = gtk_menu_item_new_with_label(_("400%"));
621 gtk_menu_shell_append(menu, item);
622
623 item = gtk_menu_item_new_with_label(_("800%"));
625 gtk_menu_shell_append(menu, item);
626
627 item = gtk_menu_item_new_with_label(_("1600%"));
629 gtk_menu_shell_append(menu, item);
630
631 dt_gui_menu_popup(GTK_MENU(menu), NULL, 0, 0);
632
633 return TRUE;
634 }
635
636 d->dragging = 1;
637 _lib_navigation_set_position(self, event->x, event->y, w, h);
638 return TRUE;
639}
640
642 gpointer user_data)
643{
644 dt_lib_module_t *self = (dt_lib_module_t *)user_data;
646 d->dragging = 0;
647
648 return TRUE;
649}
650
652 gpointer user_data)
653{
654 return TRUE;
655}
656
657// clang-format off
658// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
659// vim: shiftwidth=2 expandtab tabstop=2 cindent
660// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
661// 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
const float v
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
void dt_control_queue_redraw_widget(GtkWidget *widget)
threadsafe request of redraw of specific widget. Use this function if you need to redraw a specific w...
Definition control.c:969
struct dt_develop_t * dt_dev_get_global(void)
Definition darktable.c:528
struct dt_lib_t * dt_lib_get_global(void)
Definition darktable.c:621
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
Definition darktable.c:646
void dt_dev_pixelpipe_cache_wait_cleanup(dt_dev_pixelpipe_cache_wait_t *wait, const char *reason)
Cancel one pending GUI cache wait request and clear its runtime state.
gboolean dt_dev_pixelpipe_is_backbufer_valid(dt_dev_pixelpipe_t *pipe)
void dt_dev_pixelpipe_change_zoom_main(dt_develop_t *dev)
void dt_dev_pixelpipe_cache_wait_set_owner(dt_dev_pixelpipe_cache_wait_t *wait, const char *owner_tag, gpointer owner_object)
Attach debug ownership metadata to one cache wait request.
gboolean dt_dev_pixelpipe_cache_peek_gui(dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, void **data, dt_pixel_cache_entry_t **cache_entry, dt_dev_pixelpipe_cache_wait_t *wait, dt_dev_pixelpipe_cache_ready_callback_t restart, gpointer restart_data)
int32_t dt_dev_roi_request_preview_height(const dt_develop_t *dev)
float dt_dev_roi_request_natural_scale(const dt_develop_t *dev)
int32_t dt_dev_roi_request_preview_width(const dt_develop_t *dev)
gboolean dt_dev_viewport_set_center(dt_develop_t *dev, const float center_x, const float center_y)
float dt_dev_viewport_center_y(const dt_develop_t *dev)
gboolean dt_dev_viewport_set_scaling(dt_develop_t *dev, const float scaling)
float dt_dev_viewport_center_x(const dt_develop_t *dev)
float dt_dev_viewport_scaling(const dt_develop_t *dev)
void dt_dev_get_processed_size(const dt_develop_t *dev, int *procw, int *proch)
Definition develop.c:1109
gboolean dt_dev_clamp_viewport_center(dt_develop_t *dev)
Clamp the viewport centre against the box currently visible at this zoom.
Definition develop.c:1065
void dt_dev_check_zoom_pos_bounds(dt_develop_t *dev, float *dev_x, float *dev_y, float *box_w, float *box_h)
Ensure that the current ROI position is within allowed bounds .
Definition develop.c:1074
GdkRGBA color[]
Definition geotagging.c:541
#define UNKNOWN_IMAGE
Definition image.h:78
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition macros.h:96
#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
#define DT_MODULE(MODVER)
Instantiate the version handshake every module must export. Use once, at file scope,...
void gui_reset(dt_lib_module_t *self)
Definition navigation.c:224
static void _zoom_preset_callback(GtkButton *button, gpointer user_data)
Definition navigation.c:569
static void _lib_navigation_history_resync_callback(gpointer instance, gpointer user_data)
Definition navigation.c:153
static void _lib_navigation_restart_cache_wait(gpointer user_data)
Definition navigation.c:145
static void _lib_navigation_control_redraw_callback(gpointer instance, gpointer user_data)
Definition navigation.c:137
dt_lib_zoom_t
Definition navigation.c:77
@ LIB_ZOOM_100
Definition navigation.c:83
@ LIB_ZOOM_SMALL
Definition navigation.c:78
@ LIB_ZOOM_200
Definition navigation.c:84
@ LIB_ZOOM_33
Definition navigation.c:81
@ LIB_ZOOM_25
Definition navigation.c:80
@ LIB_ZOOM_400
Definition navigation.c:85
@ LIB_ZOOM_FIT
Definition navigation.c:79
@ LIB_ZOOM_50
Definition navigation.c:82
@ LIB_ZOOM_LAST
Definition navigation.c:88
@ LIB_ZOOM_1600
Definition navigation.c:87
@ LIB_ZOOM_800
Definition navigation.c:86
void gui_cleanup(dt_lib_module_t *self)
Definition navigation.c:208
static gboolean _lib_navigation_draw_callback(GtkWidget *widget, cairo_t *crf, gpointer user_data)
Definition navigation.c:231
static gboolean _lib_navigation_leave_notify_callback(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
Definition navigation.c:651
static gboolean _lib_navigation_motion_notify_callback(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
Definition navigation.c:509
uint32_t container(dt_lib_module_t *self)
Definition navigation.c:121
static void _lib_navigation_set_position(struct dt_lib_module_t *self, double x, double y, int alloc_wd, int alloc_ht)
Definition navigation.c:477
static void _zoom_preset_change(dt_lib_zoom_t zoom)
Definition navigation.c:519
void gui_init(dt_lib_module_t *self)
Definition navigation.c:169
int position()
Definition navigation.c:131
const char ** views(dt_lib_module_t *self)
Definition navigation.c:115
int expandable(dt_lib_module_t *self)
Definition navigation.c:126
static gboolean _lib_navigation_button_press_callback(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
Definition navigation.c:574
#define DT_NAVIGATION_INSET
Definition navigation.c:65
static gboolean _lib_navigation_button_release_callback(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
Definition navigation.c:641
const char * name
Definition pdf.h:90
void * dt_pixel_cache_entry_get_data(dt_pixel_cache_entry_t *entry)
void dt_dev_pixelpipe_cache_rdlock_entry(gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the read lock on the entry.
size_t dt_pixel_cache_entry_get_size(dt_pixel_cache_entry_t *entry)
Peek the size (in bytes) reserved for the host buffer of a cache entry.
Pixelpipe cache for storing intermediate results in the pixelpipe.
static dt_backbuf_state_t dt_dev_backbuf_snapshot(const dt_backbuf_t *backbuf)
Read the whole record as one publication.
static uint64_t dt_dev_backbuf_get_hash(const dt_backbuf_t *backbuf)
void dt_gui_menu_popup(GtkMenu *menu, GtkWidget *button, GdkGravity widget_anchor, GdkGravity menu_anchor)
Definition popup.c:53
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
GtkWidget * dt_ui_resizable_drawing_area(GtkWidget *area, char *config_str, int default_height, int min_height)
Make a self-drawing widget (typically a GtkDrawingArea graph or scope) vertically resizable.
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
Definition signal.h:407
struct dt_control_signal_t * dt_control_signal_get_global(void)
Definition darktable.c:616
@ DT_SIGNAL_HISTORY_RESYNC
This signal is raised once darkroom history has been resynchronized into all live pipelines....
Definition signal.h:212
@ DT_SIGNAL_CONTROL_NAVIGATION_REDRAW
This signal is raised when dt_control_navigation_redraw() is called. no param, no returned value.
Definition signal.h:281
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
Definition signal.h:396
unsigned __int64 uint64_t
Definition strptime.c:75
One coherent publication, by value.
dt_backbuf_t backbuf
dt_image_t image_storage
Definition develop.h:225
struct dt_dev_pixelpipe_t * preview_pipe
Definition develop.h:214
int32_t id
Definition image.h:401
GModule *void * data
Definition lib.h:79
GtkWidget * widget
Definition lib.h:83
cairo_surface_t * image_surface
Definition navigation.c:72
dt_dev_pixelpipe_cache_wait_t preview_wait
Definition navigation.c:73
GtkWidget * area
Definition navigation.c:69
struct dt_lib_t::@48::@49 navigation
struct dt_lib_t::@48 proxy
void * data
dt_atomic_uint64 age
One consumer's outstanding request, owned by that consumer, not by the queue.
#define MIN(a, b)
Definition thinplate.c:32
static void dt_get_times(dt_times_t *t)
Definition times.h:50
void dt_show_times_f(const dt_times_t *start, const char *prefix, const char *suffix,...) __attribute__((format(printf
#define DT_PIXEL_APPLY_DPI(value)
@ DT_UI_CONTAINER_PANEL_LEFT_TOP