diff --git a/data/themes/darktable-elegant-highcontrast.css b/data/themes/darktable-elegant-highcontrast.css
index ce514283368c..ba21229f38e7 100644
--- a/data/themes/darktable-elegant-highcontrast.css
+++ b/data/themes/darktable-elegant-highcontrast.css
@@ -37,5 +37,5 @@
@define-color graph_fg_active @grey_100;
@define-color graph_grid @grey_00;
-#iop-panel-label, #lib-panel-label, #iop-module-name { color: @fg_color; }
+#iop-panel-label, #lib-panel-label, #iop-module-name, #lib-module-name { color: @fg_color; }
#module-header .toggle:checked { color: @fg_color; }
diff --git a/data/themes/darktable-icons-highcontrast.css b/data/themes/darktable-icons-highcontrast.css
index f94a1f4d3a09..06b17e1b6cc4 100644
--- a/data/themes/darktable-icons-highcontrast.css
+++ b/data/themes/darktable-icons-highcontrast.css
@@ -37,5 +37,5 @@
@define-color graph_fg_active @grey_100;
@define-color graph_grid @grey_00;
-#iop-panel-label, #lib-panel-label, #iop-module-name { color: @fg_color; }
+#iop-panel-label, #lib-panel-label, #iop-module-name, #lib-module-name { color: @fg_color; }
#module-header .toggle:checked { color: @fg_color; }
diff --git a/data/themes/darktable.css b/data/themes/darktable.css
index e3defb87dbe2..92d28f089a13 100644
--- a/data/themes/darktable.css
+++ b/data/themes/darktable.css
@@ -600,7 +600,8 @@ dialog .sidebar row:selected:hover label,
}
#snapshot-button entry,
-#iop-module-name
+#iop-module-name,
+#lib-module-name
{
font-weight: lighter;
font-family: sans-serif, "Arial Unicode MS";
diff --git a/src/libs/filtering.c b/src/libs/filtering.c
index d6e30f39942a..613175457d65 100644
--- a/src/libs/filtering.c
+++ b/src/libs/filtering.c
@@ -19,10 +19,8 @@
#include "bauhaus/bauhaus.h"
#include "common/collection.h"
#include "common/darktable.h"
-#include "common/metadata.h"
#include "control/conf.h"
#include "control/control.h"
-#include "control/jobs.h"
#include "dtgtk/button.h"
#include "dtgtk/range.h"
#include "gui/accelerators.h"
diff --git a/src/libs/import.c b/src/libs/import.c
index d9ad5c68a3ca..f2a9a50f7a8f 100644
--- a/src/libs/import.c
+++ b/src/libs/import.c
@@ -1,6 +1,6 @@
/*
This file is part of darktable,
- Copyright (C) 2011-2024 darktable developers.
+ Copyright (C) 2011-2025 darktable developers.
darktable is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,11 +16,9 @@
along with darktable. If not, see .
*/
-#include "bauhaus/bauhaus.h"
#include "common/collection.h"
#include "common/darktable.h"
#include "common/file_location.h"
-#include "common/debug.h"
#include "common/exif.h"
#include "common/metadata.h"
#include "common/datetime.h"
@@ -29,7 +27,6 @@
#ifdef HAVE_GPHOTO2
#include "control/jobs/camera_jobs.h"
#endif
-#include "dtgtk/expander.h"
#include "dtgtk/button.h"
#include "gui/accelerators.h"
#include "gui/gtk.h"
diff --git a/src/libs/lib.c b/src/libs/lib.c
index 39bb6325a60a..725024df953d 100644
--- a/src/libs/lib.c
+++ b/src/libs/lib.c
@@ -1,6 +1,6 @@
/*
This file is part of darktable,
- Copyright (C) 2009-2024 darktable developers.
+ Copyright (C) 2009-2025 darktable developers.
darktable is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,14 +23,10 @@
#include "control/control.h"
#include "dtgtk/button.h"
#include "dtgtk/expander.h"
-#include "dtgtk/icon.h"
#include "gui/accelerators.h"
#include "gui/drag_and_drop.h"
#include "gui/gtk.h"
#include "gui/presets.h"
-#ifdef GDK_WINDOWING_QUARTZ
-#include "osx/osx.h"
-#endif
#include
#include
@@ -103,8 +99,38 @@ gchar *dt_lib_get_active_preset_name(dt_lib_module_info_t *minfo)
return name;
}
-static void edit_preset(const char *name_in,
- dt_lib_module_info_t *minfo)
+// get dt_lib_module_info_t for a module. Must be freed by _free_module_info()
+static dt_lib_module_info_t *_get_module_info_for_module(dt_lib_module_t *module)
+{
+ dt_lib_module_info_t *mi = calloc(1, sizeof(dt_lib_module_info_t));
+
+ mi->plugin_name = g_strdup(module->plugin_name);
+ mi->version = module->version();
+ mi->module = module;
+ mi->params = module->get_params ? module->get_params(module, &mi->params_size) : NULL;
+ if(!mi->params)
+ {
+ // this is a valid case, for example in location.c when nothing got selected
+ // fprintf(stderr, "something went wrong: ¶ms=%p, size=%i\n",
+ // mi->params, mi->params_size);
+ mi->params_size = 0;
+ }
+ return mi;
+}
+
+static void _set_module_preset_label(dt_lib_module_t *module,
+ const gchar *preset_name)
+{
+ if(!module->expander) return;
+
+ gchar *preset_label_text = (*preset_name == '\0')? g_strdup("")
+ : g_strdup_printf("• %s", preset_name);
+ gtk_label_set_text(GTK_LABEL(module->preset_label), preset_label_text);
+ g_free(preset_label_text);
+}
+
+static void _edit_preset(const char *name_in,
+ dt_lib_module_info_t *minfo)
{
// get the original name of the preset
gchar *name = NULL;
@@ -144,8 +170,8 @@ static void edit_preset(const char *name_in,
GTK_WINDOW(window));
}
-static void menuitem_update_preset(GtkMenuItem *menuitem,
- dt_lib_module_info_t *minfo)
+static void _menuitem_update_preset(GtkMenuItem *menuitem,
+ dt_lib_module_info_t *minfo)
{
char *name = g_object_get_data(G_OBJECT(menuitem), "dt-preset-name");
@@ -177,8 +203,8 @@ static void menuitem_update_preset(GtkMenuItem *menuitem,
}
}
-static void menuitem_new_preset(GtkMenuItem *menuitem,
- dt_lib_module_info_t *minfo)
+static void _menuitem_new_preset(GtkMenuItem *menuitem,
+ dt_lib_module_info_t *minfo)
{
dt_lib_presets_remove(_("new preset"), minfo->plugin_name, minfo->version);
@@ -208,23 +234,23 @@ static void menuitem_new_preset(GtkMenuItem *menuitem,
dt_action_define_preset(&minfo->module->actions, _("new preset"));
// then show edit dialog
- edit_preset(_("new preset"), minfo);
+ _edit_preset(_("new preset"), minfo);
}
-static void menuitem_edit_preset(GtkMenuItem *menuitem,
- dt_lib_module_info_t *minfo)
+static void _menuitem_edit_preset(GtkMenuItem *menuitem,
+ dt_lib_module_info_t *minfo)
{
- edit_preset(NULL, minfo);
+ _edit_preset(NULL, minfo);
}
-static void menuitem_manage_presets(GtkMenuItem *menuitem,
- dt_lib_module_info_t *minfo)
+static void _menuitem_manage_presets(GtkMenuItem *menuitem,
+ dt_lib_module_info_t *minfo)
{
if(minfo->module->manage_presets) minfo->module->manage_presets(minfo->module);
}
-static void menuitem_delete_preset(GtkMenuItem *menuitem,
- dt_lib_module_info_t *minfo)
+static void _menuitem_delete_preset(GtkMenuItem *menuitem,
+ dt_lib_module_info_t *minfo)
{
gchar *name = dt_lib_get_active_preset_name(minfo);
if(name == NULL) return;
@@ -237,6 +263,7 @@ static void menuitem_delete_preset(GtkMenuItem *menuitem,
dt_action_rename_preset(&minfo->module->actions, name, NULL);
dt_lib_presets_remove(name, minfo->plugin_name, minfo->version);
+ _set_module_preset_label(minfo->module, "");
DT_CONTROL_SIGNAL_RAISE(DT_SIGNAL_PRESETS_CHANGED,
g_strdup(minfo->plugin_name));
@@ -356,6 +383,8 @@ gboolean dt_lib_presets_apply(const gchar *preset,
dt_conf_set_string(tx, preset);
g_free(tx);
res = module->set_params(module, blob, length);
+ if(!res)
+ _set_module_preset_label(module, preset);
break;
}
}
@@ -418,8 +447,8 @@ static gboolean _menuitem_button_preset(GtkMenuItem *menuitem,
return TRUE;
}
-static void free_module_info(GtkWidget *widget,
- gpointer user_data)
+static void _free_module_info(GtkWidget *widget,
+ gpointer user_data)
{
dt_lib_module_info_t *minfo = (dt_lib_module_info_t *)user_data;
g_free(minfo->plugin_name);
@@ -427,15 +456,15 @@ static void free_module_info(GtkWidget *widget,
free(minfo);
}
-static void dt_lib_presets_popup_menu_show(dt_lib_module_info_t *minfo,
- GtkWidget *w)
+static void _dt_lib_presets_popup_menu_show(dt_lib_module_info_t *minfo,
+ GtkWidget *w)
{
GtkMenu *menu = GTK_MENU(gtk_menu_new());
const gboolean hide_default = dt_conf_get_bool("plugins/lighttable/hide_default_presets");
const gboolean default_first = dt_conf_get_bool("modules/default_presets_first");
- g_signal_connect(G_OBJECT(menu), "destroy", G_CALLBACK(free_module_info), minfo);
+ g_signal_connect(G_OBJECT(menu), "destroy", G_CALLBACK(_free_module_info), minfo);
GtkWidget *mi;
int active_preset = -1, cnt = 0;
@@ -529,7 +558,7 @@ static void dt_lib_presets_popup_menu_show(dt_lib_module_info_t *minfo,
if(minfo->module->manage_presets)
{
mi = gtk_menu_item_new_with_label(_("manage presets..."));
- g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(menuitem_manage_presets), minfo);
+ g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(_menuitem_manage_presets), minfo);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
cnt++;
}
@@ -538,11 +567,11 @@ static void dt_lib_presets_popup_menu_show(dt_lib_module_info_t *minfo,
if(!selected_writeprotect)
{
mi = gtk_menu_item_new_with_label(_("edit this preset.."));
- g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(menuitem_edit_preset), minfo);
+ g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(_menuitem_edit_preset), minfo);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
mi = gtk_menu_item_new_with_label(_("delete this preset"));
- g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(menuitem_delete_preset), minfo);
+ g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(_menuitem_delete_preset), minfo);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
cnt++;
}
@@ -556,7 +585,7 @@ static void dt_lib_presets_popup_menu_show(dt_lib_module_info_t *minfo,
gtk_widget_set_tooltip_text(mi, _("nothing to save"));
}
else
- g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(menuitem_new_preset), minfo);
+ g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(_menuitem_new_preset), minfo);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
if(darktable.gui->last_preset && found)
@@ -570,7 +599,7 @@ static void dt_lib_presets_popup_menu_show(dt_lib_module_info_t *minfo,
g_object_set_data_full(G_OBJECT(mi), "dt-preset-name",
g_strdup(darktable.gui->last_preset), g_free);
g_signal_connect(G_OBJECT(mi), "activate",
- G_CALLBACK(menuitem_update_preset), minfo);
+ G_CALLBACK(_menuitem_update_preset), minfo);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
g_free(markup);
}
@@ -634,6 +663,11 @@ static gboolean default_preset_autoapply(dt_lib_module_t *self)
return FALSE;
}
+/* default gui_update implementation */
+static void default_gui_update(dt_lib_module_t *self)
+{
+}
+
static int dt_lib_load_module(void *m,
const char *libname,
const char *module_name)
@@ -666,6 +700,7 @@ static int dt_lib_load_module(void *m,
module->widget = NULL;
module->expander = NULL;
module->arrow = NULL;
+ module->preset_label = NULL;
module->reset_button = NULL;
module->presets_button = NULL;
@@ -852,11 +887,20 @@ void dt_lib_gui_queue_update(dt_lib_module_t *module)
void dt_lib_gui_update(dt_lib_module_t *module)
{
- if(module && module->gui_update && !module->gui_uptodate)
+ if(module && !module->gui_uptodate)
{
module->gui_update(module);
module->gui_uptodate = TRUE;
}
+
+ if(module->preset_label)
+ {
+ dt_lib_module_info_t *mi = _get_module_info_for_module(module);
+ gchar *active_preset_name = dt_lib_get_active_preset_name(mi);
+ _free_module_info(NULL, mi);
+ _set_module_preset_label(module, active_preset_name? active_preset_name : "");
+ g_free(active_preset_name);
+ }
}
static void dt_lib_init_module(void *m)
@@ -873,9 +917,8 @@ static void dt_lib_init_module(void *m)
if(module->widget)
{
g_object_ref_sink(module->widget);
- if(module->gui_update)
- g_signal_connect(G_OBJECT(module->widget), "draw",
- G_CALLBACK(_lib_draw_callback), module);
+ g_signal_connect(G_OBJECT(module->widget), "draw",
+ G_CALLBACK(_lib_draw_callback), module);
}
}
}
@@ -892,6 +935,7 @@ static gboolean _lib_gui_reset_callback(GtkButton *button,
{
dt_lib_module_t *module = (dt_lib_module_t *)user_data;
module->gui_reset(module);
+ gtk_label_set_text(GTK_LABEL(module->preset_label), "");
return TRUE;
}
@@ -899,20 +943,8 @@ static gboolean _presets_popup_callback(GtkButton *button,
GdkEventButton *e,
dt_lib_module_t *module)
{
- dt_lib_module_info_t *mi = calloc(1, sizeof(dt_lib_module_info_t));
-
- mi->plugin_name = g_strdup(module->plugin_name);
- mi->version = module->version();
- mi->module = module;
- mi->params = module->get_params ? module->get_params(module, &mi->params_size) : NULL;
- if(!mi->params)
- {
- // this is a valid case, for example in location.c when nothing got selected
- // fprintf(stderr, "something went wrong: ¶ms=%p, size=%i\n",
- // mi->params, mi->params_size);
- mi->params_size = 0;
- }
- dt_lib_presets_popup_menu_show(mi, GTK_WIDGET(button));
+ dt_lib_module_info_t *mi = _get_module_info_for_module(module);
+ _dt_lib_presets_popup_menu_show(mi, GTK_WIDGET(button));
if(button)
dtgtk_button_set_active(DTGTK_BUTTON(button), FALSE);
@@ -1275,6 +1307,14 @@ GtkWidget *dt_lib_gui_get_expander(dt_lib_module_t *module)
dt_action_define(&module->actions, NULL, NULL, label_evb, NULL);
gtk_box_pack_start(GTK_BOX(header), label_evb, FALSE, FALSE, 0);
+ /* add preset label */
+ module->preset_label = gtk_label_new(NULL);
+ gtk_widget_set_name(module->preset_label, "lib-module-name");
+ gtk_label_set_ellipsize(GTK_LABEL(module->preset_label), PANGO_ELLIPSIZE_MIDDLE);
+ gtk_widget_set_valign(module->preset_label, GTK_ALIGN_BASELINE);
+ g_object_set(G_OBJECT(module->preset_label), "xalign", 0.0, (gchar *)0);
+ gtk_box_pack_start(GTK_BOX(header), module->preset_label, FALSE, FALSE, 0);
+
/* add preset button if module has implementation */
module->presets_button = dtgtk_button_new(dtgtk_cairo_paint_presets, 0, NULL);
gtk_widget_set_tooltip_text(module->presets_button, _("presets and preferences"));
@@ -1316,6 +1356,15 @@ GtkWidget *dt_lib_gui_get_expander(dt_lib_module_t *module)
dt_gui_add_class(pluginui_frame, "dt_plugin_ui");
module->expander = expander;
+ // get active preset and set preset_label
+ dt_lib_module_info_t *mi = _get_module_info_for_module(module);
+ gchar *preset_name = dt_lib_get_active_preset_name(mi);
+ if(preset_name)
+ {
+ _set_module_preset_label(mi->module, preset_name);
+ g_free(preset_name);
+ }
+ _free_module_info(NULL, mi);
return module->expander;
}
@@ -1538,6 +1587,11 @@ gboolean dt_lib_presets_can_autoapply(dt_lib_module_t *mod)
return mod->preset_autoapply(mod);
}
+void dt_lib_reset_preset_label(dt_lib_module_t *mod)
+{
+ gtk_label_set_text(GTK_LABEL(mod->preset_label), "");
+}
+
static float _action_process(gpointer target,
const dt_action_element_t element,
const dt_action_effect_t effect,
diff --git a/src/libs/lib.h b/src/libs/lib.h
index 04d1319c4cdc..395c2b6b20bc 100644
--- a/src/libs/lib.h
+++ b/src/libs/lib.h
@@ -1,6 +1,6 @@
/*
This file is part of darktable,
- Copyright (C) 2009-2023 darktable developers.
+ Copyright (C) 2009-2025 darktable developers.
darktable is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -28,11 +28,7 @@
#include "gui/presets.h"
#ifdef USE_LUA
-#include "lua/call.h"
-#include "lua/events.h"
#include "lua/lib.h"
-#include "lua/modules.h"
-#include "lua/types.h"
#endif
struct dt_lib_module_t;
@@ -116,6 +112,7 @@ typedef struct dt_lib_module_t
gboolean gui_uptodate;
GtkWidget *arrow;
+ GtkWidget *preset_label;
GtkWidget *reset_button;
GtkWidget *presets_button;
diff --git a/src/libs/lib_api.h b/src/libs/lib_api.h
index d2116a3d4504..b7e2c0338d23 100644
--- a/src/libs/lib_api.h
+++ b/src/libs/lib_api.h
@@ -64,7 +64,7 @@ OPTIONAL(void, gui_reset, struct dt_lib_module_t *self);
/** update libs gui when visible
triggered by dt_lib_gui_queue_update.
don't use for widgets accessible via actions when hidden. */
-OPTIONAL(void, gui_update, struct dt_lib_module_t *self);
+DEFAULT(void, gui_update, struct dt_lib_module_t *self);
OPTIONAL(GtkWidget *, gui_tool_box, struct dt_lib_module_t *self);
diff --git a/src/libs/metadata.c b/src/libs/metadata.c
index f8b42ed644c7..f53555a51802 100644
--- a/src/libs/metadata.c
+++ b/src/libs/metadata.c
@@ -1520,14 +1520,19 @@ void *get_params(dt_lib_module_t *self, int *size)
GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview);
GtkTextIter start, end;
gtk_text_buffer_get_bounds(buffer, &start, &end);
- const gchar *tagname = g_object_get_data(G_OBJECT(textview), "tagname");
- metadata_tagnames[i] = g_strdup(tagname);
- metadata_tagname_len[i] = strlen(metadata_tagnames[i]) + 1;
- metadata_texts[i] = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
- if(!metadata_texts[i]) metadata_texts[i] = g_strdup("");
- metadata_len[i] = strlen(metadata_texts[i]) + 1;
- *size = *size + metadata_tagname_len[i] + metadata_len[i];
- i++;
+ gchar *tagtext = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
+ if(*tagtext != '\0')
+ {
+ const gchar *tagname = g_object_get_data(G_OBJECT(textview), "tagname");
+ metadata_tagnames[i] = g_strdup(tagname);
+ metadata_tagname_len[i] = strlen(metadata_tagnames[i]) + 1;
+ metadata_texts[i] = tagtext;
+ metadata_len[i] = strlen(metadata_texts[i]) + 1;
+ *size = *size + metadata_tagname_len[i] + metadata_len[i];
+ i++;
+ }
+ else
+ g_free(tagtext);
}
dt_pthread_mutex_unlock(&darktable.metadata_threadsafe);