1 /*
2 This file is part of darktable,
3 Copyright (C) 2011-2021 darktable developers.
4
5 darktable is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 darktable is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with darktable. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <gdk/gdkkeysyms.h>
20
21 #include "common/collection.h"
22 #include "common/debug.h"
23 #include "common/selection.h"
24 #include "control/conf.h"
25 #include "control/control.h"
26 #include "dtgtk/thumbtable.h"
27 #include "gui/accelerators.h"
28 #include "gui/gtk.h"
29 #include "libs/lib.h"
30 #include "libs/lib_api.h"
31
32 DT_MODULE(1)
33
34 typedef struct dt_lib_tool_lighttable_t
35 {
36 GtkWidget *zoom;
37 GtkWidget *zoom_entry;
38 GtkWidget *layout_box;
39 GtkWidget *layout_filemanager;
40 GtkWidget *layout_zoomable;
41 GtkWidget *layout_culling_dynamic;
42 GtkWidget *layout_culling_fix;
43 GtkWidget *layout_preview;
44 dt_lighttable_layout_t layout, base_layout;
45 int current_zoom;
46 gboolean fullpreview;
47 gboolean fullpreview_focus;
48 gboolean combo_evt_reset;
49 } dt_lib_tool_lighttable_t;
50
51 /* set zoom proxy function */
52 static void _lib_lighttable_set_zoom(dt_lib_module_t *self, gint zoom);
53 static gint _lib_lighttable_get_zoom(dt_lib_module_t *self);
54
55 /* get/set layout proxy function */
56 static dt_lighttable_layout_t _lib_lighttable_get_layout(dt_lib_module_t *self);
57
58 /* zoom slider change callback */
59 static void _lib_lighttable_zoom_slider_changed(GtkRange *range, gpointer user_data);
60 /* zoom entry change callback */
61 static gboolean _lib_lighttable_zoom_entry_changed(GtkWidget *entry, GdkEventKey *event,
62 dt_lib_module_t *self);
63
64 static void _set_zoom(dt_lib_module_t *self, int zoom);
65
name(dt_lib_module_t * self)66 const char *name(dt_lib_module_t *self)
67 {
68 return _("lighttable");
69 }
70
views(dt_lib_module_t * self)71 const char **views(dt_lib_module_t *self)
72 {
73 static const char *v[] = {"lighttable", NULL};
74 return v;
75 }
76
container(dt_lib_module_t * self)77 uint32_t container(dt_lib_module_t *self)
78 {
79 return DT_UI_CONTAINER_PANEL_CENTER_BOTTOM_CENTER;
80 }
81
expandable(dt_lib_module_t * self)82 int expandable(dt_lib_module_t *self)
83 {
84 return 0;
85 }
86
position()87 int position()
88 {
89 return 1001;
90 }
91
_lib_lighttable_update_btn(dt_lib_module_t * self)92 static void _lib_lighttable_update_btn(dt_lib_module_t *self)
93 {
94 dt_lib_tool_lighttable_t *d = (dt_lib_tool_lighttable_t *)self->data;
95
96 // which btn should be active ?
97 GtkWidget *active = d->layout_filemanager;
98 if(d->fullpreview)
99 active = d->layout_preview;
100 else if(d->layout == DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC)
101 active = d->layout_culling_dynamic;
102 else if(d->layout == DT_LIGHTTABLE_LAYOUT_CULLING)
103 active = d->layout_culling_fix;
104 else if(d->layout == DT_LIGHTTABLE_LAYOUT_ZOOMABLE)
105 active = d->layout_zoomable;
106
107 GList *children = gtk_container_get_children(GTK_CONTAINER(d->layout_box));
108 for(const GList *l = children; l; l = g_list_next(l))
109 {
110 GtkWidget *w = (GtkWidget *)l->data;
111 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (w == active));
112 }
113 g_list_free(children);
114
115 // and now we set the tooltips
116 if(d->fullpreview)
117 gtk_widget_set_tooltip_text(d->layout_preview, _("click to exit from full preview layout."));
118 else
119 gtk_widget_set_tooltip_text(d->layout_preview, _("click to enter full preview layout."));
120
121 if(d->layout != DT_LIGHTTABLE_LAYOUT_CULLING || d->fullpreview)
122 gtk_widget_set_tooltip_text(d->layout_culling_fix, _("click to enter culling layout in fixed mode."));
123 else
124 gtk_widget_set_tooltip_text(d->layout_culling_fix, _("click to exit culling layout."));
125
126 if(d->layout != DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC || d->fullpreview)
127 gtk_widget_set_tooltip_text(d->layout_culling_dynamic, _("click to enter culling layout in dynamic mode."));
128 else
129 gtk_widget_set_tooltip_text(d->layout_culling_dynamic, _("click to exit culling layout."));
130 }
131
_lib_lighttable_set_layout(dt_lib_module_t * self,dt_lighttable_layout_t layout)132 static void _lib_lighttable_set_layout(dt_lib_module_t *self, dt_lighttable_layout_t layout)
133 {
134 dt_lib_tool_lighttable_t *d = (dt_lib_tool_lighttable_t *)self->data;
135
136 // we deal with fullpreview first.
137 if(!d->fullpreview && layout == DT_LIGHTTABLE_LAYOUT_PREVIEW)
138 {
139 // special case for preview : we don't change previous values, just show full preview
140 d->fullpreview = TRUE;
141 _lib_lighttable_update_btn(self);
142 dt_view_lighttable_set_preview_state(darktable.view_manager, TRUE, d->fullpreview_focus);
143 return;
144 }
145 else if(d->fullpreview && layout != DT_LIGHTTABLE_LAYOUT_PREVIEW)
146 {
147 d->fullpreview = FALSE;
148 dt_view_lighttable_set_preview_state(darktable.view_manager, FALSE, FALSE);
149 // and we continue to select the right layout...
150 }
151
152 const int current_layout = dt_conf_get_int("plugins/lighttable/layout");
153 d->layout = layout;
154
155 if(current_layout != layout)
156 {
157 if(d->layout == DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC)
158 {
159 d->current_zoom = MAX(1, MIN(30, dt_collection_get_selected_count(darktable.collection)));
160 if(d->current_zoom == 1) d->current_zoom = dt_conf_get_int("plugins/lighttable/culling_num_images");
161 }
162 else if(d->layout == DT_LIGHTTABLE_LAYOUT_CULLING)
163 {
164 d->current_zoom = dt_conf_get_int("plugins/lighttable/culling_num_images");
165 }
166 else
167 {
168 d->current_zoom = dt_conf_get_int("plugins/lighttable/images_in_row");
169 }
170
171 gtk_widget_set_sensitive(d->zoom_entry, (d->layout != DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC && !d->fullpreview));
172 gtk_widget_set_sensitive(d->zoom, (d->layout != DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC && !d->fullpreview));
173 gtk_range_set_value(GTK_RANGE(d->zoom), d->current_zoom);
174
175 dt_conf_set_int("plugins/lighttable/layout", layout);
176 if(layout == DT_LIGHTTABLE_LAYOUT_FILEMANAGER || layout == DT_LIGHTTABLE_LAYOUT_ZOOMABLE)
177 {
178 d->base_layout = layout;
179 dt_conf_set_int("plugins/lighttable/base_layout", layout);
180 }
181
182 dt_control_queue_redraw_center();
183 }
184 else
185 {
186 dt_control_queue_redraw_center();
187 }
188
189 _lib_lighttable_update_btn(self);
190 }
191
_lib_lighttable_layout_btn_release(GtkWidget * w,GdkEventButton * event,dt_lib_module_t * self)192 static gboolean _lib_lighttable_layout_btn_release(GtkWidget *w, GdkEventButton *event, dt_lib_module_t *self)
193 {
194 dt_lib_tool_lighttable_t *d = (dt_lib_tool_lighttable_t *)self->data;
195 if(d->combo_evt_reset) return FALSE;
196
197 const gboolean active
198 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)); // note : this is the state before the change
199 dt_lighttable_layout_t new_layout = DT_LIGHTTABLE_LAYOUT_FILEMANAGER;
200 if(!active)
201 {
202 // that means we want to activate the button
203 if(w == d->layout_preview)
204 {
205 d->fullpreview_focus = dt_modifier_is(event->state, GDK_CONTROL_MASK);
206 new_layout = DT_LIGHTTABLE_LAYOUT_PREVIEW;
207 }
208 else if(w == d->layout_culling_fix)
209 new_layout = DT_LIGHTTABLE_LAYOUT_CULLING;
210 else if(w == d->layout_culling_dynamic)
211 new_layout = DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC;
212 else if(w == d->layout_zoomable)
213 new_layout = DT_LIGHTTABLE_LAYOUT_ZOOMABLE;
214 }
215 else
216 {
217 // that means we want to deactivate the button
218 if(w == d->layout_preview)
219 new_layout = d->layout;
220 else if(w == d->layout_culling_dynamic || w == d->layout_culling_fix)
221 new_layout = d->base_layout;
222 else
223 {
224 // we can't exit from filemanager or zoomable
225 return TRUE;
226 }
227 }
228
229 _lib_lighttable_set_layout(self, new_layout);
230 return TRUE;
231 }
232
gui_init(dt_lib_module_t * self)233 void gui_init(dt_lib_module_t *self)
234 {
235 /* initialize ui widgets */
236 dt_lib_tool_lighttable_t *d = (dt_lib_tool_lighttable_t *)g_malloc0(sizeof(dt_lib_tool_lighttable_t));
237 self->data = (void *)d;
238
239 self->widget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
240 d->layout = MIN(DT_LIGHTTABLE_LAYOUT_LAST - 1, dt_conf_get_int("plugins/lighttable/layout"));
241 d->base_layout = MIN(DT_LIGHTTABLE_LAYOUT_LAST - 1, dt_conf_get_int("plugins/lighttable/base_layout"));
242
243 if(d->layout == DT_LIGHTTABLE_LAYOUT_CULLING)
244 d->current_zoom = dt_conf_get_int("plugins/lighttable/culling_num_images");
245 else if(d->layout == DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC)
246 {
247 d->current_zoom = MAX(1, MIN(DT_LIGHTTABLE_MAX_ZOOM, dt_collection_get_selected_count(darktable.collection)));
248 if(d->current_zoom == 1) d->current_zoom = dt_conf_get_int("plugins/lighttable/culling_num_images");
249 }
250 else
251 d->current_zoom = dt_conf_get_int("plugins/lighttable/images_in_row");
252
253 // create the layouts icon list
254 d->layout_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
255 gtk_widget_set_name(d->layout_box, "lighttable_layouts_box");
256 gtk_box_pack_start(GTK_BOX(self->widget), d->layout_box, TRUE, TRUE, 0);
257
258 d->layout_filemanager = dtgtk_togglebutton_new(dtgtk_cairo_paint_lt_mode_grid, CPF_STYLE_FLAT, NULL);
259 dt_action_define(&darktable.view_manager->proxy.lighttable.view->actions, NULL,
260 "toggle filemanager layout", d->layout_filemanager, NULL);
261 dt_gui_add_help_link(d->layout_filemanager, dt_get_help_url("layout_filemanager"));
262 gtk_widget_set_tooltip_text(d->layout_filemanager, _("click to enter filemanager layout."));
263 g_signal_connect(G_OBJECT(d->layout_filemanager), "button-release-event",
264 G_CALLBACK(_lib_lighttable_layout_btn_release), self);
265 gtk_box_pack_start(GTK_BOX(d->layout_box), d->layout_filemanager, TRUE, TRUE, 0);
266
267 d->layout_zoomable = dtgtk_togglebutton_new(dtgtk_cairo_paint_lt_mode_zoom, CPF_STYLE_FLAT, NULL);
268 dt_action_define(&darktable.view_manager->proxy.lighttable.view->actions, NULL,
269 "toggle zoomable lighttable layout", d->layout_zoomable, NULL);
270 dt_gui_add_help_link(d->layout_zoomable, dt_get_help_url("layout_zoomable"));
271 gtk_widget_set_tooltip_text(d->layout_zoomable, _("click to enter zoomable lighttable layout."));
272 g_signal_connect(G_OBJECT(d->layout_zoomable), "button-release-event",
273 G_CALLBACK(_lib_lighttable_layout_btn_release), self);
274 gtk_box_pack_start(GTK_BOX(d->layout_box), d->layout_zoomable, TRUE, TRUE, 0);
275
276 d->layout_culling_fix = dtgtk_togglebutton_new(dtgtk_cairo_paint_lt_mode_culling_fixed, CPF_STYLE_FLAT, NULL);
277 dt_action_define(&darktable.view_manager->proxy.lighttable.view->actions, NULL,
278 "toggle culling mode", d->layout_culling_fix, NULL);
279 dt_gui_add_help_link(d->layout_culling_fix, dt_get_help_url("layout_culling"));
280 g_signal_connect(G_OBJECT(d->layout_culling_fix), "button-release-event",
281 G_CALLBACK(_lib_lighttable_layout_btn_release), self);
282 gtk_box_pack_start(GTK_BOX(d->layout_box), d->layout_culling_fix, TRUE, TRUE, 0);
283
284 d->layout_culling_dynamic
285 = dtgtk_togglebutton_new(dtgtk_cairo_paint_lt_mode_culling_dynamic, CPF_STYLE_FLAT, NULL);
286 dt_action_define(&darktable.view_manager->proxy.lighttable.view->actions, NULL,
287 "toggle culling dynamic mode", d->layout_culling_dynamic, NULL);
288 dt_gui_add_help_link(d->layout_culling_dynamic, dt_get_help_url("layout_culling"));
289 g_signal_connect(G_OBJECT(d->layout_culling_dynamic), "button-release-event",
290 G_CALLBACK(_lib_lighttable_layout_btn_release), self);
291 gtk_box_pack_start(GTK_BOX(d->layout_box), d->layout_culling_dynamic, TRUE, TRUE, 0);
292
293 d->layout_preview = dtgtk_togglebutton_new(dtgtk_cairo_paint_lt_mode_fullpreview, CPF_STYLE_FLAT, NULL);
294 dt_action_define(&darktable.view_manager->proxy.lighttable.view->actions, NULL,
295 "toggle sticky preview mode", d->layout_preview, NULL);
296 dt_gui_add_help_link(d->layout_preview, dt_get_help_url("layout_preview"));
297 g_signal_connect(G_OBJECT(d->layout_preview), "button-release-event",
298 G_CALLBACK(_lib_lighttable_layout_btn_release), self);
299 gtk_box_pack_start(GTK_BOX(d->layout_box), d->layout_preview, TRUE, TRUE, 0);
300
301 _lib_lighttable_update_btn(self);
302
303 /* create horizontal zoom slider */
304 d->zoom = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, 1, DT_LIGHTTABLE_MAX_ZOOM, 1);
305 gtk_widget_set_size_request(GTK_WIDGET(d->zoom), DT_PIXEL_APPLY_DPI(140), -1);
306 gtk_scale_set_draw_value(GTK_SCALE(d->zoom), FALSE);
307 gtk_range_set_increments(GTK_RANGE(d->zoom), 1, 1);
308 gtk_box_pack_start(GTK_BOX(self->widget), d->zoom, TRUE, TRUE, 0);
309
310 /* manual entry of the zoom level */
311 d->zoom_entry = gtk_entry_new();
312 gtk_entry_set_alignment(GTK_ENTRY(d->zoom_entry), 1.0);
313 gtk_entry_set_max_length(GTK_ENTRY(d->zoom_entry), 2);
314 gtk_entry_set_width_chars(GTK_ENTRY(d->zoom_entry), 3);
315 gtk_entry_set_max_width_chars(GTK_ENTRY(d->zoom_entry), 3);
316 gtk_box_pack_start(GTK_BOX(self->widget), d->zoom_entry, TRUE, TRUE, 0);
317
318 g_signal_connect(G_OBJECT(d->zoom), "value-changed", G_CALLBACK(_lib_lighttable_zoom_slider_changed),
319 (gpointer)self);
320 g_signal_connect(d->zoom_entry, "key-press-event", G_CALLBACK(_lib_lighttable_zoom_entry_changed), self);
321 gtk_range_set_value(GTK_RANGE(d->zoom), d->current_zoom);
322
323 _lib_lighttable_zoom_slider_changed(GTK_RANGE(d->zoom), self); // the slider defaults to 1 and GTK doesn't
324 // fire a value-changed signal when setting
325 // it to 1 => empty text box
326
327 gtk_widget_set_sensitive(d->zoom_entry, (d->layout != DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC && !d->fullpreview));
328 gtk_widget_set_sensitive(d->zoom, (d->layout != DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC && !d->fullpreview));
329
330 darktable.view_manager->proxy.lighttable.module = self;
331 darktable.view_manager->proxy.lighttable.set_zoom = _lib_lighttable_set_zoom;
332 darktable.view_manager->proxy.lighttable.get_zoom = _lib_lighttable_get_zoom;
333 darktable.view_manager->proxy.lighttable.get_layout = _lib_lighttable_get_layout;
334 darktable.view_manager->proxy.lighttable.set_layout = _lib_lighttable_set_layout;
335 }
336
gui_cleanup(dt_lib_module_t * self)337 void gui_cleanup(dt_lib_module_t *self)
338 {
339 g_free(self->data);
340 self->data = NULL;
341 }
342
_set_zoom(dt_lib_module_t * self,int zoom)343 static void _set_zoom(dt_lib_module_t *self, int zoom)
344 {
345 dt_lib_tool_lighttable_t *d = (dt_lib_tool_lighttable_t *)self->data;
346 if(d->layout == DT_LIGHTTABLE_LAYOUT_CULLING)
347 {
348 dt_conf_set_int("plugins/lighttable/culling_num_images", zoom);
349 dt_control_queue_redraw_center();
350 }
351 else if(d->layout == DT_LIGHTTABLE_LAYOUT_FILEMANAGER || d->layout == DT_LIGHTTABLE_LAYOUT_ZOOMABLE)
352 {
353 dt_conf_set_int("plugins/lighttable/images_in_row", zoom);
354 dt_thumbtable_zoom_changed(dt_ui_thumbtable(darktable.gui->ui), d->current_zoom, zoom);
355 }
356 }
357
_lib_lighttable_zoom_slider_changed(GtkRange * range,gpointer user_data)358 static void _lib_lighttable_zoom_slider_changed(GtkRange *range, gpointer user_data)
359 {
360 dt_lib_module_t *self = (dt_lib_module_t *)user_data;
361 dt_lib_tool_lighttable_t *d = (dt_lib_tool_lighttable_t *)self->data;
362
363 const int i = gtk_range_get_value(range);
364 gchar *i_as_str = g_strdup_printf("%d", i);
365 gtk_entry_set_text(GTK_ENTRY(d->zoom_entry), i_as_str);
366 _set_zoom(self, i);
367 d->current_zoom = i;
368 g_free(i_as_str);
369 }
370
_lib_lighttable_zoom_entry_changed(GtkWidget * entry,GdkEventKey * event,dt_lib_module_t * self)371 static gboolean _lib_lighttable_zoom_entry_changed(GtkWidget *entry, GdkEventKey *event, dt_lib_module_t *self)
372 {
373 dt_lib_tool_lighttable_t *d = (dt_lib_tool_lighttable_t *)self->data;
374 switch(event->keyval)
375 {
376 case GDK_KEY_Escape:
377 case GDK_KEY_Tab:
378 {
379 // reset
380 int i = 0;
381 if(d->layout == DT_LIGHTTABLE_LAYOUT_CULLING || d->layout == DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC)
382 i = dt_conf_get_int("plugins/lighttable/culling_num_images");
383 else
384 i = dt_conf_get_int("plugins/lighttable/images_in_row");
385 gchar *i_as_str = g_strdup_printf("%d", i);
386 gtk_entry_set_text(GTK_ENTRY(d->zoom_entry), i_as_str);
387 g_free(i_as_str);
388 gtk_window_set_focus(GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)), NULL);
389 return FALSE;
390 }
391
392 case GDK_KEY_Return:
393 case GDK_KEY_KP_Enter:
394 {
395 // apply zoom level
396 const gchar *value = gtk_entry_get_text(GTK_ENTRY(d->zoom_entry));
397 int i = atoi(value);
398 gtk_range_set_value(GTK_RANGE(d->zoom), i);
399 gtk_window_set_focus(GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)), NULL);
400 return FALSE;
401 }
402
403 // allow 0 .. 9, left/right movement using arrow keys and del/backspace
404 case GDK_KEY_0:
405 case GDK_KEY_KP_0:
406 case GDK_KEY_1:
407 case GDK_KEY_KP_1:
408 case GDK_KEY_2:
409 case GDK_KEY_KP_2:
410 case GDK_KEY_3:
411 case GDK_KEY_KP_3:
412 case GDK_KEY_4:
413 case GDK_KEY_KP_4:
414 case GDK_KEY_5:
415 case GDK_KEY_KP_5:
416 case GDK_KEY_6:
417 case GDK_KEY_KP_6:
418 case GDK_KEY_7:
419 case GDK_KEY_KP_7:
420 case GDK_KEY_8:
421 case GDK_KEY_KP_8:
422 case GDK_KEY_9:
423 case GDK_KEY_KP_9:
424
425 case GDK_KEY_Left:
426 case GDK_KEY_Right:
427 case GDK_KEY_Delete:
428 case GDK_KEY_BackSpace:
429 return FALSE;
430
431 default: // block everything else
432 return TRUE;
433 }
434 }
435
_lib_lighttable_get_layout(dt_lib_module_t * self)436 static dt_lighttable_layout_t _lib_lighttable_get_layout(dt_lib_module_t *self)
437 {
438 dt_lib_tool_lighttable_t *d = (dt_lib_tool_lighttable_t *)self->data;
439 return d->layout;
440 }
441
_lib_lighttable_set_zoom(dt_lib_module_t * self,gint zoom)442 static void _lib_lighttable_set_zoom(dt_lib_module_t *self, gint zoom)
443 {
444 dt_lib_tool_lighttable_t *d = (dt_lib_tool_lighttable_t *)self->data;
445 gtk_range_set_value(GTK_RANGE(d->zoom), zoom);
446 d->current_zoom = zoom;
447 }
448
_lib_lighttable_get_zoom(dt_lib_module_t * self)449 static gint _lib_lighttable_get_zoom(dt_lib_module_t *self)
450 {
451 dt_lib_tool_lighttable_t *d = (dt_lib_tool_lighttable_t *)self->data;
452 return d->current_zoom;
453 }
454
_lib_lighttable_key_accel_toggle_filemanager(GtkAccelGroup * accel_group,GObject * acceleratable,guint keyval,GdkModifierType modifier,gpointer data)455 static gboolean _lib_lighttable_key_accel_toggle_filemanager(GtkAccelGroup *accel_group, GObject *acceleratable,
456 guint keyval, GdkModifierType modifier, gpointer data)
457 {
458 dt_lib_module_t *self = (dt_lib_module_t *)data;
459 _lib_lighttable_set_layout(self, DT_LIGHTTABLE_LAYOUT_FILEMANAGER);
460 return TRUE;
461 }
462
_lib_lighttable_key_accel_toggle_zoomable(GtkAccelGroup * accel_group,GObject * acceleratable,guint keyval,GdkModifierType modifier,gpointer data)463 static gboolean _lib_lighttable_key_accel_toggle_zoomable(GtkAccelGroup *accel_group, GObject *acceleratable,
464 guint keyval, GdkModifierType modifier, gpointer data)
465 {
466 dt_lib_module_t *self = (dt_lib_module_t *)data;
467 _lib_lighttable_set_layout(self, DT_LIGHTTABLE_LAYOUT_ZOOMABLE);
468 return TRUE;
469 }
470
_lib_lighttable_key_accel_toggle_preview(GtkAccelGroup * accel_group,GObject * acceleratable,guint keyval,GdkModifierType modifier,gpointer data)471 static gboolean _lib_lighttable_key_accel_toggle_preview(GtkAccelGroup *accel_group, GObject *acceleratable,
472 guint keyval, GdkModifierType modifier, gpointer data)
473 {
474 dt_lib_module_t *self = (dt_lib_module_t *)data;
475 dt_lib_tool_lighttable_t *d = (dt_lib_tool_lighttable_t *)self->data;
476
477 if(d->fullpreview)
478 _lib_lighttable_set_layout(self, d->layout);
479 else
480 {
481 d->fullpreview_focus = FALSE;
482 _lib_lighttable_set_layout(self, DT_LIGHTTABLE_LAYOUT_PREVIEW);
483 }
484
485 return TRUE;
486 }
487
_lib_lighttable_key_accel_toggle_preview_focus(GtkAccelGroup * accel_group,GObject * acceleratable,guint keyval,GdkModifierType modifier,gpointer data)488 static gboolean _lib_lighttable_key_accel_toggle_preview_focus(GtkAccelGroup *accel_group, GObject *acceleratable,
489 guint keyval, GdkModifierType modifier,
490 gpointer data)
491 {
492 dt_lib_module_t *self = (dt_lib_module_t *)data;
493 dt_lib_tool_lighttable_t *d = (dt_lib_tool_lighttable_t *)self->data;
494
495 if(d->fullpreview)
496 _lib_lighttable_set_layout(self, d->layout);
497 else
498 {
499 d->fullpreview_focus = TRUE;
500 _lib_lighttable_set_layout(self, DT_LIGHTTABLE_LAYOUT_PREVIEW);
501 }
502
503 return TRUE;
504 }
505
_lib_lighttable_key_accel_toggle_culling_dynamic_mode(GtkAccelGroup * accel_group,GObject * acceleratable,guint keyval,GdkModifierType modifier,gpointer data)506 static gboolean _lib_lighttable_key_accel_toggle_culling_dynamic_mode(GtkAccelGroup *accel_group,
507 GObject *acceleratable, guint keyval,
508 GdkModifierType modifier, gpointer data)
509 {
510 dt_lib_module_t *self = (dt_lib_module_t *)data;
511 dt_lib_tool_lighttable_t *d = (dt_lib_tool_lighttable_t *)self->data;
512
513 // if we are already in any culling layout, we return to the base layout
514 if(d->layout != DT_LIGHTTABLE_LAYOUT_CULLING && d->layout != DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC)
515 _lib_lighttable_set_layout(self, DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC);
516 else
517 _lib_lighttable_set_layout(self, d->base_layout);
518
519 dt_control_queue_redraw_center();
520 return TRUE;
521 }
522
_lib_lighttable_key_accel_toggle_culling_mode(GtkAccelGroup * accel_group,GObject * acceleratable,guint keyval,GdkModifierType modifier,gpointer data)523 static gboolean _lib_lighttable_key_accel_toggle_culling_mode(GtkAccelGroup *accel_group, GObject *acceleratable,
524 guint keyval, GdkModifierType modifier,
525 gpointer data)
526 {
527 dt_lib_module_t *self = (dt_lib_module_t *)data;
528 dt_lib_tool_lighttable_t *d = (dt_lib_tool_lighttable_t *)self->data;
529
530 // if we are already in any culling layout, we return to the base layout
531 if(d->layout != DT_LIGHTTABLE_LAYOUT_CULLING && d->layout != DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC)
532 _lib_lighttable_set_layout(self, DT_LIGHTTABLE_LAYOUT_CULLING);
533 else
534 _lib_lighttable_set_layout(self, d->base_layout);
535
536 dt_control_queue_redraw_center();
537 return TRUE;
538 }
539
_lib_lighttable_key_accel_toggle_culling_zoom_mode(GtkAccelGroup * accel_group,GObject * acceleratable,guint keyval,GdkModifierType modifier,gpointer data)540 static gboolean _lib_lighttable_key_accel_toggle_culling_zoom_mode(GtkAccelGroup *accel_group,
541 GObject *acceleratable, guint keyval,
542 GdkModifierType modifier, gpointer data)
543 {
544 dt_lib_module_t *self = (dt_lib_module_t *)data;
545 dt_lib_tool_lighttable_t *d = (dt_lib_tool_lighttable_t *)self->data;
546
547 if(d->layout == DT_LIGHTTABLE_LAYOUT_CULLING)
548 _lib_lighttable_set_layout(self, DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC);
549 else if(d->layout == DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC)
550 _lib_lighttable_set_layout(self, DT_LIGHTTABLE_LAYOUT_CULLING);
551
552 return TRUE;
553 }
554
_lib_lighttable_key_accel_exit_layout(GtkAccelGroup * accel_group,GObject * acceleratable,guint keyval,GdkModifierType modifier,gpointer data)555 static gboolean _lib_lighttable_key_accel_exit_layout(GtkAccelGroup *accel_group, GObject *acceleratable,
556 guint keyval, GdkModifierType modifier, gpointer data)
557 {
558 dt_lib_module_t *self = (dt_lib_module_t *)data;
559 dt_lib_tool_lighttable_t *d = (dt_lib_tool_lighttable_t *)self->data;
560
561 if(d->fullpreview)
562 _lib_lighttable_set_layout(self, d->layout);
563 else if(d->layout != d->base_layout)
564 _lib_lighttable_set_layout(self, d->base_layout);
565
566 return TRUE;
567 }
568
init_key_accels(dt_lib_module_t * self)569 void init_key_accels(dt_lib_module_t *self)
570 {
571 // view accels
572 dt_accel_register_lib_as_view("lighttable", NC_("accel", "toggle filemanager layout"), 0, 0);
573 dt_accel_register_lib_as_view("lighttable", NC_("accel", "toggle zoomable lighttable layout"), 0, 0);
574 dt_accel_register_lib_as_view("lighttable", NC_("accel", "toggle culling mode"), GDK_KEY_x, 0);
575 dt_accel_register_lib_as_view("lighttable", NC_("accel", "toggle culling dynamic mode"), GDK_KEY_x,
576 GDK_CONTROL_MASK);
577 dt_accel_register_lib_as_view("lighttable", NC_("accel", "toggle culling zoom mode"), GDK_KEY_less, 0);
578 dt_accel_register_lib_as_view("lighttable", NC_("accel", "toggle sticky preview mode"), GDK_KEY_f, 0);
579 dt_accel_register_lib_as_view("lighttable", NC_("accel", "toggle sticky preview mode with focus detection"), 0,
580 0);
581 dt_accel_register_lib_as_view("lighttable", NC_("accel", "exit current layout"), GDK_KEY_Escape, 0);
582 }
583
connect_key_accels(dt_lib_module_t * self)584 void connect_key_accels(dt_lib_module_t *self)
585 {
586 /* setup key accelerators */
587
588 // view accels
589 dt_accel_connect_lib_as_view(
590 self, "lighttable", "toggle filemanager layout",
591 g_cclosure_new(G_CALLBACK(_lib_lighttable_key_accel_toggle_filemanager), self, NULL));
592 dt_accel_connect_lib_as_view(self, "lighttable", "toggle zoomable lighttable layout",
593 g_cclosure_new(G_CALLBACK(_lib_lighttable_key_accel_toggle_zoomable), self, NULL));
594 dt_accel_connect_lib_as_view(
595 self, "lighttable", "toggle culling dynamic mode",
596 g_cclosure_new(G_CALLBACK(_lib_lighttable_key_accel_toggle_culling_dynamic_mode), self, NULL));
597 dt_accel_connect_lib_as_view(
598 self, "lighttable", "toggle culling mode",
599 g_cclosure_new(G_CALLBACK(_lib_lighttable_key_accel_toggle_culling_mode), self, NULL));
600 dt_accel_connect_lib_as_view(
601 self, "lighttable", "toggle culling zoom mode",
602 g_cclosure_new(G_CALLBACK(_lib_lighttable_key_accel_toggle_culling_zoom_mode), self, NULL));
603 dt_accel_connect_lib_as_view(self, "lighttable", "toggle sticky preview mode",
604 g_cclosure_new(G_CALLBACK(_lib_lighttable_key_accel_toggle_preview), self, NULL));
605 dt_accel_connect_lib_as_view(
606 self, "lighttable", "toggle sticky preview mode with focus detection",
607 g_cclosure_new(G_CALLBACK(_lib_lighttable_key_accel_toggle_preview_focus), self, NULL));
608
609 dt_accel_connect_lib_as_view(self, "lighttable", "exit current layout",
610 g_cclosure_new(G_CALLBACK(_lib_lighttable_key_accel_exit_layout), self, NULL));
611 }
612
613 #ifdef USE_LUA
layout_cb(lua_State * L)614 static int layout_cb(lua_State *L)
615 {
616 dt_lib_module_t *self = lua_touserdata(L, lua_upvalueindex(1));
617 const dt_lighttable_layout_t tmp = _lib_lighttable_get_layout(self);
618 if(lua_gettop(L) > 0){
619 dt_lighttable_layout_t value;
620 luaA_to(L, dt_lighttable_layout_t, &value, 1);
621 _lib_lighttable_set_layout(self, value);
622 }
623 luaA_push(L, dt_lighttable_layout_t, &tmp);
624 return 1;
625 }
zoom_level_cb(lua_State * L)626 static int zoom_level_cb(lua_State *L)
627 {
628 dt_lib_module_t *self = lua_touserdata(L, lua_upvalueindex(1));
629 const gint tmp = _lib_lighttable_get_zoom(self);
630 if(lua_gettop(L) > 0){
631 int value;
632 luaA_to(L, int, &value, 1);
633 _lib_lighttable_set_zoom(self, value);
634 }
635 luaA_push(L, int, &tmp);
636 return 1;
637 }
638
init(struct dt_lib_module_t * self)639 void init(struct dt_lib_module_t *self)
640 {
641 lua_State *L = darktable.lua_state.state;
642 int my_type = dt_lua_module_entry_get_type(L, "lib", self->plugin_name);
643 lua_pushlightuserdata(L, self);
644 lua_pushcclosure(L, layout_cb, 1);
645 dt_lua_gtk_wrap(L);
646 lua_pushcclosure(L, dt_lua_type_member_common, 1);
647 dt_lua_type_register_const_type(L, my_type, "layout");
648 lua_pushlightuserdata(L, self);
649 lua_pushcclosure(L, zoom_level_cb, 1);
650 dt_lua_gtk_wrap(L);
651 lua_pushcclosure(L, dt_lua_type_member_common, 1);
652 dt_lua_type_register_const_type(L, my_type, "zoom_level");
653
654 luaA_enum(L,dt_lighttable_layout_t);
655 luaA_enum_value(L, dt_lighttable_layout_t, DT_LIGHTTABLE_LAYOUT_FIRST);
656 luaA_enum_value(L, dt_lighttable_layout_t, DT_LIGHTTABLE_LAYOUT_ZOOMABLE);
657 luaA_enum_value(L, dt_lighttable_layout_t, DT_LIGHTTABLE_LAYOUT_FILEMANAGER);
658 luaA_enum_value(L, dt_lighttable_layout_t, DT_LIGHTTABLE_LAYOUT_CULLING);
659 luaA_enum_value(L, dt_lighttable_layout_t, DT_LIGHTTABLE_LAYOUT_CULLING_DYNAMIC);
660 luaA_enum_value(L, dt_lighttable_layout_t, DT_LIGHTTABLE_LAYOUT_PREVIEW);
661 luaA_enum_value(L, dt_lighttable_layout_t, DT_LIGHTTABLE_LAYOUT_LAST);
662 }
663 #endif
664 // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
665 // vim: shiftwidth=2 expandtab tabstop=2 cindent
666 // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
667