65#ifdef GDK_WINDOWING_QUARTZ
68#include <gdk/gdkkeysyms.h>
71#include <libxml/parser.h>
87 return _(
"apply styles");
93 static const char *
v[] = {
"special", NULL};
117 GtkTreeIter parent = *iter;
123 if(!gtk_tree_model_get_iter_first(
model, iter))
125 gtk_tree_store_append(GTK_TREE_STORE(
model), iter, NULL);
132 if(!gtk_tree_model_iter_children(GTK_TREE_MODEL(
model), iter, &parent))
134 gtk_tree_store_append(GTK_TREE_STORE(
model), iter, &parent);
144 const gboolean match = !g_strcmp0(
name, parent_name);
151 while(gtk_tree_model_iter_next(
model, iter));
154 gtk_tree_store_append(GTK_TREE_STORE(
model), iter, root?NULL:&parent);
163 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->tree));
165 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->tree), NULL);
166 gtk_tree_store_clear(GTK_TREE_STORE(
model));
171 for(
const GList *res_iter = result; res_iter; res_iter = g_list_next(res_iter))
180 gchar *escaped_description = g_markup_escape_text(style->
description, -1);
181 tooltip = g_strconcat(
"<b>", escaped_description,
"</b>\n", items_string, NULL);
186 tooltip = g_strdup(items_string);
189 gchar **split = g_strsplit(style->
name,
"|", 0);
194 const gchar *s = split[
k];
206 gtk_tree_store_set(GTK_TREE_STORE(
model), &iter,
222 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->tree),
model);
223 g_object_unref(
model);
234 model = gtk_tree_view_get_model(
d->tree);
236 if(!gtk_tree_model_get_iter(
model, &iter, path))
return;
256 GList *style_names = NULL;
257 for (
const GList *style = selected_styles; style; style = g_list_next(style))
260 gtk_tree_model_get_iter(
model, &iter, (GtkTreePath *)style->data);
262 if(G_VALUE_HOLDS_STRING(&
value))
263 style_names = g_list_prepend(style_names, g_strdup(g_value_get_string(&
value)));
264 g_value_unset(&
value);
266 return g_list_reverse(style_names);
272 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->tree));
274 if(gtk_tree_selection_count_selected_rows(selection) == 0)
return;
276 GtkTreeModel *
model= gtk_tree_view_get_model(
d->tree);
277 GList *selected_styles = gtk_tree_selection_get_selected_rows(selection, &
model);
279 g_list_free_full(selected_styles, (GDestroyNotify) gtk_tree_path_free);
280 selected_styles = NULL;
308 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->tree));
310 if(gtk_tree_selection_count_selected_rows(selection) == 0)
return;
313 GtkTreeModel *
model= gtk_tree_view_get_model(
d->tree);
315 GList *styles = gtk_tree_selection_get_selected_rows(selection, &
model);
316 for (
const GList *style = styles; style; style = g_list_next(style))
320 gtk_tree_model_get_iter(
model, &iter, (GtkTreePath *)style->data);
322 if(G_VALUE_HOLDS_STRING(&
value))
323 name = g_strdup(g_value_get_string(&
value));
324 g_value_unset(&
value);
333 g_list_free_full (styles, (GDestroyNotify) gtk_tree_path_free);
338 gint
res = GTK_RESPONSE_YES;
343 GtkWidget *dialog = gtk_message_dialog_new
344 (GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
345 ngettext(
"do you really want to remove %d style?",
"do you really want to remove %d styles?", style_cnt),
347#ifdef GDK_WINDOWING_QUARTZ
351 gtk_window_set_title(GTK_WINDOW(dialog), ngettext(
"remove style?",
"remove styles?", style_cnt));
352 res = gtk_dialog_run(GTK_DIALOG(dialog));
353 gtk_widget_destroy(dialog);
356 return res == GTK_RESPONSE_YES;
363 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->tree));
365 if(gtk_tree_selection_count_selected_rows(selection) == 0)
return;
367 GtkTreeModel *
model= gtk_tree_view_get_model(
d->tree);
368 GList *selected_styles = gtk_tree_selection_get_selected_rows(selection, &
model);
370 g_list_free_full(selected_styles, (GDestroyNotify) gtk_tree_path_free);
371 selected_styles = NULL;
375 const gint select_cnt = g_list_length(style_names);
376 const gboolean single_raise = (select_cnt == 1);
384 for (
const GList *style = style_names; style; style = g_list_next(style))
404 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->tree));
406 if(gtk_tree_selection_count_selected_rows(selection) == 0)
return;
408 GtkTreeModel *
model= gtk_tree_view_get_model(
d->tree);
409 GList *selected_styles = gtk_tree_selection_get_selected_rows(selection, &
model);
411 g_list_free_full(selected_styles, (GDestroyNotify) gtk_tree_path_free);
412 selected_styles = NULL;
417 gint overwrite_check_button = 0;
421 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
422 _(
"select directory"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
423 _(
"_save"), _(
"_cancel"));
426 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filechooser),
FALSE);
428 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
430 char *filedir = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
432 for (
const GList *style = style_names; style; style = g_list_next(style))
437 snprintf(stylename,
sizeof(stylename),
"%s/%s.dtstyle", filedir, (
char*)style->data);
439 if(g_file_test(stylename, G_FILE_TEST_EXISTS) ==
TRUE)
442 if(overwrite_check_button == 1)
449 else if(overwrite == 2)
461 char overwrite_str[256];
463 gint overwrite_dialog_res = GTK_RESPONSE_ACCEPT;
464 gint overwrite_dialog_check_button_res =
TRUE;
468 GtkWidget *dialog_overwrite_export = gtk_dialog_new_with_buttons(_(
"overwrite style?"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
469 _(
"cancel"), GTK_RESPONSE_CANCEL,
470 _(
"skip"), GTK_RESPONSE_NONE,
471 _(
"overwrite"), GTK_RESPONSE_ACCEPT, NULL);
474 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog_overwrite_export));
475 sprintf(overwrite_str, _(
"style `%s' already exists.\ndo you want to overwrite existing style?\n"), (
char*)style->data);
476 GtkWidget *label = gtk_label_new(overwrite_str);
477 GtkWidget *overwrite_dialog_check_button = gtk_check_button_new_with_label(_(
"apply this option to all existing styles"));
479 gtk_container_add(GTK_CONTAINER(content_area), label);
480 gtk_container_add(GTK_CONTAINER(content_area), overwrite_dialog_check_button);
481 gtk_widget_show_all(dialog_overwrite_export);
486 gtk_widget_set_sensitive(GTK_WIDGET(overwrite_dialog_check_button),
FALSE);
487 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_overwrite_export), GTK_RESPONSE_NONE,
FALSE);
490#ifdef GDK_WINDOWING_QUARTZ
494 overwrite_dialog_res = gtk_dialog_run(GTK_DIALOG(dialog_overwrite_export));
495 overwrite_dialog_check_button_res = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(overwrite_dialog_check_button));
496 gtk_widget_destroy(dialog_overwrite_export);
499 if(overwrite_dialog_res == GTK_RESPONSE_ACCEPT)
504 if(overwrite_dialog_check_button_res ==
TRUE)
506 overwrite_check_button = 1;
510 overwrite_check_button = 0;
513 else if(overwrite_dialog_res == GTK_RESPONSE_NONE)
518 if(overwrite_dialog_check_button_res ==
TRUE)
520 overwrite_check_button = 1;
524 overwrite_check_button = 0;
540 dt_control_log(_(
"style %s was successfully exported"), (
char*)style->data);
545 g_object_unref(filechooser);
553 gint overwrite_check_button = 0;
557 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
558 _(
"select style"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_OPEN,
559 _(
"_open"), _(
"_cancel"));
562 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filechooser),
TRUE);
564 GtkFileFilter *filter;
565 filter = GTK_FILE_FILTER(gtk_file_filter_new());
566 gtk_file_filter_add_pattern(filter,
"*.dtstyle");
567 gtk_file_filter_add_pattern(filter,
"*.DTSTYLE");
568 gtk_file_filter_set_name(filter, _(
"Ansel style files"));
569 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter);
571 filter = GTK_FILE_FILTER(gtk_file_filter_new());
572 gtk_file_filter_add_pattern(filter,
"*");
573 gtk_file_filter_set_name(filter, _(
"all files"));
575 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter);
577 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
579 GSList *filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(filechooser));
581 for(
const GSList *filename = filenames; filename; filename = g_slist_next(filename))
585 xmlDoc *document = xmlReadFile((
char*)filename->data, NULL, XML_PARSE_NOBLANKS);
586 xmlNode *root = NULL;
588 root = xmlDocGetRootElement(document);
593 "[styles] file %s is not a style file\n", (
char*)filename->data);
595 xmlFreeDoc(document);
599 for(xmlNode *node = root->children->children; node; node = node->next)
601 if(node->type == XML_ELEMENT_NODE)
603 if(strcmp((
char*)node->name,
"name") == 0)
605 bname = g_strdup((
char*)xmlNodeGetContent(node));
612 xmlFreeDoc(document);
616 "[styles] file %s is malformed style file\n", (
char*)filename->data);
624 if(overwrite_check_button == 1)
632 else if(overwrite == 2)
644 char overwrite_str[256];
646 gint overwrite_dialog_res = GTK_RESPONSE_ACCEPT;
647 gint overwrite_dialog_check_button_res =
TRUE;
652 GtkWidget *dialog_overwrite_import = gtk_dialog_new_with_buttons(_(
"overwrite style?"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
653 _(
"cancel"), GTK_RESPONSE_CANCEL,
654 _(
"skip"), GTK_RESPONSE_NONE,
655 _(
"overwrite"), GTK_RESPONSE_ACCEPT, NULL);
658 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog_overwrite_import));
659 sprintf(overwrite_str, _(
"style `%s' already exists.\ndo you want to overwrite existing style?\n"), (
char*)filename->data);
660 GtkWidget *label = gtk_label_new(overwrite_str);
661 GtkWidget *overwrite_dialog_check_button = gtk_check_button_new_with_label(_(
"apply this option to all existing styles"));
663 gtk_container_add(GTK_CONTAINER(content_area), label);
664 gtk_container_add(GTK_CONTAINER(content_area), overwrite_dialog_check_button);
665 gtk_widget_show_all(dialog_overwrite_import);
668 if(g_slist_length(filenames) == 1)
670 gtk_widget_set_sensitive(GTK_WIDGET(overwrite_dialog_check_button),
FALSE);
671 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_overwrite_import), GTK_RESPONSE_NONE,
FALSE);
674#ifdef GDK_WINDOWING_QUARTZ
678 overwrite_dialog_res = gtk_dialog_run(GTK_DIALOG(dialog_overwrite_import));
679 overwrite_dialog_check_button_res = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(overwrite_dialog_check_button));
680 gtk_widget_destroy(dialog_overwrite_import);
683 if(overwrite_dialog_res == GTK_RESPONSE_ACCEPT)
688 if(overwrite_dialog_check_button_res ==
TRUE)
690 overwrite_check_button = 1;
694 overwrite_check_button = 0;
697 else if(overwrite_dialog_res == GTK_RESPONSE_NONE)
703 if(overwrite_dialog_check_button_res ==
TRUE)
705 overwrite_check_button = 1;
709 overwrite_check_button = 0;
734 g_object_unref(filechooser);
746 const gchar *
name = gtk_entry_get_text(
d->entry);
762 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
d->duplicate)));
773 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->tree));
774 const gint sel_styles_cnt = gtk_tree_selection_count_selected_rows(selection);
776 gtk_widget_set_sensitive(GTK_WIDGET(
d->create_button), has_act_on);
777 gtk_widget_set_sensitive(GTK_WIDGET(
d->edit_button), sel_styles_cnt > 0);
778 gtk_widget_set_sensitive(GTK_WIDGET(
d->delete_button), sel_styles_cnt > 0);
781 gtk_widget_set_sensitive(GTK_WIDGET(
d->export_button), sel_styles_cnt > 0);
783 gtk_widget_set_sensitive(GTK_WIDGET(
d->apply_button), has_act_on && sel_styles_cnt > 0);
819 self->
data = (
void *)
d;
821 d->edit_button = NULL;
826 d->tree = GTK_TREE_VIEW(gtk_tree_view_new());
827 gtk_tree_view_set_headers_visible(
d->tree,
FALSE);
828 GtkTreeStore *treestore = gtk_tree_store_new(
DT_STYLES_NUM_COLS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
829 GtkTreeViewColumn *col = gtk_tree_view_column_new();
830 gtk_tree_view_append_column(GTK_TREE_VIEW(
d->tree), col);
831 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
832 g_object_set(renderer,
"ellipsize", PANGO_ELLIPSIZE_MIDDLE, (gchar *)0);
833 gtk_tree_view_column_pack_start(col, renderer,
TRUE);
836 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->tree)), GTK_SELECTION_MULTIPLE);
837 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->tree), GTK_TREE_MODEL(treestore));
838 g_object_unref(treestore);
840 gtk_widget_set_tooltip_text(GTK_WIDGET(
d->tree), _(
"available styles,\ndoubleclick to apply"));
842 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->tree)),
"changed", G_CALLBACK(
_tree_selection_changed), self);
846 d->entry = GTK_ENTRY(w);
847 gtk_entry_set_placeholder_text(GTK_ENTRY(
d->entry), _(
"filter style names"));
848 gtk_widget_set_tooltip_text(w, _(
"filter style names"));
849 gtk_entry_set_width_chars(GTK_ENTRY(w), 0);
854 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(
d->entry),
TRUE,
TRUE, 0);
859 d->duplicate = gtk_check_button_new_with_label(_(
"create duplicate"));
860 gtk_label_set_ellipsize(GTK_LABEL(gtk_bin_get_child(GTK_BIN(
d->duplicate))), PANGO_ELLIPSIZE_START);
861 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(
d->duplicate),
TRUE,
FALSE, 0);
863 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->duplicate),
865 gtk_widget_set_tooltip_text(
d->duplicate, _(
"creates a duplicate of the image before applying style"));
870 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(hbox1),
TRUE,
FALSE, 0);
871 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(hbox2),
TRUE,
FALSE, 0);
872 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(hbox3),
TRUE,
FALSE, 0);
876 gtk_box_pack_start(GTK_BOX(hbox1),
d->create_button,
TRUE,
TRUE, 0);
880 gtk_box_pack_start(GTK_BOX(hbox1),
d->edit_button,
TRUE,
TRUE, 0);
884 gtk_box_pack_start(GTK_BOX(hbox1),
d->delete_button,
TRUE,
TRUE, 0);
888 gtk_box_pack_start(GTK_BOX(hbox2),
d->import_button,
TRUE,
TRUE, 0);
892 gtk_box_pack_start(GTK_BOX(hbox2),
d->export_button,
TRUE,
TRUE, 0);
896 gtk_box_pack_start(GTK_BOX(hbox3),
d->apply_button,
TRUE,
TRUE, 0);
899 GtkEntryCompletion *completion = gtk_entry_completion_new();
900 gtk_entry_completion_set_model(completion, gtk_tree_view_get_model(GTK_TREE_VIEW(
d->tree)));
901 gtk_entry_completion_set_text_column(completion, 0);
902 gtk_entry_completion_set_inline_completion(completion,
TRUE);
903 gtk_entry_set_completion(
d->entry, completion);
945 const gint styles_cnt = g_list_length(all_styles);
950 for (
const GList *result = all_styles; result; result = g_list_next(result))
int dt_act_on_get_images_nb(const gboolean only_visible, const gboolean force)
GList * dt_act_on_get_images()
GtkWidget * dt_gui_main_window(void)
dt_collection_properties_t
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
void dt_conf_set_bool(const char *name, int val)
int dt_conf_get_bool(const char *name)
void dt_conf_set_folder_from_file_chooser(const char *name, GtkFileChooser *chooser)
gboolean dt_conf_get_folder_to_file_chooser(const char *name, GtkFileChooser *chooser)
void dt_control_log(const char *msg,...)
#define dt_database_start_transaction()
#define dt_database_release_transaction()
GtkWidget * view
the tree view
#define g_list_is_singleton(list)
void dt_gui_styles_dialog_edit(const char *name)
gboolean dt_history_style_on_list(const GList *list, const char *name, const gboolean duplicate)
void dt_lib_cancel_postponed_update(dt_lib_module_t *mod)
GtkWidget * dt_action_button_new(dt_lib_module_t *self, const gchar *label, gpointer callback, gpointer data, const gchar *tooltip, guint accel_key, GdkModifierType mods)
void dt_lib_queue_postponed_update(dt_lib_module_t *mod, void(*update_fn)(dt_lib_module_t *self))
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict const size_t k
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
#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,...
void dt_osx_disallow_fullscreen(GtkWidget *widget)
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
struct dt_control_signal_t * dt_control_signal_get_global(void)
@ DT_SIGNAL_STYLE_CHANGED
This signal is raised when a style is added/deleted/changed
@ DT_SIGNAL_MOUSE_OVER_IMAGE_CHANGE
This signal is raised when mouse hovers over image thumbs both on lighttable and in the filmstrip....
@ DT_SIGNAL_SELECTION_CHANGED
This signal is raised when the selection is changed no param, no returned value.
@ DT_SIGNAL_COLLECTION_CHANGED
This signal is raised when collection changed. To avoid leaking the list, dt_collection_t is connecte...
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
static const dt_aligned_pixel_simd_t value
gboolean dt_styles_exists(const char *name)
char * dt_styles_get_item_list_as_string(const char *name)
void dt_multiple_styles_apply_to_list(GList *styles, const GList *list, gboolean duplicate)
void dt_styles_delete_by_name_adv(const char *name, const gboolean raise)
void dt_styles_save_to_file(const char *style_name, const char *filedir, gboolean overwrite)
void dt_style_free(gpointer data)
void dt_styles_delete_by_name(const char *name)
void dt_styles_import_from_file(const char *style_path)
GList * dt_styles_get_list(const char *filter)
gboolean _ask_before_delete_style(const gint style_cnt)
void gui_reset(dt_lib_module_t *self)
static void create_clicked(GtkWidget *w, gpointer user_data)
static void _update(dt_lib_module_t *self)
static void export_clicked(GtkWidget *w, gpointer user_data)
static void _styles_changed_callback(gpointer instance, gpointer user_data)
static gboolean entry_callback(GtkEntry *entry, gpointer user_data)
static void delete_clicked(GtkWidget *w, gpointer user_data)
void gui_cleanup(dt_lib_module_t *self)
static gboolean _get_node_for_name(GtkTreeModel *model, gboolean root, GtkTreeIter *iter, const gchar *parent_name)
GList * _get_selected_style_names(GList *selected_styles, GtkTreeModel *model)
static void import_clicked(GtkWidget *w, gpointer user_data)
static gboolean duplicate_callback(GtkEntry *entry, gpointer user_data)
static void _mouse_over_image_callback(gpointer instance, dt_lib_module_t *self)
static void _gui_styles_update_view(dt_lib_styles_t *d)
static void apply_clicked(GtkWidget *w, gpointer user_data)
static void _collection_updated_callback(gpointer instance, dt_collection_change_t query_change, dt_collection_properties_t changed_property, gpointer imgs, int next, dt_lib_module_t *self)
uint32_t container(dt_lib_module_t *self)
static gboolean entry_activated(GtkEntry *entry, gpointer user_data)
static void edit_clicked(GtkWidget *w, gpointer user_data)
static void _tree_selection_changed(GtkTreeSelection *treeselection, gpointer data)
void gui_init(dt_lib_module_t *self)
const char ** views(dt_lib_module_t *self)
static void _image_selection_changed_callback(gpointer instance, dt_lib_module_t *self)
static void _styles_row_activated_callback(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *col, gpointer user_data)
void dt_styles_create_from_list(const GList *list)
Telling the user something happened.