76 return _(
"Auto style");
81 static const char *
v[] = {
"studio_capture", NULL };
97 for(GList *l =
d->pool; l; l = g_list_next(l))
98 if(!g_strcmp0((
const char *)l->data,
name))
return TRUE;
107 GString *conf = g_string_new(NULL);
108 for(GList *l =
d->pool; l; l = g_list_next(l))
111 g_string_append(conf, (
const char *)l->data);
115 g_string_free(conf,
TRUE);
125 for(GList *l =
d->pool; l; l = g_list_next(l))
127 gtk_list_store_append(
store, &iter);
130 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->pool_treeview), GTK_TREE_MODEL(
store));
131 g_object_unref(
store);
142 GList *next = g_list_next(l);
143 gboolean found =
FALSE;
144 for(GList *s = all_styles; s && !found; s = g_list_next(s))
145 found = !g_strcmp0(((
dt_style_t *)s->data)->name, (
const char *)l->data);
149 d->pool = g_list_delete_link(
d->pool, l);
161 const gchar *segment_name)
163 GtkTreeIter parent = *iter;
167 if(!gtk_tree_model_get_iter_first(
model, iter))
169 gtk_tree_store_append(GTK_TREE_STORE(
model), iter, NULL);
175 if(!gtk_tree_model_iter_children(
model, iter, &parent))
177 gtk_tree_store_append(GTK_TREE_STORE(
model), iter, &parent);
184 gchar *node_name = NULL;
186 const gboolean match = !g_strcmp0(node_name, segment_name);
188 if(match)
return TRUE;
190 while(gtk_tree_model_iter_next(
model, iter));
192 gtk_tree_store_append(GTK_TREE_STORE(
model), iter, root ? NULL : &parent);
209 for(GList *s = all_styles; s; s = g_list_next(s))
212 gchar **segments = g_strsplit(style->
name,
"|", 0);
214 for(
int k = 0; segments[
k];
k++)
225 g_strfreev(segments);
228 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->styles_treeview), GTK_TREE_MODEL(
store));
229 g_object_unref(
store);
241 GtkTreeModel *
model, GtkTreeIter *iter, gpointer user_data)
244 gchar *fullname = NULL;
248 g_object_set(renderer,
"foreground-set",
TRUE,
"foreground",
"#888", NULL);
250 g_object_set(renderer,
"foreground-set",
FALSE, NULL);
261 GtkTreeModel *
model, GtkTreeIter *iter, gpointer user_data)
264 gchar *fullname = NULL;
269 g_object_set(renderer,
"visible",
FALSE, NULL);
274 g_object_set(renderer,
"visible",
TRUE,
"pixbuf", in_pool ?
d->add_icon_disabled :
d->add_icon_enabled,
287 const int index = gtk_tree_path_get_indices(path)[0];
289 if(column ==
d->pool_up_col)
291 if(index <= 0)
return;
292 GList *previous = g_list_nth(
d->pool, index - 1);
293 GList *current = g_list_next(previous);
294 gpointer tmp = previous->data;
295 previous->data = current->data;
298 else if(column ==
d->pool_down_col)
300 GList *current = g_list_nth(
d->pool, index);
301 GList *next = current ? g_list_next(current) : NULL;
303 gpointer tmp = current->data;
304 current->data = next->data;
307 else if(column ==
d->pool_remove_col)
309 GList *link = g_list_nth(
d->pool, index);
311 char *removed_name = (
char *)link->data;
312 d->pool = g_list_delete_link(
d->pool, link);
313 gtk_widget_queue_draw(
d->styles_treeview);
332 if(
IS_NULL_PTR(event) ||
event->type != GDK_BUTTON_PRESS ||
event->button != GDK_BUTTON_PRIMARY)
return FALSE;
334 GtkTreePath *path = NULL;
335 GtkTreeViewColumn *column = NULL;
336 if(!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), (gint)event->x, (gint)event->y, &path, &column,
340 const gboolean consumed = column ==
d->pool_up_col || column ==
d->pool_down_col
341 || column ==
d->pool_remove_col;
343 gtk_tree_path_free(path);
348 GtkTooltip *
tooltip, gpointer user_data)
351 if(keyboard_tip)
return FALSE;
353 GtkTreePath *path = NULL;
354 GtkTreeViewColumn *column = NULL;
355 if(!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview),
x, y, &path, &column, NULL, NULL))
return FALSE;
356 gtk_tree_path_free(path);
358 const char *text = NULL;
359 if(column ==
d->pool_up_col) text = _(
"Apply this style earlier");
360 else if(column ==
d->pool_down_col) text = _(
"Apply this style later");
361 else if(column ==
d->pool_remove_col) text = _(
"Remove this style from the pool");
364 gtk_tooltip_set_text(
tooltip, text);
373 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
375 if(!gtk_tree_model_get_iter(
model, &iter, path))
return FALSE;
377 gchar *fullname = NULL;
383 d->pool = g_list_append(
d->pool, g_strdup(fullname));
385 gtk_widget_queue_draw(
d->styles_treeview);
395 if(
IS_NULL_PTR(event) ||
event->type != GDK_BUTTON_PRESS ||
event->button != GDK_BUTTON_PRIMARY)
return FALSE;
397 GtkTreePath *path = NULL;
398 GtkTreeViewColumn *column = NULL;
399 if(!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), (gint)event->x, (gint)event->y, &path, &column,
403 gboolean consumed =
FALSE;
405 gtk_tree_path_free(path);
410 GtkTooltip *
tooltip, gpointer user_data)
413 if(keyboard_tip)
return FALSE;
415 GtkTreePath *path = NULL;
416 GtkTreeViewColumn *column = NULL;
417 if(!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview),
x, y, &path, &column, NULL, NULL))
return FALSE;
418 gtk_tree_path_free(path);
420 if(column !=
d->styles_add_col)
return FALSE;
421 gtk_tooltip_set_text(
tooltip, _(
"Add this style to the pool"));
447 for(GList *l =
d->pool; l; l = g_list_next(l))
449 const char *pool_name = (
const char *)l->data;
469 dt_control_log(ngettext(
"Applied %d style.",
"Applied %d styles.", applied), applied);
489 for(gchar **pool_name = names; *pool_name; pool_name++)
490 if((*pool_name)[0] !=
'\0')
d->pool = g_list_append(
d->pool, g_strdup(*pool_name));
500 GtkCellRenderer **out_renderer)
502 GtkTreeViewColumn *col = gtk_tree_view_column_new();
503 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
504 g_object_set(renderer,
"ellipsize", PANGO_ELLIPSIZE_END, (gchar *)0);
505 gtk_tree_view_column_pack_start(col, renderer,
TRUE);
506 gtk_tree_view_column_add_attribute(col, renderer,
"text", name_model_col);
507 gtk_tree_view_column_set_expand(col,
TRUE);
508 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), col);
509 if(out_renderer) *out_renderer = renderer;
518 GtkCellRenderer **out_renderer)
520 GtkTreeViewColumn *col = gtk_tree_view_column_new();
521 GtkCellRenderer *renderer = gtk_cell_renderer_pixbuf_new();
522 g_object_set(renderer,
"icon-name", icon_name,
"stock-size", GTK_ICON_SIZE_MENU, NULL);
523 gtk_tree_view_column_pack_start(col, renderer,
FALSE);
524 gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED);
526 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), col);
527 if(out_renderer) *out_renderer = renderer;
541 gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &
width, &
height);
543 GdkPixbuf *base = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), icon_name,
width,
544 GTK_ICON_LOOKUP_FORCE_SIZE, NULL);
547 cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
width,
height);
548 cairo_t *cr = cairo_create(surface);
549 gdk_cairo_set_source_pixbuf(cr, base, 0, 0);
550 cairo_paint_with_alpha(cr, alpha);
553 GdkPixbuf *dimmed = gdk_pixbuf_get_from_surface(surface, 0, 0,
width,
height);
554 cairo_surface_destroy(surface);
555 g_object_unref(base);
562 self->
data = (
void *)
d;
567 GtkWidget *pool_label = gtk_label_new(_(
"Pool"));
568 gtk_widget_set_halign(pool_label, GTK_ALIGN_START);
571 d->pool_treeview = gtk_tree_view_new();
572 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(
d->pool_treeview),
FALSE);
578 gtk_widget_set_has_tooltip(
d->pool_treeview,
TRUE);
581 gtk_box_pack_start(GTK_BOX(self->
widget),
582 dt_ui_scroll_wrap(
d->pool_treeview, 100,
"plugins/darkroom/studio_style/poolwindowheight",
586 GtkWidget *apply = gtk_button_new_with_label(_(
"Apply to the displayed image"));
587 gtk_widget_set_tooltip_text(apply, _(
"Replace the history of the displayed image with the pool of styles"));
592 GtkWidget *styles_label = gtk_label_new(_(
"Styles"));
593 gtk_widget_set_halign(styles_label, GTK_ALIGN_START);
599 d->styles_treeview = gtk_tree_view_new();
600 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(
d->styles_treeview),
FALSE);
601 GtkCellRenderer *name_renderer = NULL;
602 GtkTreeViewColumn *name_col
606 GtkCellRenderer *add_renderer = NULL;
610 g_object_set(add_renderer,
"icon-name", NULL, NULL);
614 gtk_widget_set_has_tooltip(
d->styles_treeview,
TRUE);
617 gtk_box_pack_start(GTK_BOX(self->
widget),
637 if(!
IS_NULL_PTR(
d->add_icon_enabled)) g_object_unref(
d->add_icon_enabled);
638 if(!
IS_NULL_PTR(
d->add_icon_disabled)) g_object_unref(
d->add_icon_disabled);
void dt_image_history_changed(const int32_t imgid, const gboolean refresh_filmstrip)
gchar * dt_conf_get_string(const char *name)
void dt_conf_set_string(const char *name, const char *val)
void dt_control_log(const char *msg,...)
#define DT_MODULE(MODVER)
static void dt_free_gpointer(gpointer ptr)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
int store(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *sdata, const int32_t imgid, dt_imageio_module_format_t *format, dt_imageio_module_data_t *fdata, const int num, const int total, const gboolean high_quality, const gboolean export_masks, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, dt_export_metadata_t *metadata)
#define DT_FOLDER_SURVEY_STYLES_SEPARATOR
#define DT_FOLDER_SURVEY_STYLES_CONF_KEY
GtkWidget * dt_ui_scroll_wrap(GtkWidget *w, gint min_size, char *config_str, dt_ui_resize_mode_t mode)
Wrap a scrollable content widget in a recessed, vertically resizable scrolled window.
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
void dt_hm_batch_state_cleanup(dt_hm_batch_state_t *batch)
Release resources held by a batch state (the cached order). Safe to call on a zeroed state.
@ DT_HISTORY_MERGE_APPEND
float *const restrict const size_t k
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
@ DT_SIGNAL_DEVELOP_HISTORY_CHANGE
This signal is raised when develop history is changed no param, no returned value.
@ DT_SIGNAL_STYLE_CHANGED
This signal is raised when a style is added/deleted/changed
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
struct _GtkWidget GtkWidget
int dt_styles_apply_to_image_merge(const char *name, const int style_id, const int32_t newimgid, const dt_history_merge_strategy_t mode, dt_hm_batch_state_t *batch)
void dt_style_free(gpointer data)
int32_t dt_styles_get_id_by_name(const char *name)
GList * dt_styles_get_list(const char *filter)
struct dt_control_signal_t * signals
GtkTreeViewColumn * pool_down_col
GtkWidget * pool_treeview
GtkWidget * styles_treeview
GdkPixbuf * add_icon_disabled
GtkTreeViewColumn * pool_up_col
GdkPixbuf * add_icon_enabled
GtkTreeViewColumn * styles_add_col
GtkTreeViewColumn * pool_remove_col
static gboolean _studio_style_styles_button_pressed(GtkWidget *treeview, GdkEventButton *event, gpointer user_data)
static GtkTreeViewColumn * _studio_style_add_name_column(GtkWidget *treeview, const int name_model_col, GtkCellRenderer **out_renderer)
Append the text column carrying the row's display name. Packed with expand=TRUE so any later-appended...
static gboolean _studio_style_pool_query_tooltip(GtkWidget *treeview, gint x, gint y, gboolean keyboard_tip, GtkTooltip *tooltip, gpointer user_data)
static void _studio_style_populate_styles_tree(dt_lib_studio_style_t *d)
Rebuild the styles tree from every available style, grouping category segments split on "|" in the st...
static GtkTreeViewColumn * _studio_style_add_icon_column(GtkWidget *treeview, const char *icon_name, GtkCellRenderer **out_renderer)
Append one fixed-width icon column, for per-row action clicks handled by column identity (see the *_b...
static gboolean _studio_style_pool_contains(dt_lib_studio_style_t *d, const char *name)
static gboolean _studio_style_add_click(dt_lib_studio_style_t *d, GtkWidget *treeview, GtkTreePath *path)
Add the style leaf under a click to the end of the pool.
static gboolean _studio_style_get_node_for_name(GtkTreeModel *model, const gboolean root, GtkTreeIter *iter, const gchar *segment_name)
Find, or create as a child of the last found/created sibling, the tree node for one "|"-separated pat...
static void _studio_style_save(dt_lib_studio_style_t *d)
Persist the pool, in order, to conf.
void gui_cleanup(dt_lib_module_t *self)
static void _studio_style_changed_callback(gpointer instance, gpointer user_data)
static gboolean _studio_style_pool_button_pressed(GtkWidget *treeview, GdkEventButton *event, gpointer user_data)
Left click on a pool row's up/down/remove icon column.
static gboolean _studio_style_styles_query_tooltip(GtkWidget *treeview, gint x, gint y, gboolean keyboard_tip, GtkTooltip *tooltip, gpointer user_data)
static void _studio_style_name_cell_data_func(GtkTreeViewColumn *column, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data)
Gray a leaf's name when its style is already in the pool. Computed live at render time (not stored in...
uint32_t container(dt_lib_module_t *self)
static void _studio_style_pool_action_click(dt_lib_studio_style_t *d, GtkTreePath *path, GtkTreeViewColumn *column)
Apply the up/down/remove action for the pool row under a click, identified by which icon column was h...
static GdkPixbuf * _studio_style_load_icon(const char *icon_name, const double alpha)
Load a themed icon at the menu icon size, optionally pre-blended to a lower alpha....
static void _studio_style_apply_callback(GtkWidget *widget, gpointer user_data)
Re-apply the pool, in order, to the displayed image.
void gui_init(dt_lib_module_t *self)
const char ** views(dt_lib_module_t *self)
static void _studio_style_load_pool(dt_lib_studio_style_t *d)
Load the persisted, ordered pool from conf, once at startup.
static void _studio_style_rebuild_pool_ui(dt_lib_studio_style_t *d)
Rebuild the pool treeview, in order, from d->pool.
static void _studio_style_prune_pool(dt_lib_studio_style_t *d, GList *all_styles)
Drop pool entries whose style no longer exists.
static void _studio_style_add_cell_data_func(GtkTreeViewColumn *column, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data)
Show the add icon only on leaves, swapping in a pre-dimmed pixbuf when the leaf's style is already in...
int32_t dt_view_active_images_get_first()
@ DT_UI_CONTAINER_PANEL_LEFT_CENTER