59#ifdef GDK_WINDOWING_QUARTZ
62#include <gdk/gdkkeysyms.h>
65#include <libxml/parser.h>
80 return _(
"apply styles");
86 static const char *
v[] = {
"special", NULL};
110 GtkTreeIter parent = *iter;
116 if(!gtk_tree_model_get_iter_first(
model, iter))
118 gtk_tree_store_append(GTK_TREE_STORE(
model), iter, NULL);
125 if(!gtk_tree_model_iter_children(GTK_TREE_MODEL(
model), iter, &parent))
127 gtk_tree_store_append(GTK_TREE_STORE(
model), iter, &parent);
137 const gboolean match = !g_strcmp0(
name, parent_name);
144 while(gtk_tree_model_iter_next(
model, iter));
147 gtk_tree_store_append(GTK_TREE_STORE(
model), iter, root?NULL:&parent);
156 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->tree));
158 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->tree), NULL);
159 gtk_tree_store_clear(GTK_TREE_STORE(
model));
164 for(
const GList *res_iter = result; res_iter; res_iter = g_list_next(res_iter))
173 gchar *escaped_description = g_markup_escape_text(style->
description, -1);
174 tooltip = g_strconcat(
"<b>", escaped_description,
"</b>\n", items_string, NULL);
179 tooltip = g_strdup(items_string);
182 gchar **split = g_strsplit(style->
name,
"|", 0);
187 const gchar *s = split[
k];
199 gtk_tree_store_set(GTK_TREE_STORE(
model), &iter,
215 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->tree),
model);
216 g_object_unref(
model);
227 model = gtk_tree_view_get_model(
d->tree);
229 if(!gtk_tree_model_get_iter(
model, &iter, path))
return;
249 GList *style_names = NULL;
250 for (
const GList *style = selected_styles; style; style = g_list_next(style))
253 gtk_tree_model_get_iter(
model, &iter, (GtkTreePath *)style->data);
255 if(G_VALUE_HOLDS_STRING(&
value))
256 style_names = g_list_prepend(style_names, g_strdup(g_value_get_string(&
value)));
257 g_value_unset(&
value);
259 return g_list_reverse(style_names);
265 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->tree));
267 if(gtk_tree_selection_count_selected_rows(selection) == 0)
return;
269 GtkTreeModel *
model= gtk_tree_view_get_model(
d->tree);
270 GList *selected_styles = gtk_tree_selection_get_selected_rows(selection, &
model);
272 g_list_free_full(selected_styles, (GDestroyNotify) gtk_tree_path_free);
273 selected_styles = NULL;
301 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->tree));
303 if(gtk_tree_selection_count_selected_rows(selection) == 0)
return;
306 GtkTreeModel *
model= gtk_tree_view_get_model(
d->tree);
308 GList *styles = gtk_tree_selection_get_selected_rows(selection, &
model);
309 for (
const GList *style = styles; style; style = g_list_next(style))
313 gtk_tree_model_get_iter(
model, &iter, (GtkTreePath *)style->data);
315 if(G_VALUE_HOLDS_STRING(&
value))
316 name = g_strdup(g_value_get_string(&
value));
317 g_value_unset(&
value);
326 g_list_free_full (styles, (GDestroyNotify) gtk_tree_path_free);
331 gint res = GTK_RESPONSE_YES;
336 GtkWidget *dialog = gtk_message_dialog_new
337 (GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
338 ngettext(
"do you really want to remove %d style?",
"do you really want to remove %d styles?", style_cnt),
340#ifdef GDK_WINDOWING_QUARTZ
344 gtk_window_set_title(GTK_WINDOW(dialog), ngettext(
"remove style?",
"remove styles?", style_cnt));
345 res = gtk_dialog_run(GTK_DIALOG(dialog));
346 gtk_widget_destroy(dialog);
349 return res == GTK_RESPONSE_YES;
356 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->tree));
358 if(gtk_tree_selection_count_selected_rows(selection) == 0)
return;
360 GtkTreeModel *
model= gtk_tree_view_get_model(
d->tree);
361 GList *selected_styles = gtk_tree_selection_get_selected_rows(selection, &
model);
363 g_list_free_full(selected_styles, (GDestroyNotify) gtk_tree_path_free);
364 selected_styles = NULL;
368 const gint select_cnt = g_list_length(style_names);
369 const gboolean single_raise = (select_cnt == 1);
377 for (
const GList *style = style_names; style; style = g_list_next(style))
397 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->tree));
399 if(gtk_tree_selection_count_selected_rows(selection) == 0)
return;
401 GtkTreeModel *
model= gtk_tree_view_get_model(
d->tree);
402 GList *selected_styles = gtk_tree_selection_get_selected_rows(selection, &
model);
404 g_list_free_full(selected_styles, (GDestroyNotify) gtk_tree_path_free);
405 selected_styles = NULL;
410 gint overwrite_check_button = 0;
414 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
415 _(
"select directory"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
416 _(
"_save"), _(
"_cancel"));
419 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filechooser),
FALSE);
421 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
423 char *filedir = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
425 for (
const GList *style = style_names; style; style = g_list_next(style))
430 snprintf(stylename,
sizeof(stylename),
"%s/%s.dtstyle", filedir, (
char*)style->data);
432 if(g_file_test(stylename, G_FILE_TEST_EXISTS) ==
TRUE)
435 if(overwrite_check_button == 1)
442 else if(overwrite == 2)
454 char overwrite_str[256];
456 gint overwrite_dialog_res = GTK_RESPONSE_ACCEPT;
457 gint overwrite_dialog_check_button_res =
TRUE;
461 GtkWidget *dialog_overwrite_export = gtk_dialog_new_with_buttons(_(
"overwrite style?"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
462 _(
"cancel"), GTK_RESPONSE_CANCEL,
463 _(
"skip"), GTK_RESPONSE_NONE,
464 _(
"overwrite"), GTK_RESPONSE_ACCEPT, NULL);
467 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog_overwrite_export));
468 sprintf(overwrite_str, _(
"style `%s' already exists.\ndo you want to overwrite existing style?\n"), (
char*)style->data);
469 GtkWidget *label = gtk_label_new(overwrite_str);
470 GtkWidget *overwrite_dialog_check_button = gtk_check_button_new_with_label(_(
"apply this option to all existing styles"));
472 gtk_container_add(GTK_CONTAINER(content_area), label);
473 gtk_container_add(GTK_CONTAINER(content_area), overwrite_dialog_check_button);
474 gtk_widget_show_all(dialog_overwrite_export);
479 gtk_widget_set_sensitive(GTK_WIDGET(overwrite_dialog_check_button),
FALSE);
480 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_overwrite_export), GTK_RESPONSE_NONE,
FALSE);
483#ifdef GDK_WINDOWING_QUARTZ
487 overwrite_dialog_res = gtk_dialog_run(GTK_DIALOG(dialog_overwrite_export));
488 overwrite_dialog_check_button_res = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(overwrite_dialog_check_button));
489 gtk_widget_destroy(dialog_overwrite_export);
492 if(overwrite_dialog_res == GTK_RESPONSE_ACCEPT)
497 if(overwrite_dialog_check_button_res ==
TRUE)
499 overwrite_check_button = 1;
503 overwrite_check_button = 0;
506 else if(overwrite_dialog_res == GTK_RESPONSE_NONE)
511 if(overwrite_dialog_check_button_res ==
TRUE)
513 overwrite_check_button = 1;
517 overwrite_check_button = 0;
533 dt_control_log(_(
"style %s was successfully exported"), (
char*)style->data);
538 g_object_unref(filechooser);
546 gint overwrite_check_button = 0;
550 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
551 _(
"select style"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_OPEN,
552 _(
"_open"), _(
"_cancel"));
555 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filechooser),
TRUE);
557 GtkFileFilter *filter;
558 filter = GTK_FILE_FILTER(gtk_file_filter_new());
559 gtk_file_filter_add_pattern(filter,
"*.dtstyle");
560 gtk_file_filter_add_pattern(filter,
"*.DTSTYLE");
561 gtk_file_filter_set_name(filter, _(
"Ansel style files"));
562 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter);
564 filter = GTK_FILE_FILTER(gtk_file_filter_new());
565 gtk_file_filter_add_pattern(filter,
"*");
566 gtk_file_filter_set_name(filter, _(
"all files"));
568 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter);
570 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
572 GSList *filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(filechooser));
574 for(
const GSList *filename = filenames; filename; filename = g_slist_next(filename))
578 xmlDoc *document = xmlReadFile((
char*)filename->data, NULL, XML_PARSE_NOBLANKS);
579 xmlNode *root = NULL;
581 root = xmlDocGetRootElement(document);
586 "[styles] file %s is not a style file\n", (
char*)filename->data);
588 xmlFreeDoc(document);
592 for(xmlNode *node = root->children->children; node; node = node->next)
594 if(node->type == XML_ELEMENT_NODE)
596 if(strcmp((
char*)node->name,
"name") == 0)
598 bname = g_strdup((
char*)xmlNodeGetContent(node));
605 xmlFreeDoc(document);
609 "[styles] file %s is malformed style file\n", (
char*)filename->data);
617 if(overwrite_check_button == 1)
625 else if(overwrite == 2)
637 char overwrite_str[256];
639 gint overwrite_dialog_res = GTK_RESPONSE_ACCEPT;
640 gint overwrite_dialog_check_button_res =
TRUE;
645 GtkWidget *dialog_overwrite_import = gtk_dialog_new_with_buttons(_(
"overwrite style?"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
646 _(
"cancel"), GTK_RESPONSE_CANCEL,
647 _(
"skip"), GTK_RESPONSE_NONE,
648 _(
"overwrite"), GTK_RESPONSE_ACCEPT, NULL);
651 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog_overwrite_import));
652 sprintf(overwrite_str, _(
"style `%s' already exists.\ndo you want to overwrite existing style?\n"), (
char*)filename->data);
653 GtkWidget *label = gtk_label_new(overwrite_str);
654 GtkWidget *overwrite_dialog_check_button = gtk_check_button_new_with_label(_(
"apply this option to all existing styles"));
656 gtk_container_add(GTK_CONTAINER(content_area), label);
657 gtk_container_add(GTK_CONTAINER(content_area), overwrite_dialog_check_button);
658 gtk_widget_show_all(dialog_overwrite_import);
661 if(g_slist_length(filenames) == 1)
663 gtk_widget_set_sensitive(GTK_WIDGET(overwrite_dialog_check_button),
FALSE);
664 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_overwrite_import), GTK_RESPONSE_NONE,
FALSE);
667#ifdef GDK_WINDOWING_QUARTZ
671 overwrite_dialog_res = gtk_dialog_run(GTK_DIALOG(dialog_overwrite_import));
672 overwrite_dialog_check_button_res = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(overwrite_dialog_check_button));
673 gtk_widget_destroy(dialog_overwrite_import);
676 if(overwrite_dialog_res == GTK_RESPONSE_ACCEPT)
681 if(overwrite_dialog_check_button_res ==
TRUE)
683 overwrite_check_button = 1;
687 overwrite_check_button = 0;
690 else if(overwrite_dialog_res == GTK_RESPONSE_NONE)
696 if(overwrite_dialog_check_button_res ==
TRUE)
698 overwrite_check_button = 1;
702 overwrite_check_button = 0;
727 g_object_unref(filechooser);
739 const gchar *
name = gtk_entry_get_text(
d->entry);
755 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
d->duplicate)));
766 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->tree));
767 const gint sel_styles_cnt = gtk_tree_selection_count_selected_rows(selection);
769 gtk_widget_set_sensitive(GTK_WIDGET(
d->create_button), has_act_on);
770 gtk_widget_set_sensitive(GTK_WIDGET(
d->edit_button), sel_styles_cnt > 0);
771 gtk_widget_set_sensitive(GTK_WIDGET(
d->delete_button), sel_styles_cnt > 0);
774 gtk_widget_set_sensitive(GTK_WIDGET(
d->export_button), sel_styles_cnt > 0);
776 gtk_widget_set_sensitive(GTK_WIDGET(
d->apply_button), has_act_on && sel_styles_cnt > 0);
812 self->
data = (
void *)
d;
814 d->edit_button = NULL;
819 d->tree = GTK_TREE_VIEW(gtk_tree_view_new());
820 gtk_tree_view_set_headers_visible(
d->tree,
FALSE);
821 GtkTreeStore *treestore = gtk_tree_store_new(
DT_STYLES_NUM_COLS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
822 GtkTreeViewColumn *col = gtk_tree_view_column_new();
823 gtk_tree_view_append_column(GTK_TREE_VIEW(
d->tree), col);
824 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
825 g_object_set(renderer,
"ellipsize", PANGO_ELLIPSIZE_MIDDLE, (gchar *)0);
826 gtk_tree_view_column_pack_start(col, renderer,
TRUE);
829 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->tree)), GTK_SELECTION_MULTIPLE);
830 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->tree), GTK_TREE_MODEL(treestore));
831 g_object_unref(treestore);
833 gtk_widget_set_tooltip_text(GTK_WIDGET(
d->tree), _(
"available styles,\ndoubleclick to apply"));
835 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->tree)),
"changed", G_CALLBACK(
_tree_selection_changed), self);
839 d->entry = GTK_ENTRY(w);
840 gtk_entry_set_placeholder_text(GTK_ENTRY(
d->entry), _(
"filter style names"));
841 gtk_widget_set_tooltip_text(w, _(
"filter style names"));
842 gtk_entry_set_width_chars(GTK_ENTRY(w), 0);
847 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(
d->entry),
TRUE,
TRUE, 0);
852 d->duplicate = gtk_check_button_new_with_label(_(
"create duplicate"));
853 gtk_label_set_ellipsize(GTK_LABEL(gtk_bin_get_child(GTK_BIN(
d->duplicate))), PANGO_ELLIPSIZE_START);
854 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(
d->duplicate),
TRUE,
FALSE, 0);
856 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->duplicate),
858 gtk_widget_set_tooltip_text(
d->duplicate, _(
"creates a duplicate of the image before applying style"));
863 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(hbox1),
TRUE,
FALSE, 0);
864 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(hbox2),
TRUE,
FALSE, 0);
865 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(hbox3),
TRUE,
FALSE, 0);
869 gtk_box_pack_start(GTK_BOX(hbox1),
d->create_button,
TRUE,
TRUE, 0);
873 gtk_box_pack_start(GTK_BOX(hbox1),
d->edit_button,
TRUE,
TRUE, 0);
877 gtk_box_pack_start(GTK_BOX(hbox1),
d->delete_button,
TRUE,
TRUE, 0);
881 gtk_box_pack_start(GTK_BOX(hbox2),
d->import_button,
TRUE,
TRUE, 0);
885 gtk_box_pack_start(GTK_BOX(hbox2),
d->export_button,
TRUE,
TRUE, 0);
889 gtk_box_pack_start(GTK_BOX(hbox3),
d->apply_button,
TRUE,
TRUE, 0);
892 GtkEntryCompletion *completion = gtk_entry_completion_new();
893 gtk_entry_completion_set_model(completion, gtk_tree_view_get_model(GTK_TREE_VIEW(
d->tree)));
894 gtk_entry_completion_set_text_column(completion, 0);
895 gtk_entry_completion_set_inline_completion(completion,
TRUE);
896 gtk_entry_set_completion(
d->entry, completion);
938 const gint styles_cnt = g_list_length(all_styles);
943 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()
dt_collection_properties_t
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,...)
uint32_t view(const dt_view_t *self)
void dt_print(dt_debug_thread_t thread, const char *msg,...)
#define g_list_is_singleton(list)
#define DT_MODULE(MODVER)
static void dt_free_gpointer(gpointer ptr)
static const dt_aligned_pixel_simd_t value
#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_database_start_transaction(db)
#define dt_database_release_transaction(db)
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.
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
#define DT_GUI_BOX_SPACING
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))
float *const restrict const size_t k
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,...)
@ 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)
struct _GtkWidget GtkWidget
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_create_from_list(const GList *list)
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)
struct dt_gui_gtk_t * gui
const struct dt_database_t * db
struct dt_control_signal_t * signals