64#include <glib/gstdio.h>
71#define DT_IOP_ORDER_INFO (dt_get_debug_flags() & DT_DEBUG_IOPORDER)
168 for(
const GList *modules = g_list_first(
dt_dev_get_global()->iop); modules; modules = g_list_next(modules))
173 reference = module->gui->expander;
179 GtkBorder margin = { 0 };
180 GtkStyleContext *context = gtk_widget_get_style_context(
reference);
181 gtk_style_context_get_margin(context, gtk_style_context_get_state(context), &margin);
185 gtk_widget_set_margin_start(
d->sections[
i], margin.left);
186 gtk_widget_set_margin_end(
d->sections[
i], margin.right);
187 gtk_widget_set_margin_top(
d->sections[
i], margin.top);
188 gtk_widget_set_margin_bottom(
d->sections[
i], margin.bottom);
202 if(
d &&
d->drag_highlight)
204 gtk_drag_unhighlight(
d->drag_highlight);
205 d->drag_highlight = NULL;
211 for(
const GList *modules = g_list_last(
dt_dev_get_global()->iop); modules; modules = g_list_previous(modules))
214 if(!module->gui || !module->gui->expander)
continue;
232 if(!GTK_IS_WIDGET(widget) || !gtk_widget_is_visible(widget))
return;
234 if(g_object_get_data(G_OBJECT(widget),
"dt-module"))
236 *widgets = g_list_append(*widgets, widget);
240 if(!GTK_IS_CONTAINER(widget))
return;
243 GList *children = gtk_container_get_children(GTK_CONTAINER(widget));
244 for(GList *child = children; child; child = g_list_next(child))
246 g_list_free(children);
260 g_list_free(
d->visible_expanders);
261 d->visible_expanders = NULL;
282 d->visible_expanders_tab = tab;
300 if(!GTK_IS_WIDGET(page) || !module_src)
return NULL;
302 GtkAllocation source_allocation = { 0 };
303 gtk_widget_get_allocation(module_src->
gui->
header, &source_allocation);
304 const int y_slop = source_allocation.height / 2;
305 gboolean after_src =
TRUE;
308 GList *children = NULL;
312 for(GList *l = children; l; l = g_list_next(l))
319 if(!gtk_widget_translate_coordinates(w, page, 0, 0, &widget_x, &widget_y))
continue;
321 GtkAllocation allocation = { 0 };
322 gtk_widget_get_allocation(w, &allocation);
323 if((after_src && y <= widget_y + y_slop)
324 || (!after_src && y <= widget_y + allocation.height + y_slop))
326 module_dest = (
dt_iop_module_t *)g_object_get_data(G_OBJECT(w),
"dt-module");
331 g_list_free(children);
338 GtkSelectionData *selection_data, guint info, guint time,
341 guint time, gpointer user_data);
343 guint time, gpointer user_data);
345 GtkSelectionData *selection_data, guint info, guint time,
352 g_object_add_weak_pointer(G_OBJECT(widget), (gpointer *)slot);
372 gtk_widget_show(
d->pages[
i]);
399 gtk_widget_show(
d->sections[
i]);
407 gtk_widget_show(
d->containers[
i]);
422 const gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(
d->notebook));
434 gtk_notebook_set_current_page(GTK_NOTEBOOK(
d->notebook), tab);
461 return (tab == current_tab) && (
_is_module_in_history(module) ||
module->enabled || !(module->flags() & IOP_FLAGS_DEPRECATED));
502 return d->pages[tab];
518 GtkWidget *widget =
module->gui->expander;
519 g_object_set_data(G_OBJECT(widget),
"dt-module", module);
521 if(g_object_get_data(G_OBJECT(widget),
"modulegroups-dnd"))
return;
527 g_object_set_data(G_OBJECT(widget),
"modulegroups-dnd", GINT_TO_POINTER(
TRUE));
542 gboolean has_visible =
FALSE;
546 for(GList *modules = g_list_last(
dt_dev_get_global()->iop); modules; modules = g_list_previous(modules))
550 || !gtk_widget_get_visible(module->gui->expander)) continue;
551 if(gtk_widget_get_parent(module->gui->expander) != target)
continue;
553 gtk_box_reorder_child(GTK_BOX(target), module->gui->expander,
position++);
566 d->drag_source = module_src;
568 g_object_set_data(G_OBJECT(widget),
"dt-module-dragged", GINT_TO_POINTER(
TRUE));
570 if(!module_src || !module_src->
gui->
header)
return;
572 GdkWindow *
window = gtk_widget_get_parent_window(module_src->
gui->
header);
575 GtkAllocation allocation = { 0 };
576 gtk_widget_get_allocation(module_src->
gui->
header, &allocation);
578 cairo_t *cr = cairo_create(surface);
581 gtk_widget_draw(module_src->
gui->
header, cr);
584 cairo_surface_set_device_offset(surface, -allocation.width *
dt_gui_get_global()->ppd / 2,
586 gtk_drag_set_icon_surface(context, surface);
589 cairo_surface_destroy(surface);
598 d->drag_source = NULL;
599 g_object_set_data(G_OBJECT(widget),
"dt-module-dragged", NULL);
603 GtkSelectionData *selection_data, guint info, guint time,
606 const guint number_data = 1;
607 gtk_selection_data_set(selection_data, gdk_atom_intern(
"iop",
TRUE), 32, (
const guchar *)&number_data, 1);
611 guint time, gpointer user_data)
613 gtk_drag_get_data(widget, dc, gdk_atom_intern(
"iop",
TRUE), time);
618 guint time, gpointer user_data)
626 gboolean can_move =
FALSE;
629 if(module_dest && module_src != module_dest)
639 gdk_drag_status(dc, 0, time);
650 gdk_drag_status(dc, GDK_ACTION_COPY, time);
655 GtkSelectionData *selection_data, guint info, guint time,
663 if(module_src && module_dest && module_src != module_dest)
673 d->drag_source = NULL;
685 return _(
"modulegroups");
690 static const char *
v[] = {
"darkroom", NULL };
713 GdkModifierType modifier, gpointer data)
727 GdkModifierType modifier, gpointer data)
743 int delta_x, delta_y;
748 if(delta_x > 0. || delta_y > 0.)
749 future = current + 1;
750 else if(delta_x < 0. || delta_y < 0.)
751 future = current - 1;
776 GdkModifierType modifier, gpointer user_data)
789 const GList *children =
d->visible_expanders;
792 GList *first = g_list_first((GList *)children);
793 GtkWidget *widget = first ? GTK_WIDGET(first->data) : NULL;
803 for(
const GList *module = g_list_first((GList *)children);
module;
module = g_list_next(module))
805 GtkWidget *widget = GTK_WIDGET(module->data);
807 target = (
dt_iop_module_t *)g_object_get_data(G_OBJECT(widget),
"dt-module");
811 GList *last = g_list_last((GList *)children);
812 GtkWidget *widget = last ? GTK_WIDGET(last->data) : NULL;
813 target = widget ? (
dt_iop_module_t *)g_object_get_data(G_OBJECT(widget),
"dt-module") : NULL;
824 GdkModifierType modifier, gpointer user_data)
837 const GList *children =
d->visible_expanders;
840 GList *last = g_list_last((GList *)children);
841 GtkWidget *widget = last ? GTK_WIDGET(last->data) : NULL;
851 for(
const GList *module = g_list_last((GList *)children);
module;
module = g_list_previous(module))
853 GtkWidget *widget = GTK_WIDGET(module->data);
855 target = (
dt_iop_module_t *)g_object_get_data(G_OBJECT(widget),
"dt-module");
859 GList *first = g_list_first((GList *)children);
860 GtkWidget *widget = first ? GTK_WIDGET(first->data) : NULL;
861 target = widget ? (
dt_iop_module_t *)g_object_get_data(G_OBJECT(widget),
"dt-module") : NULL;
880 GtkWidget *parent = gtk_widget_get_parent(widget);
884 gtk_widget_get_name(widget));
888 GtkWidget *grandparent = gtk_widget_get_parent(parent);
892 gtk_widget_get_name(widget), gtk_widget_get_name(parent));
896 GType
type = G_OBJECT_TYPE(grandparent);
898 gboolean visible_parent =
TRUE;
900 if(
type == GTK_TYPE_NOTEBOOK)
903 gint page_num = gtk_notebook_page_num(GTK_NOTEBOOK(grandparent), parent);
905 gtk_notebook_set_current_page(GTK_NOTEBOOK(grandparent), page_num);
907 visible_parent =
FALSE;
909 else if(
type == GTK_TYPE_STACK)
913 GtkWidget *visible_child = gtk_stack_get_visible_child(GTK_STACK(grandparent));
914 if(visible_child != parent) visible_parent =
FALSE;
917 return gtk_widget_is_visible(widget) && gtk_widget_is_sensitive(widget)
926 for(GList *first = widgets; first; first = g_list_next(first))
937 for(GList *last = widgets; last; last = g_list_previous(last))
947 gtk_widget_grab_focus(widget);
956 if(!focused || !
m->widget_list)
return FALSE;
961 if(!current_widget && first_item)
968 GList *current_item = g_list_find(
m->widget_list, current_widget);
986 if(!focused || !
m->widget_list)
return FALSE;
991 if(!current_widget && last_item)
998 GList *current_item = g_list_find(
m->widget_list, current_widget);
1016 self->
data = (
void *)
d;
1018 d->visible_expanders = NULL;
1023 gtk_widget_set_name(self->
widget,
"modules-tabs");
1026 d->notebook = GTK_WIDGET(gtk_notebook_new());
1028 char *labels[] = { _(
"Pipeline"), _(
"Basic"), _(
"Repair"), _(
"Sharpness"), _(
"Effects"), _(
"Technics"), _(
"All") };
1030 = { _(
"List all modules currently enabled in the reverse order of application in the pipeline."),
1031 _(
"Modules destined to adjust brightness, contrast and dynamic range, work with film scans, and perform color-grading."),
1032 _(
"Modules destined to repair and reconstruct noisy or missing pixels."),
1033 _(
"Modules destined to manipulate local contrast, sharpness and blur."),
1034 _(
"Modules applying special effects."),
1035 _(
"Technical modules that can be ignored in most situations."),
1036 _(
"All modules available in the software.") };
1042 gtk_widget_set_tooltip_text(label, tooltips[
i]);
1043 gtk_widget_set_halign(label, GTK_ALIGN_CENTER);
1044 gtk_widget_set_hexpand(label,
TRUE);
1045 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
1048 gtk_notebook_append_page(GTK_NOTEBOOK(
d->notebook), page, label);
1049 gtk_container_child_set(GTK_CONTAINER(
d->notebook), page,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
1050 gtk_widget_show(page);
1054 gtk_notebook_set_current_page(GTK_NOTEBOOK(
d->notebook),
dt_conf_get_int(
"plugins/darkroom/moduletab"));
1055 gtk_notebook_popup_enable(GTK_NOTEBOOK(
d->notebook));
1056 gtk_notebook_set_scrollable(GTK_NOTEBOOK(
d->notebook),
TRUE);
1057 g_signal_connect(G_OBJECT(
d->notebook),
"switch_page", G_CALLBACK(
_switch_page), self);
1058 g_signal_connect(G_OBJECT(
d->notebook),
"scroll-event", G_CALLBACK(
_scroll_event), self);
1061 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(
d->notebook),
TRUE,
TRUE, 0);
1062 gtk_widget_show_all(self->
widget);
1081 N_(
"move to the next modules tab"), GDK_KEY_Tab, GDK_CONTROL_MASK, _(
"Triggers the action"));
1083 N_(
"move to the previous modules tab"), GDK_KEY_Tab,
1084 GDK_CONTROL_MASK | GDK_SHIFT_MASK, _(
"Triggers the action"));
1087 N_(
"Focus on the next module"), GDK_KEY_Page_Down, 0, _(
"Triggers the action"));
1089 N_(
"Focus on the previous module"), GDK_KEY_Page_Up, 0, _(
"Triggers the action"));
1092 N_(
"Focus on the next module control"), GDK_KEY_Down,
DT_PRIMARY_MASK, _(
"Triggers the action"));
1094 N_(
"Focus on the previous module control"), GDK_KEY_Up,
DT_PRIMARY_MASK, _(
"Triggers the action"));
1115 for(GList *modules = g_list_first(
dt_dev_get_global()->iop); modules; modules = g_list_next(modules))
1124 gtk_widget_destroy(
d->pages[
i]);
1134 for(GList *history = g_list_last(
dt_dev_get_global()->history); history; history = g_list_previous(history))
1137 if(hitem->module == module)
return TRUE;
1145 if(!GTK_IS_WIDGET(widget) || !GTK_IS_BOX(target))
return FALSE;
1147 GtkWidget *parent = gtk_widget_get_parent(widget);
1148 if(parent == target)
return FALSE;
1150 g_object_ref(widget);
1151 if(GTK_IS_CONTAINER(parent)) gtk_container_remove(GTK_CONTAINER(parent), widget);
1152 gtk_box_pack_start(GTK_BOX(target), widget,
FALSE,
FALSE, 0);
1153 g_object_unref(widget);
1172 for(GList *modules = g_list_last(dev->
iop); modules; modules = g_list_previous(modules))
1177 GtkWidget *w =
module->gui ? module->gui->expander : NULL;
1220 const gboolean scroll_new_instance_to_header
1235 gtk_widget_set_visible(
d->sections[
i], has_section);
1236 gtk_widget_set_visible(
d->containers[
i], has_section);
1246 gtk_widget_queue_resize(
d->pages[tab]);
1247 gtk_widget_queue_draw(
d->pages[tab]);
1249 return G_SOURCE_REMOVE;
1268 const gboolean prefer_active_once
1270 && GPOINTER_TO_INT(g_object_get_data(G_OBJECT(expander),
1271 "dt-modulegroups-prefer-active-once"));
1272 const gboolean allow_switch_from_active
1274 && GPOINTER_TO_INT(g_object_get_data(G_OBJECT(expander),
1275 "dt-modulegroups-switch-from-active-once"));
1279 g_object_set_data(G_OBJECT(expander),
"dt-modulegroups-prefer-active-once", NULL);
1280 g_object_set_data(G_OBJECT(expander),
"dt-modulegroups-switch-from-active-once", NULL);
1284 if(prefer_active_once && module_in_active_tab && current_tab !=
MOD_TAB_ACTIVE)
1288 else if(allow_switch_from_active && module_in_active_tab && current_tab !=
MOD_TAB_ACTIVE)
1293 else if((current_tab !=
MOD_TAB_ACTIVE || allow_switch_from_active)
Handle default and user-set shortcuts (accelerators)
#define dt_accels_new_darkroom_action(a, b, w, c, d, e, f, g)
struct dt_ui_t * dt_gui_get_ui(void)
void dt_gui_add_help_link(GtkWidget *widget, char *link)
#define dt_accels_new_darkroom_locked_action(a, b, w, c, d, e, f, g)
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
struct dt_develop_t * dt_dev_get_global(void)
struct dt_gui_gtk_t * dt_gui_get_global(void)
void dt_dev_modules_update_multishow(dt_develop_t *dev)
gboolean dt_iop_module_is_in_pipeline(dt_iop_module_t *iop)
gboolean dt_iop_is_hidden(dt_iop_module_t *module)
gboolean dt_iop_gui_move_module_before(dt_iop_module_t *module, dt_iop_module_t *module_next, const char *reason)
Move a module before another one and commit the GUI-side effects.
gboolean dt_iop_module_instance_exists(dt_iop_module_t *iop)
gboolean dt_iop_gui_move_module_after(dt_iop_module_t *module, dt_iop_module_t *module_prev, const char *reason)
Move a module after another one and commit the GUI-side effects.
void dt_iop_request_focus(dt_iop_module_t *module)
Move darkroom focus to module, or clear it with NULL.
void dt_iop_gui_set_expanded(dt_iop_module_t *module, gboolean expanded, gboolean collapse_others)
gboolean dt_iop_gui_module_is_visible(dt_iop_module_t *module)
gboolean dt_ioppr_check_can_move_before_iop(GList *iop_list, dt_iop_module_t *module, dt_iop_module_t *module_next)
Validate whether module can be moved before module_next.
gboolean dt_ioppr_check_can_move_after_iop(GList *iop_list, dt_iop_module_t *module, dt_iop_module_t *module_prev)
Validate whether module can be moved after module_prev.
GtkWidget * dt_ui_section_label_new(const gchar *str)
_lib_location_type_t type
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...
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
#define DT_MODULE(MODVER)
Instantiate the version handshake every module must export. Use once, at file scope,...
static dt_modulesgroups_tabs_t _get_current_tab(dt_lib_module_t *self)
dt_modulegroups_dnd_target_t
@ DT_MODULEGROUPS_DND_TARGET_IOP
static void _modulegroups_clear_drop_state(dt_lib_modulegroups_t *d)
Remove all drag-and-drop visual feedback from module headers.
static gboolean _focus_previous_control()
static GList * _find_previous_visible_widget(GList *widgets)
static void _modulegroups_drag_data_get(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time, gpointer user_data)
static gboolean _focus_next_module(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval, GdkModifierType modifier, gpointer user_data)
static void _modulegroups_clear_visible_expanders_cache(dt_lib_modulegroups_t *d)
Drop the cached list of visible expanders used for keyboard module focus.
static void _modulegroups_setup_drag_source(dt_lib_module_t *self, dt_iop_module_t *module)
Attach the module drag source handlers once to an expander widget.
dt_modulesgroups_tabs_t _modulegroups_cycle_tabs(int tab)
static gboolean _modulegroups_drag_drop(GtkWidget *widget, GdkDragContext *dc, gint x, gint y, guint time, gpointer user_data)
static GtkWidget * _get_target_container(dt_lib_module_t *self, const dt_iop_module_t *module)
Return the GtkBox currently hosting a module for the active tab.
void gui_cleanup(dt_lib_module_t *self)
static dt_modulesgroups_tabs_t _group_to_tab(dt_iop_group_t group)
static GList * _find_next_visible_widget(GList *widgets)
static void _modulegroups_append_visible_expanders(GtkWidget *widget, GList **widgets)
Append visible module expanders in display order from a page subtree.
static void _ensure_page_widgets(dt_lib_module_t *self)
static void _set_current_tab_from_module_group(dt_lib_module_t *self, dt_iop_group_t group)
static const guint _modulegroups_n_targets
static dt_iop_module_t * _modulegroups_get_dnd_dest_module(GtkWidget *page, const gint y, dt_iop_module_t *module_src)
Find the module header under the current drop position.
static void _modulegroups_track_widget(GtkWidget **slot, GtkWidget *widget)
static gboolean _modulegroups_switch_tab_next(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval, GdkModifierType modifier, gpointer data)
static void _modulegroups_drag_data_received(GtkWidget *widget, GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time, gpointer user_data)
uint32_t container(dt_lib_module_t *self)
static void _set_current_tab(dt_lib_module_t *self, dt_modulesgroups_tabs_t tab)
static void _modulegroups_drag_leave(GtkWidget *widget, GdkDragContext *dc, guint time, gpointer user_data)
static gboolean _update_iop_visibility(gpointer user_data)
static gboolean _is_valid_widget(GtkWidget *widget)
static gboolean _is_module_in_history(const dt_iop_module_t *module)
static const GtkTargetEntry _modulegroups_target_list[]
void gui_init(dt_lib_module_t *self)
static gboolean _modulegroups_drag_motion(GtkWidget *widget, GdkDragContext *dc, gint x, gint y, guint time, gpointer user_data)
const char ** views(dt_lib_module_t *self)
dt_modulesgroups_basic_sections_t
int expandable(dt_lib_module_t *self)
static void _modulegroups_sync_section_label_margins(dt_lib_modulegroups_t *d)
Align the basic-tab section labels with the module expander margins.
static void _modulegroups_refresh_visible_expanders_cache(dt_lib_module_t *self, dt_modulesgroups_tabs_t tab)
Rebuild the visible expander cache for one tab after GUI update.
static gboolean _is_module_in_tab(dt_iop_module_t *module, dt_modulesgroups_tabs_t current_tab)
static gboolean _modulegroups_switch_tab_previous(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval, GdkModifierType modifier, gpointer data)
static void _modulegroups_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer user_data)
static gboolean _scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
static gboolean _modulegroups_reorder_target(GtkWidget *target)
Reorder one page or subgroup container to match reverse pipeline order.
static void _lib_modulegroups_signal_set(gpointer instance, gpointer module, gpointer user_data)
static void _modulegroups_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer user_data)
static void _lib_modulegroups_refresh(gpointer instance, gpointer user_data)
static void _switch_page(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data)
static gboolean _modulegroups_move_widget(GtkWidget *widget, GtkWidget *target)
static gboolean _focus_next_control()
static void _focus_widget(GtkWidget *widget)
static void _focus_module(dt_iop_module_t *module)
static gboolean _focus_previous_module(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval, GdkModifierType modifier, gpointer user_data)
static double reference(const op_t op, const double x)
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
struct dt_control_signal_t * dt_control_signal_get_global(void)
@ DT_SIGNAL_DEVELOP_INITIALIZE
This signal is raised when darktable.develop is initialized.
@ DT_SIGNAL_DEVELOP_IMAGE_CHANGED
This signal is raised when image is changed in darkroom.
@ DT_SIGNAL_DEVELOP_MODULE_MOVED
This signal is raised when order of modules in pipeline is changed.
@ DT_SIGNAL_DEVELOP_MODULEGROUPS_SET
This signal is raised to request a modulegroups update. 1 : dt_iop_module_t *module,...
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
struct dt_iop_module_t * gui_module
GtkWidget * scroll_to_header_once
The dt_gui_module_t type is the intersection between a dt_lib_module_t and a dt_iop_module_t structur...
struct dt_iop_module_gui_t * gui
GtkWidget * containers[TAB_BASIC_LAST]
GList * visible_expanders
GtkWidget * sections[TAB_BASIC_LAST]
GtkWidget * drag_highlight
dt_modulesgroups_tabs_t visible_expanders_tab
GtkWidget * pages[MOD_TAB_LAST]
dt_iop_module_t * drag_source
dt_thumbtable_t * thumbtable_filmstrip
char * dt_get_help_url(char *name)
GtkBox * dt_ui_get_container(dt_ui_t *ui, const dt_ui_container_t c)
@ DT_UI_CONTAINER_PANEL_RIGHT_CENTER
@ DT_UI_CONTAINER_PANEL_RIGHT_TOP