Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
filemanager.c
Go to the documentation of this file.
1/*
2 This file is part of Ansel,
3 Copyright (C) 2026 Aurélien PIERRE.
4
5 Ansel is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 Ansel is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
17*/
25#include "common/conf.h"
26#include "common/selection.h"
30#include "gui/dtgtk/thumbnail.h"
31#include "gui/application.h"
32#include "views/view.h"
33
34#include <math.h>
37
38
39// --- Content widget ---------------------------------------------------------------------------
40
42{
43 // GtkFixed: the grid pins its width to the viewport (horizontal policy NEVER) and only ever
44 // scrolls vertically, so the implicit GtkViewport it gets inside the GtkScrolledWindow is fine.
45 return gtk_fixed_new();
46}
47
48
49// --- Geometry ---------------------------------------------------------------------------------
50
51static void _grid_configure_dims(dt_thumbtable_t *table, int *new_width, int *new_height,
52 int *per_row, int *thumb_width, int *thumb_height)
53{
54 // GtkScrolledWindow reserves a "scrollbar-spacing" gutter between the content and the scrollbar.
55 // It is a legacy GtkWidget *style property* (default 3px), not a CSS box property - invisible in the
56 // GTK Inspector's CSS pane. We zero it via CSS (#thumbtable-scroll, see ansel.css) but still read its
57 // real value here so the maths stays exact whatever the theme/DPI yields.
58 gint sb_spacing = 0;
59 gtk_widget_style_get(table->scroll_window, "scrollbar-spacing", &sb_spacing, NULL);
60
61 // Use actual widget allocations for sizing: GtkAdjustment page sizes are not reliably updated
62 // during shrinking, which can prevent thumbnails from downscaling until another resize happens.
63 int width = gtk_widget_get_allocated_width(table->parent_overlay);
64 int height = gtk_widget_get_allocated_height(table->parent_overlay);
65
66 GtkWidget *v_scroll = gtk_scrolled_window_get_vscrollbar(GTK_SCROLLED_WINDOW(table->scroll_window));
67 const int v_scroll_w = v_scroll ? gtk_widget_get_allocated_width(v_scroll) : 0;
68 if(v_scroll_w > 0) width -= v_scroll_w + sb_spacing;
69
70 const int cols = dt_conf_get_int("plugins/lighttable/images_in_row");
71
72 // Reserve the per-cell decoration surplus on the cross axis so the whole grid (cols*thumb_width plus
73 // the last cell's protruding border) stays within the viewport. Under the NEVER scroll policy a
74 // GtkFixed wider than the viewport would drag the scrolled window (and scrollbar) past the parent.
75 const int deco = dt_thumbtable_thumb_cell_decoration();
76
77 *new_width = width;
78 *new_height = height;
79 *per_row = cols;
80 *thumb_width = (int)floorf((float)(width - deco) / (float)MAX(cols, 1));
81 *thumb_height = (cols == 1) ? height : *thumb_width;
82}
83
84static void _grid_rowid_to_position(dt_thumbtable_t *table, int rowid, int *x, int *y)
85{
86 int row = rowid / table->thumbs_per_row; // euclidean division
87 int col = rowid % table->thumbs_per_row;
88 *x = col * table->thumb_width;
89 *y = row * table->thumb_height;
90}
91
92static int _grid_position_to_rowid(dt_thumbtable_t *table, const double x, const double y)
93{
94 // Attempt to get the image rowid sitting in the center of the middle row
95 return (y + table->view_height / 2) / table->thumb_height * table->thumbs_per_row
96 + table->thumbs_per_row / 2 - 1;
97}
98
99static void _grid_get_row_ids(dt_thumbtable_t *table, int *rowid_min, int *rowid_max)
100{
101 // Pixel coordinates of the viewport:
102 float page_size = gtk_adjustment_get_page_size(table->v_scrollbar);
103 float position = gtk_adjustment_get_value(table->v_scrollbar);
104
105 // what is currently visible lies between position and position + page_size.
106 // don't preload next/previous rows because, when in 1 thumb/column,
107 // that can be quite slow
108 int row_min = floorf(position / (float)table->thumb_height);
109 int row_max = ceilf((position + page_size) / (float)table->thumb_height);
110
111 // rowid is the positional ID of the image in the SQLite collection, indexed from 0.
112 // SQLite indexes from 1 but then be use our own array to cache results.
113 *rowid_min = row_min * table->thumbs_per_row;
114 *rowid_max = row_max * table->thumbs_per_row;
115}
116
117static gboolean _grid_is_rowid_visible(dt_thumbtable_t *table, int rowid)
118{
119 // Pixel coordinates of the viewport:
120 int page_size = gtk_adjustment_get_page_size(table->v_scrollbar);
121 int position = gtk_adjustment_get_value(table->v_scrollbar);
122 int page_bottom = page_size + position;
123
124 int img_top = (rowid / table->thumbs_per_row) * table->thumb_height;
125 int img_bottom = img_top + table->thumb_height;
126 return img_top >= position && img_bottom <= page_bottom;
127}
128
130{
131 int current_w = 0, current_h = 0;
132 gtk_widget_get_size_request(table->grid, &current_w, &current_h);
133
134 const int height = (int)ceilf((float)table->collection_count / (float)table->thumbs_per_row) * table->thumb_height;
135 // Pin the cross-axis (width) to the viewport so the grid reaches the scrollbar instead of stopping
136 // at the floor-rounded column total. Safe under NEVER: the grid content already fits view_width
137 // (decoration budgeted in configure), so this lands on a stable fixpoint (grid = view_width,
138 // scrolled window = parent) without perturbing the cross-axis adjustment.
139 if(current_h != height || current_w != table->view_width)
140 {
141 gtk_widget_set_size_request(table->grid, table->view_width, height);
142 dt_print(DT_DEBUG_LIGHTTABLE, "Configuring grid size main dimension: %.f\n", (double)height);
143 }
144}
145
146
147// --- Group borders ----------------------------------------------------------------------------
148
150{
151 const int32_t rowid = thumb->rowid;
152 const int32_t groupid = thumb->info.group_id;
153
154 if(table->lut[CLAMP_ROW(rowid - table->thumbs_per_row)].groupid != groupid
155 || IS_COLLECTION_EDGE(rowid - table->thumbs_per_row))
156 *borders |= DT_THUMBNAIL_BORDER_TOP;
157
158 if(table->lut[CLAMP_ROW(rowid + table->thumbs_per_row)].groupid != groupid
159 || IS_COLLECTION_EDGE(rowid + table->thumbs_per_row))
160 *borders |= DT_THUMBNAIL_BORDER_BOTTOM;
161
162 if(table->lut[CLAMP_ROW(rowid - 1)].groupid != groupid
163 || IS_COLLECTION_EDGE(rowid - 1))
164 *borders |= DT_THUMBNAIL_BORDER_LEFT;
165
166 if(table->lut[CLAMP_ROW(rowid + 1)].groupid != groupid
167 || IS_COLLECTION_EDGE(rowid + 1))
168 *borders |= DT_THUMBNAIL_BORDER_RIGHT;
169
170 // If the group spans over more than a full row,
171 // close the row ends. Otherwise, we leave orphans opened at the row ends.
172 if(table->lut[rowid].thumb->info.group_members > table->thumbs_per_row)
173 {
174 if(rowid % table->thumbs_per_row == 0)
175 *borders |= DT_THUMBNAIL_BORDER_LEFT;
176 if(rowid % table->thumbs_per_row == table->thumbs_per_row - 1)
177 *borders |= DT_THUMBNAIL_BORDER_RIGHT;
178 }
179}
180
181
182// --- Child placement --------------------------------------------------------------------------
183
185{
186 gtk_fixed_put(GTK_FIXED(table->grid), thumb->widget, thumb->x, thumb->y);
187}
188
190{
191 gtk_fixed_move(GTK_FIXED(table->grid), thumb->widget, thumb->x, thumb->y);
192}
193
194
195// --- Scrollbars -------------------------------------------------------------------------------
196
197static gboolean _grid_wants_scroll_value(dt_thumbtable_t *table, GtkAdjustment *adjustment)
198{
199 return adjustment == table->v_scrollbar;
200}
201
202static gboolean _grid_wants_page_size_notify(dt_thumbtable_t *table, GObject *object)
203{
204 // Page size is only used to size the filemanager/grid. Only react to the scroll-axis (vertical)
205 // adjustment. The cross-axis adjustment's page size is driven by the grid width we set during
206 // configure; reacting to it would re-enter configure and can spin in a resize/redraw loop.
207 return object == (GObject *)table->v_scrollbar;
208}
209
210static gboolean _grid_relevant_scrollbar_changed(dt_thumbtable_t *table, GtkWidget *widget, GtkAllocation *allocation)
211{
212 // Filemanager fallback sizing subtracts the vertical scrollbar width.
213 GtkWidget *v_scroll = gtk_scrolled_window_get_vscrollbar(GTK_SCROLLED_WINDOW(table->scroll_window));
214 if(widget != v_scroll) return FALSE;
215 if(allocation->width == table->last_v_scrollbar_width) return FALSE;
216 table->last_v_scrollbar_width = allocation->width;
217 return TRUE;
218}
219
220
221// --- Per-thumbnail state ----------------------------------------------------------------------
222
223// The grid highlights the lighttable selection.
224static gboolean _grid_is_thumb_highlighted(dt_thumbtable_t *table, int32_t imgid)
225{
227}
228
234
235static void _grid_on_drag_begin(dt_thumbtable_t *table, int32_t imgid)
236{
237 // Ensure the image that collects the drag event is properly part of the selection
238 if(imgid > UNKNOWN_IMAGE)
240}
241
242
243// --- Parent / focus ---------------------------------------------------------------------------
244
246{
247 // The filemanager grid overlays the center canvas and floats as an OVERLAY child so its size
248 // request stays decoupled from the panel (the outer GtkOverlay drives its allocation). It is
249 // not affected by the Wayland blank-until-hover issue because it is the focused content
250 // of the lighttable view, not a static sibling of a continuously repainted surface.
251 gtk_overlay_add_overlay(GTK_OVERLAY(table->parent_overlay), table->scroll_window);
252 gtk_widget_set_name(table->grid, "thumbtable-filemanager");
253 dt_gui_add_help_link(table->grid, dt_get_help_url("lighttable_filemanager"));
254 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(table->scroll_window), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
255}
256
258{
259 // This runs from a g_idle() callback (see dt_thumbtable_schedule_focus), so by the time it
260 // fires the user may already have switched to another view (e.g. Studio Capture). Grabbing
261 // the grid's focus regardless would steal it back from that view's own center widget.
263 if(IS_NULL_PTR(current_view) || strcmp(current_view->module_name, "lighttable")) return;
264
265 GtkWidget *focused = NULL;
266 GtkWidget *toplevel = gtk_widget_get_toplevel(table->grid);
267 if(!IS_NULL_PTR(toplevel) && GTK_IS_WINDOW(toplevel))
268 focused = gtk_window_get_focus(GTK_WINDOW(toplevel));
269
270 // Grab focus here otherwise, on first click over the grid,
271 // scrolled window gets scrolled all the way to the top and it's annoying.
272 // This can work only if the grid is mapped and realized, which we ensure
273 // by wrapping that in a g_idle() method.
274 if(IS_NULL_PTR(focused) || (!GTK_IS_EDITABLE(focused) && !GTK_IS_TEXT_VIEW(focused)))
275 gtk_widget_grab_focus(table->grid);
276}
277
278
279// --- Keyboard ---------------------------------------------------------------------------------
280
281static gboolean _grid_handle_key(dt_thumbtable_t *table, GdkEventKey *event, guint key, int32_t imgid)
282{
283 switch(key)
284 {
285 case GDK_KEY_Up:
286 dt_thumbtable_move_in_grid(table, event, DT_TT_MOVE_UP, imgid);
287 return TRUE;
288 case GDK_KEY_Down:
289 dt_thumbtable_move_in_grid(table, event, DT_TT_MOVE_DOWN, imgid);
290 return TRUE;
291 case GDK_KEY_space:
292 {
293 if(dt_modifier_is(event->state, GDK_SHIFT_MASK))
294 {
296 int rowid = dt_thumbtable_find_rowid_from_imgid(table, imgid);
298 dt_thumbtable_select_range(table, rowid);
299 }
300 else if(dt_modifier_is(event->state, DT_PRIMARY_MASK))
302 else
304 return TRUE;
305 }
306 case GDK_KEY_nobreakspace:
307 {
308 // Shift + space is decoded as nobreakspace on BÉPO keyboards
310 int rowid = dt_thumbtable_find_rowid_from_imgid(table, imgid);
312 dt_thumbtable_select_range(table, rowid);
313 return TRUE;
314 }
315 }
316 return FALSE;
317}
318
319static void _grid_pre_activate(dt_thumbtable_t *table, int32_t imgid)
320{
321 // This is only to be consistent with mouse events:
322 // opening to darkroom happens with double click (aka ACTIVATE event),
323 // but the first click always select the clicked thumbnail before.
325}
326
327
328// --- Vtable -----------------------------------------------------------------------------------
329
331{
332 static const dt_thumbtable_layout_ops_t ops = {
334 .configure_dims = _grid_configure_dims,
335 .rowid_to_position = _grid_rowid_to_position,
336 .position_to_rowid = _grid_position_to_rowid,
337 .get_row_ids = _grid_get_row_ids,
338 .is_rowid_visible = _grid_is_rowid_visible,
339 .update_content_size = _grid_update_content_size,
340 .group_borders = _grid_group_borders,
341 .place_child = _grid_place_child,
342 .move_child = _grid_move_child,
343 .wants_scroll_value = _grid_wants_scroll_value,
344 .wants_page_size_notify = _grid_wants_page_size_notify,
345 .relevant_scrollbar_changed = _grid_relevant_scrollbar_changed,
346 .is_thumb_highlighted = _grid_is_thumb_highlighted,
347 .on_thumbnail_added = _grid_on_thumbnail_added,
348 .on_drag_begin = _grid_on_drag_begin,
349 .setup_parent = _grid_setup_parent,
350 .grab_focus = _grid_grab_focus,
351 .handle_key = _grid_handle_key,
352 .pre_activate = _grid_pre_activate,
353 };
354 return &ops;
355}
356
357
358// --- Grid-only public API ---------------------------------------------------------------------
359
361{
362 table->zoom = level;
365 dt_thumbtable_schedule_focus(table, G_PRIORITY_DEFAULT_IDLE);
366}
367
372
373void dt_thumbtable_offset_zoom(dt_thumbtable_t *table, const double delta_x, const double delta_y)
374{
376 GHashTableIter iter;
377 gpointer value = NULL;
378 g_hash_table_iter_init(&iter, table->list);
379 while(g_hash_table_iter_next(&iter, NULL, &value))
380 {
382 thumb->zoomx += delta_x;
383 thumb->zoomy += delta_y;
384 gtk_widget_queue_draw(thumb->w_image);
385 }
387}
388
396static gboolean _thumbtable_idle_apply_grid_configuration(gpointer user_data)
397{
398 dt_thumbtable_t *table = (dt_thumbtable_t *)user_data;
399 if(IS_NULL_PTR(table)) return G_SOURCE_REMOVE;
400
401 table->idle_update_id = 0;
402
403 // Reconfigure the grid with new column settings from config
405
406 // Update and populate visible thumbnails at new sizes
408
410
411 // Queue redraw for any unpopulated areas
412 if(table->thumb_nb == 0) gtk_widget_queue_draw(table->grid);
413
414 // Schedule scrolling as a follow-up idle callback with lower priority.
415 // This ensures the GTK widget grid is fully mapped and realized before we attempt to scroll.
416 // We use a lower priority (G_PRIORITY_LOW) to let the GTK layout pass complete first.
417 dt_thumbtable_schedule_focus(table, G_PRIORITY_LOW);
418
419 return G_SOURCE_REMOVE;
420}
421
423{
424 if(IS_NULL_PTR(table)) return;
425 if(table->scroll_window && !gtk_widget_is_visible(table->scroll_window)) return;
426
427 // Cancel any pending standard idle update to coalesce configuration changes
428 if(table->idle_update_id)
429 {
430 g_source_remove(table->idle_update_id);
431 table->idle_update_id = 0;
432 }
433
434 // Ensure we have the current active image so we can scroll back to it after grid size change
436
437 // Schedule the coordinated grid configuration with higher priority to ensure
438 // it runs before other pending updates
439 table->idle_update_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
441 table, NULL);
442}
443
444// clang-format off
445// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
446// vim: shiftwidth=2 expandtab tabstop=2 cindent
447// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
448// clang-format on
Handle default and user-set shortcuts (accelerators)
#define DT_PRIMARY_MASK
void dt_gui_add_help_link(GtkWidget *widget, char *link)
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
int position()
static const float x
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
static const int row
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
struct dt_view_manager_t * dt_view_manager_get_global(void)
Definition darktable.c:599
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:127
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:117
void dt_thumbtable_set_zoom(dt_thumbtable_t *table, dt_thumbtable_zoom_t level)
static void _grid_place_child(dt_thumbtable_t *table, dt_thumbnail_t *thumb)
void dt_thumbtable_offset_zoom(dt_thumbtable_t *table, const double delta_x, const double delta_y)
void dt_thumbtable_apply_grid_configuration(dt_thumbtable_t *table)
Apply grid configuration changes with proper event synchronization.
static void _grid_on_drag_begin(dt_thumbtable_t *table, int32_t imgid)
static void _grid_rowid_to_position(dt_thumbtable_t *table, int rowid, int *x, int *y)
Definition filemanager.c:84
static GtkWidget * _grid_create_content_widget(void)
Definition filemanager.c:41
static gboolean _grid_wants_page_size_notify(dt_thumbtable_t *table, GObject *object)
static gboolean _grid_wants_scroll_value(dt_thumbtable_t *table, GtkAdjustment *adjustment)
static gboolean _grid_is_thumb_highlighted(dt_thumbtable_t *table, int32_t imgid)
static gboolean _grid_is_rowid_visible(dt_thumbtable_t *table, int rowid)
static void _grid_get_row_ids(dt_thumbtable_t *table, int *rowid_min, int *rowid_max)
Definition filemanager.c:99
static void _grid_group_borders(dt_thumbtable_t *table, dt_thumbnail_t *thumb, dt_thumbnail_border_t *borders)
static void _grid_setup_parent(dt_thumbtable_t *table)
static gboolean _grid_handle_key(dt_thumbtable_t *table, GdkEventKey *event, guint key, int32_t imgid)
static gboolean _thumbtable_idle_apply_grid_configuration(gpointer user_data)
Idle callback for applying grid configuration.
static void _grid_move_child(dt_thumbtable_t *table, dt_thumbnail_t *thumb)
static void _grid_update_content_size(dt_thumbtable_t *table)
static void _grid_grab_focus(dt_thumbtable_t *table)
static void _grid_on_thumbnail_added(dt_thumbtable_t *table, dt_thumbnail_t *thumb)
dt_thumbtable_zoom_t dt_thumbtable_get_zoom(dt_thumbtable_t *table)
static int _grid_position_to_rowid(dt_thumbtable_t *table, const double x, const double y)
Definition filemanager.c:92
const dt_thumbtable_layout_ops_t * dt_thumbtable_grid_ops(void)
static void _grid_pre_activate(dt_thumbtable_t *table, int32_t imgid)
static gboolean _grid_relevant_scrollbar_changed(dt_thumbtable_t *table, GtkWidget *widget, GtkAllocation *allocation)
static void _grid_configure_dims(dt_thumbtable_t *table, int *new_width, int *new_height, int *per_row, int *thumb_width, int *thumb_height)
Definition filemanager.c:51
#define UNKNOWN_IMAGE
Definition image.h:78
@ DT_DEBUG_LIGHTTABLE
Definition logging.h:60
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
#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
char * key
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
struct dt_selection_t * dt_selection_get_global(void)
Definition selection.c:80
gboolean dt_selection_is_id_selected(struct dt_selection_t *selection, int32_t imgid)
Definition selection.c:404
void dt_selection_select(dt_selection_t *selection, int32_t imgid)
Definition selection.c:279
void dt_selection_select_single(dt_selection_t *selection, int32_t imgid)
Definition selection.c:297
void dt_selection_toggle(dt_selection_t *selection, int32_t imgid)
Definition selection.c:305
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
int32_t group_id
Definition image.h:401
uint32_t group_members
Definition image.h:402
int32_t id
Definition image.h:401
gboolean disable_actions
Definition thumbnail.h:105
dt_image_t info
Definition thumbnail.h:77
int32_t rowid
Definition thumbnail.h:69
GtkWidget * w_image
Definition thumbnail.h:85
GtkWidget * widget
Definition thumbnail.h:80
dt_thumbnail_t * thumb
Definition thumbtable.h:90
Per-mode layout strategy. One instance per frontend, shared (const) by all tables of that mode and st...
GtkWidget *(* create_content_widget)(void)
GHashTable * list
Definition thumbtable.h:118
GtkWidget * grid
Definition thumbtable.h:110
dt_pthread_mutex_t lock
Definition thumbtable.h:168
GtkAdjustment * v_scrollbar
Definition thumbtable.h:157
dt_thumbtable_zoom_t zoom
Definition thumbtable.h:185
int last_v_scrollbar_width
Definition thumbtable.h:203
GtkWidget * scroll_window
Definition thumbtable.h:154
dt_thumbtable_cache_t * lut
Definition thumbtable.h:152
uint32_t thumb_nb
Definition thumbtable.h:135
GtkWidget * parent_overlay
Definition thumbtable.h:163
char module_name[64]
Definition view.h:155
#define MAX(a, b)
Definition thinplate.c:29
void dt_thumbnail_update_selection(dt_thumbnail_t *thumb, gboolean selected)
Definition thumbnail.c:923
dt_thumbnail_border_t
Definition thumbnail.h:50
@ DT_THUMBNAIL_BORDER_BOTTOM
Definition thumbnail.h:55
@ DT_THUMBNAIL_BORDER_TOP
Definition thumbnail.h:53
@ DT_THUMBNAIL_BORDER_RIGHT
Definition thumbnail.h:54
@ DT_THUMBNAIL_BORDER_LEFT
Definition thumbnail.h:52
void dt_thumbtable_update(dt_thumbtable_t *table)
Definition thumbtable.c:789
void dt_thumbtable_set_active_rowid(dt_thumbtable_t *table)
Update internal active row tracking.
Definition thumbtable.c:381
void dt_thumbtable_configure(dt_thumbtable_t *table)
Definition thumbtable.c:556
int dt_thumbtable_thumb_cell_decoration(void)
Definition thumbtable.c:535
#define CLAMP_ROW(rowid)
Definition thumbtable.c:635
int dt_thumbtable_find_rowid_from_imgid(dt_thumbtable_t *table, const int32_t imgid)
Definition thumbtable.c:413
#define IS_COLLECTION_EDGE(rowid)
Definition thumbtable.c:636
void dt_thumbtable_move_in_grid(dt_thumbtable_t *table, GdkEventKey *event, dt_thumbtable_direction_t direction, int origin_imgid)
void dt_thumbtable_select_range(dt_thumbtable_t *table, const int rowid)
Select a range of images in the collection.
A widget to manage and display image thumbnails in Ansel's lighttable and filmstrip views.
dt_thumbtable_zoom_t
Zoom levels for thumbnail display.
Definition thumbtable.h:76
#define dt_thumbtable_refresh_thumbnail(table, imgid, reinit)
Definition thumbtable.h:298
Private interface shared between the thumbtable engine (thumbtable.c) and its two frontends (filemana...
#define dt_thumbtable_schedule_focus(table, priority)
@ DT_TT_MOVE_DOWN
@ DT_TT_MOVE_UP
char * dt_get_help_url(char *name)
const dt_view_t * dt_view_manager_get_current_view(dt_view_manager_t *vm)
Definition view.c:139
static gboolean dt_modifier_is(GdkModifierType state, const GdkModifierType desired_modifier_mask)