Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
duplicate.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2015-2016, 2019-2022 Aldric Renaudin.
4 Copyright (C) 2018-2019 Matthieu Moy.
5 Copyright (C) 2018-2021 Pascal Obry.
6 Copyright (C) 2018 rawfiner.
7 Copyright (C) 2019-2020, 2022-2023, 2025-2026 Aurélien PIERRE.
8 Copyright (C) 2019 Edgardo Hoszowski.
9 Copyright (C) 2019-2020 Philippe Weyland.
10 Copyright (C) 2020 Chris Elston.
11 Copyright (C) 2020-2022 Diederik Ter Rahe.
12 Copyright (C) 2020 Hanno Schwalm.
13 Copyright (C) 2020 Hubert Kowalski.
14 Copyright (C) 2020 Marco.
15 Copyright (C) 2020 Mark-64.
16 Copyright (C) 2020, 2022 Nicolas Auffray.
17 Copyright (C) 2021 Fabio Heer.
18 Copyright (C) 2021 Ralf Brown.
19 Copyright (C) 2022 Martin Bařinka.
20 Copyright (C) 2023 Alynx Zhou.
21 Copyright (C) 2026 Guillaume STUTIN.
22
23
24 darktable is free software: you can redistribute it and/or modify
25 it under the terms of the GNU General Public License as published by
26 the Free Software Foundation, either version 3 of the License, or
27 (at your option) any later version.
28
29 darktable is distributed in the hope that it will be useful,
30 but WITHOUT ANY WARRANTY; without even the implied warranty of
31 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 GNU General Public License for more details.
33
34 You should have received a copy of the GNU General Public License
35 along with darktable. If not, see <http://www.gnu.org/licenses/>.
36*/
37
38#include "common/collection.h"
40#include "widgets/button.h"
42#include "system/macros.h"
44#include "metadata/metadata.h"
45#include "control/control.h"
46#include "develop/develop.h"
48#include "gui/dtgtk/thumbnail.h"
49
50#include "libs/lib.h"
51
52#include <sqlite3.h>
53#include "gui/window_manager.h"
55#include "widgets/container.h"
56#include "widgets/scroll_wrap.h"
59#include "control/signal.h"
60
61DT_MODULE(1)
62
63
64typedef struct dt_lib_duplicate_t
65{
67 int32_t imgid; // duplicate currently held under mouse press, UNKNOWN_IMAGE if none
68 dt_dev_snapshot_t preview; // hold-to-preview render, ROI-scoped and recomputed on pan/zoom, see develop/dev_snapshot.h
69 int32_t preview_cached_imgid; // which imgid `preview` currently holds, UNKNOWN_IMAGE if none
70
71 GList *thumbs;
73
74const char *name(struct dt_lib_module_t *self)
75{
76 return _("Duplicates");
77}
78
79const char **views(dt_lib_module_t *self)
80{
81 static const char *v[] = {"darkroom", NULL};
82 return v;
83}
84
89
91{
92 return 850;
93}
94
95static void _lib_duplicate_init_callback(gpointer instance, dt_lib_module_t *self);
96
97static gboolean _lib_duplicate_caption_out_callback(GtkWidget *widget, GdkEvent *event, dt_lib_module_t *self)
98{
99 const int32_t imgid = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),"imgid"));
100
101 // we write the content of the textbox to the caption field
102 dt_metadata_set(imgid, "Xmp.darktable.version_name", gtk_entry_get_text(GTK_ENTRY(widget)), FALSE);
103 dt_control_save_xmp(imgid);
104
105 return FALSE;
106}
107
108static void _lib_duplicate_delete(GtkButton *button, dt_lib_module_t *self)
109{
111 const int32_t imgid = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "imgid"));
112
113 if(imgid == dt_dev_get_global()->image_storage.id)
114 {
115 // we find the duplicate image to show now
116 for(GList *l = d->thumbs; l; l = g_list_next(l))
117 {
118 dt_thumbnail_t *thumb = (dt_thumbnail_t *)l->data;
119 if(thumb->info.id == imgid)
120 {
121 GList *l2 = g_list_next(l);
122 if(IS_NULL_PTR(l2)) l2 = g_list_previous(l);
123 if(l2)
124 {
125 dt_thumbnail_t *th2 = (dt_thumbnail_t *)l2->data;
127 th2->info.id);
128 break;
129 }
130 }
131 }
132 }
133
134 // and we remove the image
137 g_list_prepend(NULL, GINT_TO_POINTER(imgid)));
138}
139
140static gboolean _lib_duplicate_thumb_press_callback(GtkWidget *widget, GdkEventButton *event, dt_lib_module_t *self)
141{
142 if(event->button == 1 && event->type == GDK_BUTTON_PRESS)
143 {
145 if(IS_NULL_PTR(dev)) return FALSE;
146
148 const int32_t imgid = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "imgid"));
149 if(imgid <= 0) return FALSE;
150
151 // Render once per duplicate and keep it around for the panel's lifetime -- re-pressing the
152 // same thumbnail is then instant. The first press on a given duplicate still pays for a full
153 // pipeline run (same cost as the "take snapshot" button in libs/snapshots.c), so show the
154 // same busy-cursor feedback while it's in flight.
155 if(d->preview_cached_imgid != imgid)
156 {
158 const gboolean ok = dt_dev_snapshot_capture(&d->preview, dev, imgid, NULL, NULL, -1);
160 d->preview_cached_imgid = ok ? imgid : UNKNOWN_IMAGE;
161 }
162
163 d->imgid = (d->preview_cached_imgid == imgid) ? imgid : UNKNOWN_IMAGE;
165 return TRUE;
166 }
167 return FALSE;
168}
169
170// Cancels the hold-to-preview, whether triggered by releasing the button or by the pointer
171// leaving the thumbnail while still held -- see the two signals this is connected to below.
172static gboolean _lib_duplicate_thumb_revert_callback(GtkWidget *widget, GdkEvent *event, dt_lib_module_t *self)
173{
174 // thumb->widget (the event box this is connected to) is not a single window: it contains
175 // several unconditionally-shown child event boxes/drawing areas of its own (w_image,
176 // w_top_eb, w_bottom_eb in dtgtk/thumbnail.c), each with their own GdkWindow. Moving the
177 // pointer between those, while still inside the thumbnail's visible bounds, crosses a child
178 // window boundary and fires a leave-notify on the parent too (detail == GDK_NOTIFY_INFERIOR).
179 // Only a crossing to a window that is NOT a descendant is an actual "left the thumbnail".
180 if(event->type == GDK_LEAVE_NOTIFY && event->crossing.detail == GDK_NOTIFY_INFERIOR) return FALSE;
181
183
184 d->imgid = UNKNOWN_IMAGE;
186
187 return FALSE;
188}
189
190/* while a duplicate thumbnail is held, show it full-frame in the center view instead of the
191 image currently being edited, matching the live pan/zoom -- released on button-up. */
192void gui_post_expose(dt_lib_module_t *self, cairo_t *cri, int32_t width, int32_t height, int32_t pointerx,
193 int32_t pointery)
194{
196 if(IS_NULL_PTR(d) || d->imgid <= 0 || d->preview_cached_imgid != d->imgid) return;
197
199 float image_box[4] = { 0.0f };
201 if(image_box[2] <= 0.0f || image_box[3] <= 0.0f) return;
202
203 dt_dev_snapshot_draw(&d->preview, cri, dev, width, height, image_box[0], image_box[1], image_box[2],
204 image_box[3]);
205}
206
207void view_leave(struct dt_lib_module_t *self, struct dt_view_t *old_view, struct dt_view_t *new_view)
208{
209 // we leave the view. Let's destroy the cached preview if any
211 dt_dev_snapshot_clear(&d->preview);
212 d->preview_cached_imgid = UNKNOWN_IMAGE;
213}
214
215static void _thumb_remove(gpointer user_data)
216{
217 dt_thumbnail_t *thumb = (dt_thumbnail_t *)user_data;
218 if(IS_NULL_PTR(thumb)) return;
219
220 GtkWidget *parent = NULL;
221 if(!IS_NULL_PTR(thumb->w_main)) parent = gtk_widget_get_parent(thumb->w_main);
222 if(!IS_NULL_PTR(parent) && GTK_IS_CONTAINER(parent) && !IS_NULL_PTR(thumb->w_main))
223 gtk_container_remove(GTK_CONTAINER(parent), thumb->w_main);
224
226}
227
228static void _lib_duplicate_init_callback(gpointer instance, dt_lib_module_t *self)
229{
230 //block signals to avoid concurrent calls
232
234
235 d->imgid = UNKNOWN_IMAGE;
236 // we drop the cached preview if any -- it belongs to a thumb the list rebuild below is about
237 // to tear down, and stays keyed to a specific imgid that may no longer even be a duplicate of
238 // whatever image this panel now describes
239 dt_dev_snapshot_clear(&d->preview);
240 d->preview_cached_imgid = UNKNOWN_IMAGE;
241 // we drop all the thumbs
242 g_list_free_full(d->thumbs, _thumb_remove);
243 d->thumbs = NULL;
244 // and the other widgets too
245 dt_gui_container_destroy_children(GTK_CONTAINER(d->duplicate_box));
246 // retrieve all the versions of the image
248
249 int count = 0;
250
251 // we get a summarize of all versions of the image
252 // clang-format off
253 // Materialised first: the loop below builds a thumbnail and several widgets per row, which
254 // re-enter the image cache and the database -- it used to do that from inside its own cursor.
258
259 GtkWidget *bt = NULL;
260
261 for(GList *l = versions; l; l = g_list_next(l))
262 {
263 const dt_image_version_t *v = (const dt_image_version_t *)l->data;
264 GtkWidget *hb = gtk_grid_new();
265 const int32_t imgid = v->imgid;
266 dt_image_t info = { 0 };
267 info.id = imgid;
269
270 thumb->disable_mouseover = TRUE;
271 thumb->disable_actions = TRUE;
273 dt_thumbnail_set_mouseover(thumb, imgid == dev->image_storage.id);
274 dt_thumbnail_update_selection(thumb, imgid == dev->image_storage.id);
275 gtk_widget_queue_draw(thumb->widget);
276
277 if(imgid != dev->image_storage.id)
278 {
279 g_object_set_data(G_OBJECT(thumb->widget), "imgid", GINT_TO_POINTER(imgid));
280 g_signal_connect(G_OBJECT(thumb->widget), "button-press-event",
281 G_CALLBACK(_lib_duplicate_thumb_press_callback), self);
282 g_signal_connect(G_OBJECT(thumb->widget), "button-release-event",
283 G_CALLBACK(_lib_duplicate_thumb_revert_callback), self);
284 // GTK keeps delivering crossing events to the widget that holds the implicit pointer
285 // grab, so dragging off the thumbnail without releasing is caught here the same way.
286 gtk_widget_add_events(thumb->widget, GDK_LEAVE_NOTIFY_MASK);
287 g_signal_connect(G_OBJECT(thumb->widget), "leave-notify-event",
288 G_CALLBACK(_lib_duplicate_thumb_revert_callback), self);
289 }
290
291 gchar chl[256];
292 const gchar *path = v->version_name;
293 g_snprintf(chl, sizeof(chl), "%d", v->version);
294
295 GtkWidget *tb = gtk_entry_new();
297 if(path) gtk_entry_set_text(GTK_ENTRY(tb), path);
298 gtk_entry_set_width_chars(GTK_ENTRY(tb), 0);
299 gtk_widget_set_hexpand(tb, TRUE);
300 g_object_set_data (G_OBJECT(tb), "imgid", GINT_TO_POINTER(imgid));
301 gtk_widget_add_events(tb, GDK_FOCUS_CHANGE_MASK);
302 g_signal_connect(G_OBJECT(tb), "focus-out-event", G_CALLBACK(_lib_duplicate_caption_out_callback), self);
303 GtkWidget *lb = gtk_label_new(chl);
304 gtk_widget_set_hexpand(lb, TRUE);
306 // gtk_widget_set_halign(bt, GTK_ALIGN_END);
307 g_object_set_data(G_OBJECT(bt), "imgid", GINT_TO_POINTER(imgid));
308 g_signal_connect(G_OBJECT(bt), "clicked", G_CALLBACK(_lib_duplicate_delete), self);
309
310 gtk_grid_attach(GTK_GRID(hb), thumb->widget, 0, 0, 1, 2);
311 gtk_grid_attach(GTK_GRID(hb), bt, 2, 0, 1, 1);
312 gtk_grid_attach(GTK_GRID(hb), lb, 1, 0, 1, 1);
313 gtk_grid_attach(GTK_GRID(hb), tb, 1, 1, 2, 1);
314
315 // Can't use gtk_widget_show_all here or the buttons of the thumbnail will show too
316 gtk_widget_show(thumb->widget);
317 gtk_widget_show(hb);
318 gtk_widget_show(lb);
319 gtk_widget_show(tb);
320 gtk_box_pack_start(GTK_BOX(d->duplicate_box), hb, FALSE, FALSE, 0);
321 d->thumbs = g_list_append(d->thumbs, thumb);
322 count++;
323 }
324 g_list_free_full(versions, dt_image_version_free);
325
326 gtk_widget_show(d->duplicate_box);
327
328 // we have a single image, do not allow it to be removed so hide last bt
329 if(count==1)
330 {
331 gtk_widget_set_sensitive(bt, FALSE);
332 gtk_widget_set_visible(bt, FALSE);
333 }
334
336}
337
338static void _lib_duplicate_collection_changed(gpointer instance, dt_collection_change_t query_change,
339 dt_collection_properties_t changed_property, gpointer imgs, int next,
340 dt_lib_module_t *self)
341{
342 _lib_duplicate_init_callback(instance, self);
343}
344
345static void _lib_duplicate_preview_updated_callback(gpointer instance, dt_lib_module_t *self)
346{
348 gtk_widget_queue_draw (d->duplicate_box);
350}
351
352
354{
355 /* initialize ui widgets */
357 self->data = (void *)d;
358
359 d->imgid = UNKNOWN_IMAGE;
360 d->preview_cached_imgid = UNKNOWN_IMAGE;
361
362 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
363 dt_gui_add_class(self->widget, "dt_duplicate_ui");
364
365 d->duplicate_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
366
367 GtkWidget *hb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
368
369 /* add duplicate list and buttonbox to widget */
370 gtk_box_pack_start(GTK_BOX(self->widget),
371 dt_ui_scroll_wrap(d->duplicate_box, 1, "plugins/darkroom/duplicate/windowheight",
373 gtk_box_pack_start(GTK_BOX(self->widget), hb, TRUE, TRUE, 0);
374
375 gtk_widget_show_all(self->widget);
376
380 G_CALLBACK(_lib_duplicate_collection_changed), self);
383}
384
386{
387 if(IS_NULL_PTR(self->data)) return;
389
393
394 if(!IS_NULL_PTR(d))
395 {
396 dt_dev_snapshot_clear(&d->preview);
397
398 g_list_free_full(d->thumbs, _thumb_remove);
399 d->thumbs = NULL;
400 dt_gui_container_destroy_children(GTK_CONTAINER(d->duplicate_box));
401 }
402
403
404 dt_free(self->data);
405}
406
407// clang-format off
408// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
409// vim: shiftwidth=2 expandtab tabstop=2 cindent
410// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
411// clang-format on
void dt_accels_disconnect_on_text_input(GtkWidget *widget)
Disconnect accels while a text or search entry has the focus, and reconnect them when it loses it....
Handle default and user-set shortcuts (accelerators)
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
GtkWidget * dtgtk_button_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
Definition button.c:135
void dt_collection_update_query(const dt_collection_t *collection, dt_collection_change_t query_change, dt_collection_properties_t changed_property, GList *list)
Definition collection.c:837
dt_collection_t * dt_collection_get_global(void)
Definition collection.c:138
dt_collection_properties_t
Definition collection.h:120
@ DT_COLLECTION_PROP_UNDEF
Definition collection.h:155
dt_collection_change_t
Definition collection.h:160
@ DT_COLLECTION_CHANGE_RELOAD
Definition collection.h:164
const float l2
const float v
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
void dt_gui_container_destroy_children(GtkContainer *container)
Definition container.c:80
void dt_control_queue_redraw_center()
Request a redraw of the centre view.
Definition control.c:924
void dt_control_change_cursor_by_name_and_flush(const char *curs_str)
Apply a named cursor immediatelly and flush display updates for immediate feedback.
Definition control.c:335
void dt_control_commit_cursor()
Definition control.c:343
void dt_control_save_xmp(const int32_t imgid)
void dt_control_delete_image(int32_t imgid)
struct dt_develop_t * dt_dev_get_global(void)
Definition darktable.c:528
void dt_dev_snapshot_draw(dt_dev_snapshot_t *snap, cairo_t *cri, struct dt_develop_t *dev, int32_t width, int32_t height, double clip_x, double clip_y, double clip_w, double clip_h)
void dt_dev_snapshot_clear(dt_dev_snapshot_t *snap)
gboolean dt_dev_snapshot_capture(dt_dev_snapshot_t *snap, dt_develop_t *dev, int32_t imgid, GList *history_override, GList *iop_order_override, int32_t history_end_override)
void dt_dev_get_image_box_in_widget(const dt_develop_t *dev, const int32_t width, const int32_t height, float *box)
Get the displayed image rectangle in darkroom widget coordinates.
Definition develop.c:1977
static void _lib_duplicate_preview_updated_callback(gpointer instance, dt_lib_module_t *self)
Definition duplicate.c:345
static void _lib_duplicate_collection_changed(gpointer instance, dt_collection_change_t query_change, dt_collection_properties_t changed_property, gpointer imgs, int next, dt_lib_module_t *self)
Definition duplicate.c:338
static gboolean _lib_duplicate_thumb_revert_callback(GtkWidget *widget, GdkEvent *event, dt_lib_module_t *self)
Definition duplicate.c:172
static void _lib_duplicate_init_callback(gpointer instance, dt_lib_module_t *self)
Definition duplicate.c:228
void gui_cleanup(dt_lib_module_t *self)
Definition duplicate.c:385
static void _lib_duplicate_delete(GtkButton *button, dt_lib_module_t *self)
Definition duplicate.c:108
static void _thumb_remove(gpointer user_data)
Definition duplicate.c:215
uint32_t container(dt_lib_module_t *self)
Definition duplicate.c:85
void view_leave(struct dt_lib_module_t *self, struct dt_view_t *old_view, struct dt_view_t *new_view)
Definition duplicate.c:207
void gui_init(dt_lib_module_t *self)
Definition duplicate.c:353
int position()
Definition duplicate.c:90
const char ** views(dt_lib_module_t *self)
Definition duplicate.c:79
static gboolean _lib_duplicate_thumb_press_callback(GtkWidget *widget, GdkEventButton *event, dt_lib_module_t *self)
Definition duplicate.c:140
void gui_post_expose(dt_lib_module_t *self, cairo_t *cri, int32_t width, int32_t height, int32_t pointerx, int32_t pointery)
Definition duplicate.c:192
static gboolean _lib_duplicate_caption_out_callback(GtkWidget *widget, GdkEvent *event, dt_lib_module_t *self)
Definition duplicate.c:97
#define UNKNOWN_IMAGE
Definition image.h:78
GList * dt_image_repository_get_versions(const int32_t film_id, const char *filename, const int name_keyid)
Every version of the file (film_id, filename), in version order, each with the name stored under meta...
void dt_image_version_free(gpointer data)
Release one dt_image_version_t. Use with g_list_free_full().
Reading and writing one dt_image_t to and from the library database. The SQL half of what used to be ...
#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
void dt_metadata_set(const int32_t imgid, const char *key, const char *value, const gboolean undo_on)
@ DT_METADATA_XMP_VERSION_NAME
Definition metadata.h:55
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,...
const char * name
Definition pdf.h:90
GtkWidget * dt_ui_scroll_wrap(GtkWidget *w, gint min_size, const char *config_str, dt_ui_resize_mode_t mode)
Wrap a scrollable content widget in a recessed, vertically resizable scrolled window.
@ DT_UI_RESIZE_DYNAMIC
Definition scroll_wrap.h:42
void dt_control_signal_unblock_by_func(const struct dt_control_signal_t *ctlsig, GCallback cb, gpointer user_data)
Definition signal.c:512
void dt_control_signal_block_by_func(const struct dt_control_signal_t *ctlsig, GCallback cb, gpointer user_data)
Definition signal.c:506
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
Definition signal.h:407
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:386
struct dt_control_signal_t * dt_control_signal_get_global(void)
Definition darktable.c:616
@ DT_SIGNAL_DEVELOP_INITIALIZE
This signal is raised when darktable.develop is initialized.
Definition signal.h:172
@ DT_SIGNAL_VIEWMANAGER_THUMBTABLE_ACTIVATE
Definition signal.h:98
@ DT_SIGNAL_DEVELOP_IMAGE_CHANGED
This signal is raised when image is changed in darkroom.
Definition signal.h:224
@ DT_SIGNAL_DEVELOP_PREVIEW_PIPE_FINISHED
This signal is raised when develop preview pipe process is finished no param, no returned value.
Definition signal.h:177
@ DT_SIGNAL_COLLECTION_CHANGED
This signal is raised when collection changed. To avoid leaking the list, dt_collection_t is connecte...
Definition signal.h:125
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
Definition signal.h:396
dt_image_t image_storage
Definition develop.h:225
int32_t film_id
Definition image.h:401
char filename[DT_MAX_FILENAME_LEN]
Definition image.h:386
int32_t id
Definition image.h:401
One version of a file: which duplicate it is, its id, and the name the user gave it.
int32_t preview_cached_imgid
Definition duplicate.c:69
dt_dev_snapshot_t preview
Definition duplicate.c:68
GtkWidget * duplicate_box
Definition duplicate.c:66
GModule *void * data
Definition lib.h:79
GtkWidget * widget
Definition lib.h:83
gboolean disable_actions
Definition thumbnail.h:105
dt_image_t info
Definition thumbnail.h:77
GtkWidget * w_main
Definition thumbnail.h:81
GtkWidget * widget
Definition thumbnail.h:80
gboolean disable_mouseover
Definition thumbnail.h:104
dt_thumbnail_t * dt_thumbnail_new(int rowid, dt_thumbnail_overlay_t over, dt_thumbtable_t *table, dt_image_t *info)
Definition thumbnail.c:1391
void dt_thumbnail_set_mouseover(dt_thumbnail_t *thumb, gboolean over)
Definition thumbnail.c:1676
int dt_thumbnail_destroy(dt_thumbnail_t *thumb)
Definition thumbnail.c:1419
void dt_thumbnail_update_selection(dt_thumbnail_t *thumb, gboolean selected)
Definition thumbnail.c:923
void dt_thumbnail_resize(dt_thumbnail_t *thumb, int width, int height)
Definition thumbnail.c:1606
@ DT_THUMBNAIL_OVERLAYS_NONE
Definition thumbnail.h:60
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
void dtgtk_cairo_paint_remove(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
@ DT_UI_CONTAINER_PANEL_LEFT_CENTER