diff --git a/src/develop/develop.c b/src/develop/develop.c index eef9b34d3596..7825417ae404 100644 --- a/src/develop/develop.c +++ b/src/develop/develop.c @@ -1464,17 +1464,9 @@ void dt_dev_add_masks_history_item_ext(dt_develop_t *dev, gboolean enable = _enable; // no module means that is called from the mask manager, so find the iop - if(module == NULL) + if (module == NULL) { - for(GList *modules = dev->iop; modules; modules = g_list_next(modules)) - { - dt_iop_module_t *mod = modules->data; - if(dt_iop_module_is(mod, "mask_manager")) - { - module = mod; - break; - } - } + module = dt_iop_get_module("mask_manager"); enable = FALSE; } if(module) diff --git a/src/develop/imageop.c b/src/develop/imageop.c index 6fe982d0bbb6..f9736ddfc46c 100644 --- a/src/develop/imageop.c +++ b/src/develop/imageop.c @@ -2816,7 +2816,8 @@ gboolean dt_iop_show_hide_header_buttons(dt_iop_module_t *module, return TRUE; } -static void _display_mask_indicator_callback(GtkToggleButton *bt, dt_iop_module_t *module) +static void _display_mask_indicator_callback(GtkToggleButton *bt, + dt_iop_module_t *module) { DT_GUARD_GUI_UPDATE(); diff --git a/src/develop/masks.h b/src/develop/masks.h index 786a1a80dbfd..e710ce743f2a 100644 --- a/src/develop/masks.h +++ b/src/develop/masks.h @@ -560,6 +560,8 @@ void dt_masks_replace_current_forms(dt_develop_t *dev, GList *forms); dt_masks_form_t *dt_masks_get_from_id_ext(GList *forms, dt_mask_id_t id); /** returns a form with formid == id from dev->forms */ dt_masks_form_t *dt_masks_get_from_id(const dt_develop_t *dev, dt_mask_id_t id); +/** check if a form is used by a given module (directly or as a child of its group) */ +gboolean dt_masks_is_in_module(dt_mask_id_t maskid, const struct dt_iop_module_t *module); /** register forms into the mask manager */ void dt_masks_register_forms(dt_develop_t *dev, GList *forms); diff --git a/src/develop/masks/masks.c b/src/develop/masks/masks.c index 031eb52e104e..c69382e4d7a6 100644 --- a/src/develop/masks/masks.c +++ b/src/develop/masks/masks.c @@ -319,6 +319,37 @@ static dt_masks_form_t *_group_from_module(const dt_develop_t *dev, return dt_masks_get_from_id(dev, module->blend_params->mask_id); } +static gboolean _form_is_in_group(const dt_develop_t *dev, + const dt_masks_form_t *group, + const dt_mask_id_t maskid) +{ + for(const GList *iter = group->points; iter; iter = g_list_next(iter)) + { + const dt_masks_point_group_t *pt = iter->data; + if(pt->formid == maskid) return TRUE; + + const dt_masks_form_t *child = dt_masks_get_from_id(dev, pt->formid); + if(child && (child->type & DT_MASKS_GROUP)) + { + if(_form_is_in_group(dev, child, maskid)) return TRUE; + } + } + return FALSE; +} + +gboolean dt_masks_is_in_module(const dt_mask_id_t maskid, const dt_iop_module_t *module) +{ + if(!dt_is_valid_maskid(maskid) || !module) return FALSE; + + if(maskid == module->blend_params->mask_id) return TRUE; + + const dt_masks_form_t *root = dt_masks_get_from_id(module->dev, module->blend_params->mask_id); + if(root && (root->type & DT_MASKS_GROUP)) + return _form_is_in_group(module->dev, root, maskid); + + return FALSE; +} + void dt_masks_register_forms(dt_develop_t *dev, GList *forms) { @@ -1129,8 +1160,7 @@ gboolean dt_masks_events_mouse_moved(dt_iop_module_t *module, 1. a module and it's not enabled 2. the mask manager and it is not expanded */ - const gboolean skipped = (module && !module->enabled) - && !dt_lib_gui_get_expanded(dt_lib_get_module("masks")); + const gboolean skipped = (module && !module->enabled); dt_print(DT_DEBUG_VERBOSE, "[dt_masks_events_mouse_moved] %s %s", diff --git a/src/libs/lib.c b/src/libs/lib.c index f0cf40a65b3b..31dc578adeb7 100644 --- a/src/libs/lib.c +++ b/src/libs/lib.c @@ -129,7 +129,7 @@ static void _set_module_preset_label(dt_lib_module_t *module, { if(!module->expander || !module->has_preset_label(module)) return; - + const gchar *current_preset_label_text = gtk_label_get_text(GTK_LABEL(module->preset_label)); gchar *preset_label_text = (*preset_name == '\0' || (!dt_conf_get_bool("darkroom/ui/auto_module_name_update")))? @@ -382,8 +382,8 @@ gboolean dt_lib_presets_apply(const gchar *preset, if(sqlite3_step(stmt) == SQLITE_ROW) { const void *blob = sqlite3_column_blob(stmt, 0); - int length = sqlite3_column_bytes(stmt, 0); - int writeprotect = sqlite3_column_int(stmt, 1); + const int length = sqlite3_column_bytes(stmt, 0); + const int writeprotect = sqlite3_column_int(stmt, 1); if(blob) { for(const GList *it = darktable.lib->plugins; it; it = g_list_next(it)) @@ -987,7 +987,7 @@ static gboolean _presets_popup_callback(GtkButton *button, return TRUE; } -void dt_lib_gui_set_expanded(dt_lib_module_t *module, gboolean expanded) +void dt_lib_gui_set_expanded(dt_lib_module_t *module, const gboolean expanded) { if(!module->expander || !module->arrow) return; @@ -1000,6 +1000,10 @@ void dt_lib_gui_set_expanded(dt_lib_module_t *module, gboolean expanded) darktable.lib->gui_module = expanded ? module : NULL; + /* if expanded, make sure the module is visible */ + if(module->expanded_state) + module->expanded_state(module, expanded); + /* store expanded state of module */ char var[1024]; const dt_view_t *current_view = dt_view_manager_get_current_view(darktable.view_manager); diff --git a/src/libs/lib_api.h b/src/libs/lib_api.h index f35230975188..6621a320d1e9 100644 --- a/src/libs/lib_api.h +++ b/src/libs/lib_api.h @@ -53,6 +53,8 @@ REQUIRED(uint32_t, container, struct dt_lib_module_t *self); if not the module will always be shown without the expander. */ DEFAULT(gboolean, expandable, struct dt_lib_module_t *self); +OPTIONAL(void, expanded_state, struct dt_lib_module_t *self, const gboolean expanded); + /** constructor */ OPTIONAL(void, init, struct dt_lib_module_t *self); /** callback methods for gui. */ diff --git a/src/libs/masks.c b/src/libs/masks.c index bdbb82415853..0cc282b06893 100644 --- a/src/libs/masks.c +++ b/src/libs/masks.c @@ -36,6 +36,11 @@ DT_MODULE(1) static void _lib_masks_recreate_list(dt_lib_module_t *self); static void _lib_masks_update_list(dt_lib_module_t *self); +static void _lib_masks_get_values(GtkTreeModel *model, + GtkTreeIter *iter, + dt_iop_module_t **module, + dt_mask_id_t *groupid, + dt_mask_id_t *formid); typedef struct dt_lib_masks_t { @@ -82,6 +87,68 @@ int position(const dt_lib_module_t *self) return 10; } +static gboolean _selected_masks_are_used(GtkTreeModel *model, + GList *selected, + dt_iop_module_t *module) +{ + for(GList *item = selected; item; item = g_list_next(item)) + { + GtkTreePath *ipath = (GtkTreePath *)item->data; + GtkTreeIter iter; + if(gtk_tree_model_get_iter(model, &iter, ipath)) + { + dt_mask_id_t id = INVALID_MASKID; + _lib_masks_get_values(model, &iter, NULL, NULL, &id); + + if(dt_is_valid_maskid(id) + && dt_masks_is_in_module(id, module)) + { + return TRUE; + } + } + } + + return FALSE; +} + +void expanded_state(dt_lib_module_t *self, + const gboolean expanded) +{ + // if not expanded we may want to disable the mask + + if (!expanded) + { + dt_develop_t *dev = darktable.develop; + dt_iop_module_t *mod = dev->gui_module; + const dt_iop_gui_blend_data_t *bd = mod ? mod->blend_data : NULL; + + /* + We hide the masks if: + - If the active module is not enabled + - If the active module is enabled but has no mask + - There is some selected masks in mask manage + - If the active module is enabled but the selected masks are not used by the + module. + */ + + dt_lib_masks_t *lm = self->data; + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(lm->treeview)); + GtkTreeModel *model = NULL; + GList *selected = gtk_tree_selection_get_selected_rows(selection, &model); + + if (!(mod + && mod->enabled + && (mod->blend_params->mask_mode & DEVELOP_MASK_MASK) + && bd->masks_shown != DT_MASKS_EDIT_OFF + && selected + && _selected_masks_are_used(model, selected, mod))) + { + dt_masks_change_form_gui(NULL); + dt_control_queue_redraw_center(); + } + } +} + typedef enum dt_masks_tree_cols_t { TREE_TEXT = 0,