64#define DT_IOP_ORDER_INFO (darktable.unmuted & DT_DEBUG_IOPORDER)
161 for(
const GList *modules = g_list_first(
darktable.
develop->
iop); modules; modules = g_list_next(modules))
166 reference = module->expander;
172 GtkBorder margin = { 0 };
173 GtkStyleContext *context = gtk_widget_get_style_context(reference);
174 gtk_style_context_get_margin(context, gtk_style_context_get_state(context), &margin);
178 gtk_widget_set_margin_start(
d->sections[
i], margin.left);
179 gtk_widget_set_margin_end(
d->sections[
i], margin.right);
180 gtk_widget_set_margin_top(
d->sections[
i], margin.top);
181 gtk_widget_set_margin_bottom(
d->sections[
i], margin.bottom);
195 if(
d &&
d->drag_highlight)
197 gtk_drag_unhighlight(
d->drag_highlight);
198 d->drag_highlight = NULL;
204 for(
const GList *modules = g_list_last(
darktable.
develop->
iop); modules; modules = g_list_previous(modules))
207 if(!module->expander)
continue;
225 if(!GTK_IS_WIDGET(widget) || !gtk_widget_is_visible(widget))
return;
227 if(g_object_get_data(G_OBJECT(widget),
"dt-module"))
229 *widgets = g_list_append(*widgets, widget);
233 if(!GTK_IS_CONTAINER(widget))
return;
236 GList *children = gtk_container_get_children(GTK_CONTAINER(widget));
237 for(GList *child = children; child; child = g_list_next(child))
239 g_list_free(children);
253 g_list_free(
d->visible_expanders);
254 d->visible_expanders = NULL;
275 d->visible_expanders_tab = tab;
293 if(!GTK_IS_WIDGET(page) || !module_src)
return NULL;
295 GtkAllocation source_allocation = { 0 };
296 gtk_widget_get_allocation(module_src->
header, &source_allocation);
297 const int y_slop = source_allocation.height / 2;
298 gboolean after_src =
TRUE;
301 GList *children = NULL;
305 for(GList *l = children; l; l = g_list_next(l))
312 if(!gtk_widget_translate_coordinates(w, page, 0, 0, &widget_x, &widget_y))
continue;
314 GtkAllocation allocation = { 0 };
315 gtk_widget_get_allocation(w, &allocation);
316 if((after_src && y <= widget_y + y_slop)
317 || (!after_src && y <= widget_y + allocation.height + y_slop))
319 module_dest = (
dt_iop_module_t *)g_object_get_data(G_OBJECT(w),
"dt-module");
324 g_list_free(children);
331 GtkSelectionData *selection_data, guint info, guint time,
334 guint time, gpointer user_data);
336 guint time, gpointer user_data);
338 GtkSelectionData *selection_data, guint info, guint time,
345 g_object_add_weak_pointer(G_OBJECT(widget), (gpointer *)slot);
365 gtk_widget_show(
d->pages[
i]);
392 gtk_widget_show(
d->sections[
i]);
400 gtk_widget_show(
d->containers[
i]);
415 const gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(
d->notebook));
427 gtk_notebook_set_current_page(GTK_NOTEBOOK(
d->notebook), tab);
451 return (tab == current_tab) && (
_is_module_in_history(module) ||
module->enabled || !(module->flags() & IOP_FLAGS_DEPRECATED));
492 return d->pages[tab];
508 g_object_set_data(G_OBJECT(widget),
"dt-module", module);
510 if(g_object_get_data(G_OBJECT(widget),
"modulegroups-dnd"))
return;
516 g_object_set_data(G_OBJECT(widget),
"modulegroups-dnd", GINT_TO_POINTER(
TRUE));
531 gboolean has_visible =
FALSE;
535 for(GList *modules = g_list_last(
darktable.
develop->
iop); modules; modules = g_list_previous(modules))
538 if(
dt_iop_is_hidden(module) || !
module->expander || !gtk_widget_get_visible(module->expander)) continue;
539 if(gtk_widget_get_parent(module->expander) != target)
continue;
541 gtk_box_reorder_child(GTK_BOX(target), module->expander,
position++);
554 d->drag_source = module_src;
556 g_object_set_data(G_OBJECT(widget),
"dt-module-dragged", GINT_TO_POINTER(
TRUE));
558 if(!module_src || !module_src->
header)
return;
560 GdkWindow *window = gtk_widget_get_parent_window(module_src->
header);
563 GtkAllocation allocation = { 0 };
564 gtk_widget_get_allocation(module_src->
header, &allocation);
566 cairo_t *cr = cairo_create(surface);
569 gtk_widget_draw(module_src->
header, cr);
572 cairo_surface_set_device_offset(surface, -allocation.width *
darktable.
gui->
ppd / 2,
574 gtk_drag_set_icon_surface(context, surface);
577 cairo_surface_destroy(surface);
586 d->drag_source = NULL;
587 g_object_set_data(G_OBJECT(widget),
"dt-module-dragged", NULL);
591 GtkSelectionData *selection_data, guint info, guint time,
594 const guint number_data = 1;
595 gtk_selection_data_set(selection_data, gdk_atom_intern(
"iop",
TRUE), 32, (
const guchar *)&number_data, 1);
599 guint time, gpointer user_data)
601 gtk_drag_get_data(widget, dc, gdk_atom_intern(
"iop",
TRUE), time);
606 guint time, gpointer user_data)
614 gboolean can_move =
FALSE;
617 if(module_dest && module_src != module_dest)
627 gdk_drag_status(dc, 0, time);
636 d->drag_highlight = module_dest->
expander;
637 gtk_drag_highlight(module_dest->
expander);
638 gdk_drag_status(dc, GDK_ACTION_COPY, time);
643 GtkSelectionData *selection_data, guint info, guint time,
651 if(module_src && module_dest && module_src != module_dest)
661 d->drag_source = NULL;
673 return _(
"modulegroups");
678 static const char *
v[] = {
"darkroom", NULL };
701 GdkModifierType modifier, gpointer data)
715 GdkModifierType modifier, gpointer data)
731 int delta_x, delta_y;
736 if(delta_x > 0. || delta_y > 0.)
737 future = current + 1;
738 else if(delta_x < 0. || delta_y < 0.)
739 future = current - 1;
764 GdkModifierType modifier, gpointer user_data)
777 const GList *children =
d->visible_expanders;
780 GList *first = g_list_first((GList *)children);
781 GtkWidget *widget = first ? GTK_WIDGET(first->data) : NULL;
791 for(
const GList *module = g_list_first((GList *)children);
module;
module = g_list_next(module))
793 GtkWidget *widget = GTK_WIDGET(module->data);
794 if(widget == focused->
expander)
break;
795 target = (
dt_iop_module_t *)g_object_get_data(G_OBJECT(widget),
"dt-module");
799 GList *last = g_list_last((GList *)children);
800 GtkWidget *widget = last ? GTK_WIDGET(last->data) : NULL;
801 target = widget ? (
dt_iop_module_t *)g_object_get_data(G_OBJECT(widget),
"dt-module") : NULL;
812 GdkModifierType modifier, gpointer user_data)
825 const GList *children =
d->visible_expanders;
828 GList *last = g_list_last((GList *)children);
829 GtkWidget *widget = last ? GTK_WIDGET(last->data) : NULL;
839 for(
const GList *module = g_list_last((GList *)children);
module;
module = g_list_previous(module))
841 GtkWidget *widget = GTK_WIDGET(module->data);
842 if(widget == focused->
expander)
break;
843 target = (
dt_iop_module_t *)g_object_get_data(G_OBJECT(widget),
"dt-module");
847 GList *first = g_list_first((GList *)children);
848 GtkWidget *widget = first ? GTK_WIDGET(first->data) : NULL;
849 target = widget ? (
dt_iop_module_t *)g_object_get_data(G_OBJECT(widget),
"dt-module") : NULL;
868 GtkWidget *parent = gtk_widget_get_parent(widget);
872 gtk_widget_get_name(widget));
876 GtkWidget *grandparent = gtk_widget_get_parent(parent);
880 gtk_widget_get_name(widget), gtk_widget_get_name(parent));
884 GType
type = G_OBJECT_TYPE(grandparent);
886 gboolean visible_parent =
TRUE;
888 if(
type == GTK_TYPE_NOTEBOOK)
891 gint page_num = gtk_notebook_page_num(GTK_NOTEBOOK(grandparent), parent);
893 gtk_notebook_set_current_page(GTK_NOTEBOOK(grandparent), page_num);
895 visible_parent =
FALSE;
897 else if(
type == GTK_TYPE_STACK)
901 GtkWidget *visible_child = gtk_stack_get_visible_child(GTK_STACK(grandparent));
902 if(visible_child != parent) visible_parent =
FALSE;
905 return gtk_widget_is_visible(widget) && gtk_widget_is_sensitive(widget)
914 for(GList *first = widgets; first; first = g_list_next(first))
925 for(GList *last = widgets; last; last = g_list_previous(last))
935 gtk_widget_grab_focus(widget);
944 if(!focused || !
m->widget_list)
return FALSE;
949 if(!current_widget && first_item)
956 GList *current_item = g_list_find(
m->widget_list, current_widget);
974 if(!focused || !
m->widget_list)
return FALSE;
979 if(!current_widget && last_item)
986 GList *current_item = g_list_find(
m->widget_list, current_widget);
1004 self->
data = (
void *)
d;
1006 d->visible_expanders = NULL;
1011 gtk_widget_set_name(self->
widget,
"modules-tabs");
1014 d->notebook = GTK_WIDGET(gtk_notebook_new());
1016 char *labels[] = { _(
"Pipeline"), _(
"Basic"), _(
"Repair"), _(
"Sharpness"), _(
"Effects"), _(
"Technics"), _(
"All") };
1018 = { _(
"List all modules currently enabled in the reverse order of application in the pipeline."),
1019 _(
"Modules destined to adjust brightness, contrast and dynamic range, work with film scans, and perform color-grading."),
1020 _(
"Modules destined to repair and reconstruct noisy or missing pixels."),
1021 _(
"Modules destined to manipulate local contrast, sharpness and blur."),
1022 _(
"Modules applying special effects."),
1023 _(
"Technical modules that can be ignored in most situations."),
1024 _(
"All modules available in the software.") };
1030 gtk_widget_set_tooltip_text(label, tooltips[
i]);
1031 gtk_widget_set_halign(label, GTK_ALIGN_CENTER);
1032 gtk_widget_set_hexpand(label,
TRUE);
1033 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
1036 gtk_notebook_append_page(GTK_NOTEBOOK(
d->notebook), page, label);
1037 gtk_container_child_set(GTK_CONTAINER(
d->notebook), page,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
1038 gtk_widget_show(page);
1042 gtk_notebook_set_current_page(GTK_NOTEBOOK(
d->notebook),
dt_conf_get_int(
"plugins/darkroom/moduletab"));
1043 gtk_notebook_popup_enable(GTK_NOTEBOOK(
d->notebook));
1044 gtk_notebook_set_scrollable(GTK_NOTEBOOK(
d->notebook),
TRUE);
1045 g_signal_connect(G_OBJECT(
d->notebook),
"switch_page", G_CALLBACK(
_switch_page), self);
1046 g_signal_connect(G_OBJECT(
d->notebook),
"scroll-event", G_CALLBACK(
_scroll_event), self);
1049 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(
d->notebook),
TRUE,
TRUE, 0);
1050 gtk_widget_show_all(self->
widget);
1066 N_(
"move to the next modules tab"), GDK_KEY_Tab, GDK_CONTROL_MASK, _(
"Triggers the action"));
1068 N_(
"move to the previous modules tab"), GDK_KEY_Tab,
1069 GDK_CONTROL_MASK | GDK_SHIFT_MASK, _(
"Triggers the action"));
1072 N_(
"Focus on the next module"), GDK_KEY_Page_Down, 0, _(
"Triggers the action"));
1074 N_(
"Focus on the previous module"), GDK_KEY_Page_Up, 0, _(
"Triggers the action"));
1077 N_(
"Focus on the next module control"), GDK_KEY_Down, GDK_CONTROL_MASK, _(
"Triggers the action"));
1079 N_(
"Focus on the previous module control"), GDK_KEY_Up, GDK_CONTROL_MASK, _(
"Triggers the action"));
1100 for(GList *modules = g_list_first(
darktable.
develop->
iop); modules; modules = g_list_next(modules))
1109 gtk_widget_destroy(
d->pages[
i]);
1122 if(hitem->module == module)
return TRUE;
1130 if(!GTK_IS_WIDGET(widget) || !GTK_IS_BOX(target))
return FALSE;
1132 GtkWidget *parent = gtk_widget_get_parent(widget);
1133 if(parent == target)
return FALSE;
1135 g_object_ref(widget);
1136 if(GTK_IS_CONTAINER(parent)) gtk_container_remove(GTK_CONTAINER(parent), widget);
1137 gtk_box_pack_start(GTK_BOX(target), widget,
FALSE,
FALSE, 0);
1138 g_object_unref(widget);
1158 for(GList *modules = g_list_last(
darktable.
develop->
iop); modules; modules = g_list_previous(modules))
1181 if(visible && (in_history || module->multi_priority == 0))
1210 const gboolean scroll_new_instance_to_header
1225 gtk_widget_set_visible(
d->sections[
i], has_section);
1226 gtk_widget_set_visible(
d->containers[
i], has_section);
1236 gtk_widget_queue_resize(
d->pages[tab]);
1237 gtk_widget_queue_draw(
d->pages[tab]);
1239 return G_SOURCE_REMOVE;
1257 const gboolean prefer_active_once
1259 && GPOINTER_TO_INT(g_object_get_data(G_OBJECT(iop_module->
expander),
1260 "dt-modulegroups-prefer-active-once"));
1261 const gboolean allow_switch_from_active
1263 && GPOINTER_TO_INT(g_object_get_data(G_OBJECT(iop_module->
expander),
1264 "dt-modulegroups-switch-from-active-once"));
1268 g_object_set_data(G_OBJECT(iop_module->
expander),
"dt-modulegroups-prefer-active-once", NULL);
1269 g_object_set_data(G_OBJECT(iop_module->
expander),
"dt-modulegroups-switch-from-active-once", NULL);
1273 if(prefer_active_once && module_in_active_tab && current_tab !=
MOD_TAB_ACTIVE)
1277 else if(allow_switch_from_active && module_in_active_tab && current_tab !=
MOD_TAB_ACTIVE)
1282 else if((current_tab !=
MOD_TAB_ACTIVE || allow_switch_from_active)
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
void dt_print(dt_debug_thread_t thread, const char *msg,...)
#define DT_MODULE(MODVER)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
dt_dev_history_item_t * dt_dev_history_get_last_item_by_module(GList *history_list, dt_iop_module_t *module, int history_end)
Find the last history item referencing a module up to history_end.
int32_t dt_dev_get_history_end_ext(struct dt_develop_t *dev)
Get the current history end index (GUI perspective).
void dt_dev_modules_update_multishow(dt_develop_t *dev)
#define dt_pthread_rwlock_unlock
#define dt_pthread_rwlock_rdlock
gboolean dt_gui_get_scroll_unit_deltas(const GdkEventScroll *event, int *delta_x, int *delta_y)
void dt_gui_remove_class(GtkWidget *widget, const gchar *class_name)
void dt_gui_add_help_link(GtkWidget *widget, char *link)
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
#define dt_accels_new_darkroom_locked_action(a, b, c, d, e, f, g)
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
#define dt_accels_new_darkroom_action(a, b, c, d, e, f, g)
static GtkWidget * dt_ui_section_label_new(const gchar *str)
#define DT_GUI_BOX_SPACING
GtkBox * dt_ui_get_container(dt_ui_t *ui, const dt_ui_container_t c)
void dt_iop_request_focus(dt_iop_module_t *module)
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.
void dt_iop_gui_set_expanded(dt_iop_module_t *module, gboolean expanded, gboolean collapse_others)
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.
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.
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)
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
@ 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 _GtkWidget GtkWidget
struct dt_gui_gtk_t * gui
struct dt_control_signal_t * signals
struct dt_develop_t * develop
struct dt_iop_module_t * gui_module
dt_pthread_rwlock_t history_mutex
GtkWidget * has_scroll_focus
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...
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)
@ DT_UI_CONTAINER_PANEL_RIGHT_CENTER
@ DT_UI_CONTAINER_PANEL_RIGHT_TOP