103 GtkTooltip *
tooltip, gpointer user_data);
105 GtkTreeModel *
model, GtkTreeIter *iter, gpointer data);
109 return _(
"History of changes");
114 static const char *
v[] = {
"darkroom", NULL};
132 self->
data = (
void *)
d;
134 d->selection_reset =
FALSE;
137 gtk_widget_set_name(self->
widget,
"history-ui");
147 d->history_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(
d->history_store));
148 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(
d->history_view),
FALSE);
149 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(
d->history_view),
FALSE);
151 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->history_view));
152 gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
156 gtk_widget_set_has_tooltip(
d->history_view,
TRUE);
159 GtkCellRenderer *renderer_num = gtk_cell_renderer_text_new();
160 g_object_set(G_OBJECT(renderer_num),
"xalign", 1.0,
"family",
"monospace", NULL);
161 GtkTreeViewColumn *col_num = gtk_tree_view_column_new_with_attributes(
"n", renderer_num,
165 gtk_tree_view_column_set_sizing(col_num, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
166 gtk_tree_view_append_column(GTK_TREE_VIEW(
d->history_view), col_num);
168 GtkCellRenderer *renderer_label = gtk_cell_renderer_text_new();
169 g_object_set(G_OBJECT(renderer_label),
"ellipsize", PANGO_ELLIPSIZE_END, NULL);
170 GtkTreeViewColumn *col_label = gtk_tree_view_column_new_with_attributes(
"label", renderer_label,
174 gtk_tree_view_column_set_expand(col_label,
TRUE);
175 gtk_tree_view_append_column(GTK_TREE_VIEW(
d->history_view), col_label);
177 GtkCellRenderer *renderer_icon = gtk_cell_renderer_pixbuf_new();
178 GtkTreeViewColumn *col_icon = gtk_tree_view_column_new_with_attributes(
"status", renderer_icon,
181 gtk_tree_view_column_set_sizing(col_icon, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
182 gtk_tree_view_append_column(GTK_TREE_VIEW(
d->history_view), col_icon);
189 gtk_widget_show_all(self->
widget);
201 if(
d &&
d->history_store) g_object_unref(
d->history_store);
206 const gboolean deprecated)
208 if(always_on)
return "emblem-readonly";
209 if(deprecated)
return "dialog-warning";
212 if(default_enabled)
return enabled ?
"object-select-symbolic" :
"process-stop";
213 return enabled ?
"object-select-symbolic" :
"process-stop";
226 gchar **change_parts = g_malloc0_n(field->
Struct.
entries + 1,
sizeof(
char*));
248 gchar *struct_text = num_parts ? g_strjoinv(
"\n", change_parts) : NULL;
249 g_strfreev(change_parts);
257 const gboolean is_valid =
258 g_utf8_validate((
char *)
o, -1, NULL)
259 && g_utf8_validate((
char *)
p, -1, NULL);
261 if(is_valid && strncmp((
char*)
o, (
char*)
p, field->
Array.
count))
262 return g_strdup_printf(
"%s\t\"%s\"\t\u2192\t\"%s\"",
d, (
char*)
o, (
char*)
p);
266 const int max_elements = 4;
267 gchar **change_parts = g_malloc0_n(max_elements + 1,
sizeof(
char*));
276 if(element_text && ++num_parts <= max_elements)
277 change_parts[num_parts - 1] = element_text;
282 gchar *array_text = NULL;
283 if(num_parts > max_elements)
284 array_text = g_strdup_printf(
"%s\t%d changes",
d, num_parts);
285 else if(num_parts > 0)
286 array_text = g_strjoinv(
"\n", change_parts);
288 g_strfreev(change_parts);
294 if(*(
float*)
o != *(
float*)
p && (isfinite(*(
float*)
o) || isfinite(*(
float*)
p)))
295 return g_strdup_printf(
"%s\t%.4f\t\u2192\t%.4f",
d, *(
float*)
o, *(
float*)
p);
298 if(*(
int*)
o != *(
int*)
p)
299 return g_strdup_printf(
"%s\t%d\t\u2192\t%d",
d, *(
int*)
o, *(
int*)
p);
302 if(*(
unsigned int*)
o != *(
unsigned int*)
p)
303 return g_strdup_printf(
"%s\t%u\t\u2192\t%u",
d, *(
unsigned int*)
o, *(
unsigned int*)
p);
306 if(*(
unsigned short int*)
o != *(
unsigned short int*)
p)
307 return g_strdup_printf(
"%s\t%hu\t\u2192\t%hu",
d, *(
unsigned short int*)
o, *(
unsigned short int*)
p);
310 if(*(uint8_t*)
o != *(uint8_t*)
p)
311 return g_strdup_printf(
"%s\t%d\t\u2192\t%d",
d, *(uint8_t*)
o, *(uint8_t*)
p);
314 if(*(
char*)
o != *(
char*)
p)
315 return g_strdup_printf(
"%s\t'%c'\t\u2192\t'%c'",
d, *(
char *)
o, *(
char *)
p);
318 if(*(
float complex*)
o != *(
float complex*)
p)
319 return g_strdup_printf(
"%s\t%.4f + %.4fi\t\u2192\t%.4f + %.4fi",
d,
320 creal(*(
float complex*)
o), cimag(*(
float complex*)
o),
321 creal(*(
float complex*)
p), cimag(*(
float complex*)
p));
324 if(*(
int*)
o != *(
int*)
p)
326 const char *old_str = N_(
"unknown"), *new_str = N_(
"unknown");
329 if(
i->value == *(
int*)
o)
331 old_str =
i->description;
332 if(!*old_str) old_str =
i->name;
334 if(
i->value == *(
int*)
p)
336 new_str =
i->description;
337 if(!*new_str) new_str =
i->name;
341 return g_strdup_printf(
"%s\t%s\t\u2192\t%s",
d, _(old_str), _(new_str));
345 if(*(gboolean*)
o != *(gboolean*)
p)
347 char *old_str = *(gboolean*)
o ?
"on" :
"off";
348 char *new_str = *(gboolean*)
p ?
"on" :
"off";
349 return g_strdup_printf(
"%s\t%s\t\u2192\t%s",
d, _(old_str), _(new_str));
358 fprintf(stderr,
"unsupported introspection type \"%s\" encountered in _lib_history_change_text (field %s)\n", field->
header.
type_name, field->
header.
field_name);
370 find_old = g_list_previous(find_old))
373 if(hprev == hitem)
continue;
374 if(hprev->module == hitem->module)
return hprev;
381#define add_blend_history_change(field, format, label) \
382 if((hitem->blend_params->field) != (old_blend->field)) \
384 gchar *full_format = g_strconcat("%s\t", format, "\t\u2192\t", format, NULL); \
385 change_parts[num_parts++] \
386 = g_strdup_printf(full_format, label, (old_blend->field), (hitem->blend_params->field)); \
387 dt_free(full_format); \
388 full_format = NULL; \
391#define add_blend_history_change_enum(field, label, list) \
392 if((hitem->blend_params->field) != (old_blend->field)) \
394 const char *old_str = NULL, *new_str = NULL; \
395 for(const dt_develop_name_value_t *i = list; *i->name; i++) \
397 if(i->value == (old_blend->field)) old_str = i->name; \
398 if(i->value == (hitem->blend_params->field)) new_str = i->name; \
401 change_parts[num_parts++] \
402 = (!old_str || !new_str) \
403 ? g_strdup_printf("%s\t%d\t\u2192\t%d", label, old_blend->field, hitem->blend_params->field) \
404 : g_strdup_printf("%s\t%s\t\u2192\t%s", label, _(g_dpgettext2(NULL, "blendmode", old_str)), \
405 _(g_dpgettext2(NULL, "blendmode", new_str))); \
408#define add_history_change(field, format, label) \
409 if((hitem->field) != (hprev->field)) \
411 gchar *full_format = g_strconcat("%s\t", format, "\t\u2192\t", format, NULL); \
412 change_parts[num_parts++] = g_strdup_printf(full_format, label, (hprev->field), (hitem->field)); \
413 dt_free(full_format); \
414 full_format = NULL; \
417#define add_history_change_string(field, label) \
418 if(strcmp(hitem->field, hprev->field)) \
420 change_parts[num_parts++] \
421 = g_strdup_printf("%s\t\"%s\"\t\u2192\t\"%s\"", label, (hprev->field), (hitem->field)); \
424#define add_history_change_boolean(field, label) \
425 if((hitem->field) != (hprev->field)) \
427 change_parts[num_parts++] = g_strdup_printf("%s\t%s\t\u2192\t%s", label, (hprev->field) ? _("on") : _("off"), \
428 (hitem->field) ? _("on") : _("off")); \
434 if(
IS_NULL_PTR(hitem) || !hitem->module)
return NULL;
438 = (hprev == hitem ||
IS_NULL_PTR(hprev)) ? hitem->module->default_params : hprev->module->
params;
440 = (hprev == hitem ||
IS_NULL_PTR(hprev)) ? hitem->module->default_blendop_params : hprev->module->
blend_params;
445 const gboolean enabled_by_default = (hitem->module->force_enable && hitem->module->force_enable(hitem->module, hitem->
enabled))
446 || hitem->module->default_enabled;
451 if(enabled_by_default)
452 change_parts[num_parts++] = g_strdup_printf(_(
"mandatory module created automatically"));
454 change_parts[num_parts++] = g_strdup_printf(_(
"module created per user request"));
466 if(hitem->module->have_introspection)
469 hitem->
params, old_params);
470 if(!
IS_NULL_PTR(introspection_change)) change_parts[num_parts++] = introspection_change;
494 change_parts[num_parts++] = old_blend->
mask_id == 0
495 ? g_strdup_printf(_(
"a drawn mask was added"))
497 ? g_strdup_printf(_(
"the drawn mask was removed"))
498 : g_strdup_printf(_(
"the drawn mask was changed"));
502 for(
int in_out = 1; in_out >= 0; in_out--)
504 gboolean first =
TRUE;
512 const int oactive = old_blend->
blendif & (1 <<
ch);
515 const int opolarity = old_blend->
blendif & (1 << (
ch + 16));
524 if((oactive || nactive) && (memcmp(of, nf,
sizeof(
float) * 4) || opolarity != npolarity))
528 change_parts[num_parts++] = g_strdup(in_out ? _(
"parametric output mask:") : _(
"parametric input mask:"));
532 for(
int k = 0;
k < 4;
k++)
534 b->scale_print(of[
k], oboost, s[
k][0],
sizeof(s[
k][0]));
535 b->scale_print(nf[
k], nboost, s[
k][1],
sizeof(s[
k][1]));
538 char *opol = !oactive ?
"" : (opolarity ?
"(-)" :
"(+)");
539 char *npol = !nactive ?
"" : (npolarity ?
"(-)" :
"(+)");
541 change_parts[num_parts++] = g_strdup_printf(
"%s\t%s| %s- %s| %s%s\t\u2192\t%s| %s- %s| %s%s", _(b->name),
542 s[0][0], s[1][0], s[2][0], s[3][0], opol,
543 s[0][1], s[1][1], s[2][1], s[3][1], npol);
549 gchar *tooltip_text = g_strjoinv(
"\n", change_parts);
550 g_strfreev(change_parts);
558 const gchar *tooltip_text = g_object_get_data(G_OBJECT(widget),
"tooltip-text");
561 gtk_tooltip_set_text(
tooltip, tooltip_text);
567 GtkTooltip *
tooltip, gpointer user_data)
571 GtkTreeModel *
model = GTK_TREE_MODEL(
d->history_store);
573 GtkTreePath *path = NULL;
577 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
578 if(!gtk_tree_selection_get_selected(selection, &
model, &iter))
return FALSE;
582 if(!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
x, y, &path, NULL, NULL, NULL))
return FALSE;
583 if(!gtk_tree_model_get_iter(
model, &iter, path))
585 gtk_tree_path_free(path);
590 gchar *tooltip_text = NULL;
592 g_object_set_data_full(G_OBJECT(widget),
"tooltip-text", tooltip_text, g_free);
595 if(path) gtk_tree_path_free(path);
600 GtkTreeModel *
model, GtkTreeIter *iter, gpointer data)
605 g_object_set(G_OBJECT(renderer),
"foreground-set",
FALSE, NULL);
607 g_object_set(G_OBJECT(renderer),
"foreground-set",
TRUE,
"foreground",
"#888", NULL);
641 if(history_end <= 0)
return;
658 gtk_list_store_append(
d->history_store, &iter);
667 const gchar *hint = _(
"Shift+click: show module without changing history");
670 if(tooltip_text && tooltip_text[0])
672 gchar *tooltip_with_hint = g_strconcat(tooltip_text,
"\n\n", hint, NULL);
674 return tooltip_with_hint;
678 return g_strdup(hint);
688 label = g_strdup(hitem->
op_name);
693 g_snprintf(number,
sizeof(number),
"%2d", history_end);
698 gtk_list_store_insert(
d->history_store, &iter, 0);
703 tooltip_text ? tooltip_text :
"", -1);
714 const gboolean enabled_by_default
715 = ((hitem->module->force_enable && hitem->module->force_enable(hitem->module, hitem->
enabled))
716 || hitem->module->default_enabled);
722 label = g_strdup_printf(
"%s%s", clean_name, star);
724 label = g_strdup_printf(
"%s %s%s", clean_name, hitem->
multi_name, star);
728 g_snprintf(number,
sizeof(number),
"%2d", history_end);
733 gtk_list_store_insert(
d->history_store, &iter, 0);
745 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->history_view));
746 GtkTreeModel *
model = GTK_TREE_MODEL(
d->history_store);
749 for(gboolean valid = gtk_tree_model_get_iter_first(
model, &iter); valid; valid = gtk_tree_model_iter_next(
model, &iter))
751 int row_history_end = 0;
753 if(row_history_end == history_end)
755 gtk_tree_selection_select_iter(selection, &iter);
766 d->selection_reset =
TRUE;
767 gtk_list_store_clear(
d->history_store);
777 for(
const GList *history =
dt_dev_get_global()->history; history; history = g_list_next(history), history_pos++)
784 d->selection_reset =
FALSE;
793 GtkTreeModel *
model = NULL;
795 if(!gtk_tree_selection_get_selected(selection, &
model, &iter))
return;
809 GtkTreePath *path = NULL;
810 if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), (gint)e->x, (gint)e->y, &path, NULL, NULL, NULL))
814 GtkTreeModel *
model = GTK_TREE_MODEL(
d->history_store);
816 if(gtk_tree_model_get_iter(
model, &iter, path))
822 gtk_tree_path_free(path);
Handle default and user-set shortcuts (accelerators)
const char ** description(struct dt_iop_module_t *self)
const dt_develop_name_value_t dt_develop_invert_mask_names[]
const dt_develop_name_value_t dt_develop_mask_mode_names[]
const dt_develop_name_value_t dt_develop_blend_colorspace_names[]
const dt_develop_name_value_t dt_develop_blend_mode_flag_names[]
const dt_develop_name_value_t dt_develop_combine_masks_names[]
const dt_develop_name_value_t dt_develop_blend_mode_names[]
const dt_develop_name_value_t dt_develop_feathering_guide_names[]
@ DEVELOP_COMBINE_MASKS_POS
dt_develop_blendif_channels_t
@ DEVELOP_BLEND_MODE_MASK
The blending panel's GUI state and API, cut out of develop/blend.h.
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
struct dt_develop_t * dt_dev_get_global(void)
struct dt_gui_gtk_t * dt_gui_get_global(void)
void dt_dev_pop_history_items_ext(dt_develop_t *dev) REQUIRES_SHARED(dev -> history_mutex)
Apply history items to module params up to dev->history_end.
void dt_dev_write_history(dt_develop_t *dev, gboolean async)
Thread-safe wrapper around dt_dev_write_history_ext() for dev->image_storage.id.
void dt_dev_history_pixelpipe_update(dt_develop_t *dev, gboolean rebuild)
Rebuild or resync pixelpipes after backend history changes.
void dt_dev_set_history_end_ext(struct dt_develop_t *dev, const uint32_t index)
Set the history end index (GUI perspective).
void dt_dev_history_gui_update(struct dt_develop_t *dev)
Apply history-loaded params to module GUIs.
int32_t dt_dev_get_history_end_ext(struct dt_develop_t *dev)
Get the current history end index (GUI perspective).
int dt_dev_get_thumbnail_size(dt_develop_t *dev)
void dt_dev_undo_start_record(dt_develop_t *dev)
void dt_dev_undo_end_record(dt_develop_t *dev)
gboolean enabled
–doc was passed on the command line
static int dt_pthread_rwlock_wrlock(dt_pthread_rwlock_t *rwlock) ACQUIRE(rwlock) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_rwlock_unlock(dt_pthread_rwlock_t *rwlock) RELEASE_GENERIC(rwlock) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_rwlock_rdlock(dt_pthread_rwlock_t *rwlock) ACQUIRE_SHARED(rwlock) NO_THREAD_SAFETY_ANALYSIS
gboolean delete_history_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
void dt_iop_request_focus(dt_iop_module_t *module)
Move darkroom focus to module, or clear it with NULL.
@ IOP_FLAGS_SUPPORTS_BLENDING
void dt_iop_gui_set_expanded(dt_iop_module_t *module, gboolean expanded, gboolean collapse_others)
@ DT_INTROSPECTION_TYPE_BOOL
@ DT_INTROSPECTION_TYPE_ENUM
@ DT_INTROSPECTION_TYPE_OPAQUE
@ DT_INTROSPECTION_TYPE_ARRAY
@ DT_INTROSPECTION_TYPE_CHAR
@ DT_INTROSPECTION_TYPE_FLOAT
@ DT_INTROSPECTION_TYPE_UNION
@ DT_INTROSPECTION_TYPE_UINT
@ DT_INTROSPECTION_TYPE_USHORT
@ DT_INTROSPECTION_TYPE_INT8
@ DT_INTROSPECTION_TYPE_STRUCT
@ DT_INTROSPECTION_TYPE_FLOATCOMPLEX
@ DT_INTROSPECTION_TYPE_INT
gchar * delete_underscore(const char *s)
static const dt_iop_drawlayer_params_t * params
void gui_reset(dt_lib_module_t *self)
#define add_blend_history_change_enum(field, label, list)
#define add_history_change_boolean(field, label)
static const char * _history_icon_name(const gboolean enabled, const gboolean default_enabled, const gboolean always_on, const gboolean deprecated)
static gboolean _lib_history_view_query_tooltip(GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, gpointer user_data)
static void _lib_history_change_callback(gpointer instance, gpointer user_data)
#define add_history_change(field, format, label)
static gboolean _changes_tooltip_callback(GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip)
static gchar * _lib_history_change_text(dt_introspection_field_t *field, const char *d, gpointer params, gpointer oldpar)
void gui_cleanup(dt_lib_module_t *self)
static void _history_show_module_for_end(const int history_end)
static void _history_store_add_original(dt_lib_history_t *d)
@ DT_HISTORY_VIEW_COL_HISTORY_END
@ DT_HISTORY_VIEW_COL_TOOLTIP
@ DT_HISTORY_VIEW_COL_COUNT
@ DT_HISTORY_VIEW_COL_LABEL
@ DT_HISTORY_VIEW_COL_ICON_NAME
@ DT_HISTORY_VIEW_COL_ENABLED
@ DT_HISTORY_VIEW_COL_NUMBER
static void _history_select_row_for_end(dt_lib_history_t *d, const int history_end)
uint32_t container(dt_lib_module_t *self)
static void _lib_history_view_cell_set_foreground(GtkTreeViewColumn *column, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
static gchar * _create_tooltip_text(const dt_dev_history_item_t *hitem)
void gui_init(dt_lib_module_t *self)
const char ** views(dt_lib_module_t *self)
static void _history_apply_history_end(const int history_end)
static void _history_store_prepend_item(dt_lib_history_t *d, const dt_dev_history_item_t *hitem, const int history_end)
#define add_blend_history_change(field, format, label)
#define add_history_change_string(field, label)
static const dt_dev_history_item_t * _find_previous_history_step(const dt_dev_history_item_t *hitem)
static gchar * _history_tooltip_with_hint(const dt_dev_history_item_t *hitem)
static void _lib_history_view_selection_changed(GtkTreeSelection *selection, gpointer user_data)
static gboolean _lib_history_view_button_press_callback(GtkWidget *widget, GdkEventButton *e, gpointer user_data)
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#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,...
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
struct dt_control_signal_t * dt_control_signal_get_global(void)
@ DT_SIGNAL_DEVELOP_HISTORY_CHANGE
This signal is raised when develop history is changed no param, no returned value.
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
struct dt_develop_blend_params_t * blend_params
struct dt_iop_module_t *gboolean enabled
float blendif_parameters[4 *DEVELOP_BLENDIF_SIZE]
float blendif_boost_factors[DEVELOP_BLENDIF_SIZE]
dt_pthread_rwlock_t history_mutex
union dt_introspection_field_t * field
dt_introspection_type_t type
dt_introspection_type_enum_tuple_t * values
union dt_introspection_field_t ** fields
const dt_iop_gui_blendif_channel_t * channel
GtkListStore * history_store
dt_introspection_type_header_t header
dt_introspection_type_array_t Array
dt_introspection_type_enum_t Enum
dt_introspection_type_struct_t Struct
@ DT_UI_CONTAINER_PANEL_LEFT_CENTER