154#include <gio/gunixmounts.h>
156#ifdef GDK_WINDOWING_QUARTZ
163#define PARAM_STRING_SIZE 256
310static const char *
const OP_TOKENS[] = {
"",
"<",
"<=",
">",
">=",
"<>" };
311static const char *
const OP_LABELS[] = {
"=",
"<",
"≤",
">",
"≥",
"≠" };
312#define COLLECT_N_OPS ((int)G_N_ELEMENTS(OP_TOKENS))
318 *
value = text ? text :
"";
320 if(g_str_has_prefix(text,
"<="))
325 else if(g_str_has_prefix(text,
">="))
330 else if(g_str_has_prefix(text,
"<>"))
335 else if(g_str_has_prefix(text,
"<"))
340 else if(g_str_has_prefix(text,
">"))
345 else if(g_str_has_prefix(text,
"="))
350 while(**
value ==
' ') (*value)++;
364 static const char *
v[] = {
"lighttable",
"map",
"print", NULL };
379 const int old_version,
int *new_version,
size_t *new_size)
381 if(old_version == 1 || old_version == 2)
394#define CLEAR_PARAMS(r) \
396 memset(¶ms, 0, sizeof(params)); \
398 params.rule[0].mode = 0; \
399 params.rule[0].item = r; \
402 GDateTime *now = g_date_time_new_now_local();
403 char *datetime_today = g_date_time_format(now,
"%Y:%m:%d");
404 GDateTime *gdt = g_date_time_add_days(now, -1);
405 char *datetime_24hrs = g_date_time_format(gdt,
"> %Y:%m:%d %H:%M");
406 g_date_time_unref(gdt);
407 gdt = g_date_time_add_days(now, -30);
408 char *datetime_30d = g_date_time_format(gdt,
"> %Y:%m:%d");
409 g_date_time_unref(gdt);
410 g_date_time_unref(now);
460 snprintf(
k,
sizeof(
k),
"plugins/lighttable/collect/item%1d",
n);
467 snprintf(
k,
sizeof(
k),
"plugins/lighttable/collect/item%1d",
n);
474 snprintf(
k,
sizeof(
k),
"plugins/lighttable/collect/mode%1d",
n);
481 snprintf(
k,
sizeof(
k),
"plugins/lighttable/collect/mode%1d",
n);
488 snprintf(
k,
sizeof(
k),
"plugins/lighttable/collect/string%1d",
n);
495 snprintf(
k,
sizeof(
k),
"plugins/lighttable/collect/string%1d",
n);
504 const char *val = gtk_entry_get_text(GTK_ENTRY(dr->
text));
509 s = g_strconcat(
OP_TOKENS[idx], val, NULL);
526 g_signal_handlers_block_matched(dr->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
527 g_signal_handlers_block_matched(dr->
op_combo, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
_op_changed, NULL);
534 gtk_combo_box_set_active(GTK_COMBO_BOX(dr->
op_combo), idx);
535 gtk_entry_set_text(GTK_ENTRY(dr->
text), val);
539 gtk_entry_set_text(GTK_ENTRY(dr->
text), text);
542 gtk_editable_set_position(GTK_EDITABLE(dr->
text), -1);
545 g_signal_handlers_unblock_matched(dr->
op_combo, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
_op_changed, NULL);
546 g_signal_handlers_unblock_matched(dr->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
575 return d->rule +
d->active_rule;
581 d->active_rule = CLAMP(
d->active_rule, 0,
d->nb_rules - 1);
590 for(
int i = 0;
i <
n;
i++)
605 void *
p = malloc(*
size);
613 for(uint32_t
i = 0;
i <
p->rules;
i++)
657#define ADD_COLLECT_ENTRY(value) \
658 dt_bauhaus_combobox_add_full(w, dt_collection_name(value), DT_BAUHAUS_COMBOBOX_ALIGN_RIGHT, \
659 GUINT_TO_POINTER(value + 1), NULL, TRUE)
670 gchar *setting = g_strdup_printf(
"plugins/lighttable/metadata/%s_flag", name_);
699#undef ADD_COLLECT_ENTRY
709 for(; *list; list++) length++;
719 char **tokens = g_strsplit(path, G_DIR_SEPARATOR_S, -1);
722 if(!(g_ascii_isalpha(tokens[0][0]) && tokens[0][strlen(tokens[0]) - 1] ==
':'))
729 const unsigned int size = g_strv_length(tokens);
730 result = malloc(
sizeof(
char *) *
size);
731 for(
unsigned int i = 0;
i <
size;
i++) result[
i] = tokens[
i + 1];
762 const size_t len = strlen(tag);
763 char *result = g_malloc(len + 2);
764 if(!g_strcmp0(tag, _(
"not tagged")))
766 else if(g_str_has_prefix(tag,
"darktable|"))
770 memcpy(result + 1, tag, len + 1);
771 for(
char *iter = result + 1; *iter; iter++)
772 if(*iter ==
'|') *iter =
'\1';
777 GtkTreeIter *iter, gpointer data)
783 g_object_set(renderer,
"text",
name, NULL);
786 gchar *coltext = g_strdup_printf(
"%s (%d)",
name, count);
787 g_object_set(renderer,
"text", coltext, NULL);
798 gboolean visible =
FALSE;
799 gboolean was_visible;
802 gchar *haystack = g_utf8_strdown(str, -1);
810 gchar *
operator, * number, *number2;
814 const float nb1 = g_strtod(number, NULL);
815 const float nb2 = g_strtod(haystack, NULL);
816 if(
operator&& strcmp(
operator,
">") == 0)
817 visible = (nb2 > nb1);
818 else if(
operator&& strcmp(
operator,
">=") == 0)
819 visible = (nb2 >= nb1);
820 else if(
operator&& strcmp(
operator,
"<") == 0)
821 visible = (nb2 < nb1);
822 else if(
operator&& strcmp(
operator,
"<=") == 0)
823 visible = (nb2 <= nb1);
824 else if(
operator&& strcmp(
operator,
"<>") == 0)
825 visible = (nb1 != nb2);
826 else if(
operator&& number2 && strcmp(
operator,
"[]") == 0)
828 const float nb3 = g_strtod(number2, NULL);
829 visible = (nb2 >= nb1 && nb2 <= nb3);
832 visible = (nb1 == nb2);
841 for(
const GList *l = list; l; l = g_list_next(l))
843 const char *
name = (
char *)l->data;
844 if((visible = (g_strrstr(haystack,
name + (
name[0] ==
'%')) != NULL)))
break;
850 if(needle[0] ==
'%') needle++;
854 visible = (strchr(haystack, needle[0]) != NULL);
856 visible = (g_strrstr(haystack, needle) != NULL);
861 if(visible != was_visible)
871 gboolean cur_state, visible;
878 gchar *haystack = g_utf8_strdown(str, -1),
879 *needle = g_utf8_strdown(gtk_entry_get_text(GTK_ENTRY(dr->
text)), -1);
880 visible = (g_strrstr(haystack, needle) != NULL);
892 GtkTreeIter parent, child = *iter;
895 while(gtk_tree_model_iter_parent(
model, &parent, &child))
917 for(
const char *
p = s;
p && *
p &&
n < 14;
p++)
918 if(g_ascii_isdigit(*
p)) digits[
n++] = *
p;
919 while(
n < 14) digits[
n++] = pad;
921 return g_ascii_strtoull(digits, NULL, 10);
937 const guint64 node_lo =
_date_key(str,
'0');
938 const guint64 node_hi =
_date_key(str,
'9');
940 const gboolean visible = (node_hi >=
r->lo) && (node_lo <= r->hi);
945static gboolean
list_select(GtkTreeModel *
model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
952 gchar *haystack = g_utf8_strdown(str, -1);
953 gchar *needle = g_utf8_strdown(gtk_entry_get_text(GTK_ENTRY(dr->
text)), -1);
954 if(strcmp(haystack, needle) == 0)
956 gtk_tree_selection_select_path(gtk_tree_view_get_selection(
d->view), path);
957 gtk_tree_view_scroll_to_cell(
d->view, path, NULL,
FALSE, 0.2, 0);
965static gboolean
range_select(GtkTreeModel *
model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
971 gchar *haystack = g_utf8_strdown(str, -1);
972 gchar *needle = range->
path1 ? g_utf8_strdown(range->
stop, -1) : g_utf8_strdown(range->
start, -1);
973 if(strcmp(haystack, needle) == 0)
977 range->
path2 = gtk_tree_path_copy(path);
984 range->
path1 = gtk_tree_path_copy(path);
992static gboolean
tree_expand(GtkTreeModel *
model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
996 gchar *str = NULL, *txt = NULL;
997 gboolean startwildcard =
FALSE, expanded =
FALSE;
1000 gchar *haystack = g_utf8_strdown(str, -1);
1001 gchar *needle = g_utf8_strdown(gtk_entry_get_text(GTK_ENTRY(dr->
text)), -1);
1002 gchar *txt2 = g_utf8_strdown(txt, -1);
1009 if(g_str_has_prefix(needle,
"%")) startwildcard =
TRUE;
1010 if(g_str_has_suffix(needle,
"%")) needle[strlen(needle) - 1] =
'\0';
1011 if(g_str_has_suffix(haystack,
"%")) haystack[strlen(haystack) - 1] =
'\0';
1014 if(g_str_has_suffix(needle,
"*")) needle[strlen(needle) - 1] =
'\0';
1015 if(g_str_has_suffix(needle,
"|")) needle[strlen(needle) - 1] =
'\0';
1016 if(g_str_has_suffix(haystack,
"|")) haystack[strlen(haystack) - 1] =
'\0';
1020 if(g_str_has_suffix(needle,
"*")) needle[strlen(needle) - 1] =
'\0';
1021 if(g_str_has_suffix(needle,
"/")) needle[strlen(needle) - 1] =
'\0';
1022 if(g_str_has_suffix(haystack,
"/")) haystack[strlen(haystack) - 1] =
'\0';
1026 if(g_str_has_suffix(needle,
":")) needle[strlen(needle) - 1] =
'\0';
1027 if(g_str_has_suffix(haystack,
":")) haystack[strlen(haystack) - 1] =
'\0';
1030 if(reveal && g_strrstr(txt2, needle) != NULL)
1032 gtk_tree_view_expand_to_path(
d->view, path);
1036 if(strlen(needle) == 0)
1040 else if(strcmp(haystack, needle) == 0)
1042 gtk_tree_view_expand_to_path(
d->view, path);
1043 gtk_tree_selection_select_path(gtk_tree_view_get_selection(
d->view), path);
1044 gtk_tree_view_scroll_to_cell(
d->view, path, NULL,
FALSE, 0.2, 0);
1047 else if(startwildcard && g_strrstr(haystack, needle + 1) != NULL)
1049 gtk_tree_view_expand_to_path(
d->view, path);
1054 gtk_tree_view_expand_to_path(
d->view, path);
1071 GtkTreeIter child, iter;
1073 while(gtk_tree_model_iter_n_children(
model, level > 0 ? &iter : NULL) > 0)
1083 if(!gtk_tree_model_iter_parent(
model, &child, &iter)) level = 0;
1088 if(gtk_tree_model_iter_n_children(
model, level > 0 ? &iter : NULL) != 1)
break;
1089 gtk_tree_model_iter_children(
model, &child, level > 0 ? &iter : NULL);
1093 if(level <= 0)
return NULL;
1095 if(gtk_tree_model_iter_n_children(
model, &iter) == 0 && gtk_tree_model_iter_parent(
model, &child, &iter))
1096 return gtk_tree_model_get_path(
model, &child);
1097 return gtk_tree_model_get_path(
model, &iter);
1106 GtkTreeModel *filter = gtk_tree_model_filter_new(
model, path);
1107 gtk_tree_path_free(path);
1117 GHashTable *set = (GHashTable *)data;
1118 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
1120 if(gtk_tree_model_get_iter(
model, &it, path))
1124 if(
p) g_hash_table_add(set,
p);
1139 if(
p && g_hash_table_contains(c->set,
p)) gtk_tree_view_expand_to_path(c->d->view, path);
1150 return g_strsplit(
name,
"|", -1);
1158 GtkTreeIter parent, child = *leaf;
1159 while(gtk_tree_model_iter_parent(
model, &parent, &child))
1171 GtkTreeIter *uncategorized, guint *index,
int count)
1173 if(strchr(
name,
'|') != NULL)
return FALSE;
1175 char *next_name = g_strdup(next_name_raw ? next_name_raw :
"");
1176 if(strlen(next_name) >= strlen(
name) + 1 && next_name[strlen(
name)] ==
'|') next_name[strlen(
name)] =
'\0';
1177 const gboolean leaf_toplevel = g_strcmp0(next_name,
name) && g_strcmp0(
name, _(
"not tagged"));
1179 if(!leaf_toplevel)
return FALSE;
1181 if(!uncategorized->stamp)
1203 GList *sorted_names = NULL;
1205 for(GList *
v = values;
v;
v = g_list_next(
v))
1212 char *name_folded = g_utf8_casefold(
name, -1);
1213 char *name_folded_slash = g_strconcat(name_folded, G_DIR_SEPARATOR_S, NULL);
1214 collate_key = g_utf8_collate_key_for_filename(name_folded_slash, -1);
1226 sorted_names = g_list_prepend(sorted_names, tuple);
1231 if(!
dt_conf_get_bool(
"plugins/collect/descending")) sorted_names = g_list_reverse(sorted_names);
1232 return sorted_names;
1239 gboolean no_uncategorized,
const char *format_separator)
1242 GtkTreeIter uncategorized = { 0 };
1243 char **last_tokens = NULL;
1244 int last_tokens_length = 0;
1245 GtkTreeIter last_parent = { 0 };
1248 for(GList *names = sorted_names; names; names = g_list_next(names))
1252 const int count = tuple->
count;
1253 const int status = tuple->
status;
1256 const char *next_name = names->next ? ((
name_key_tuple_t *)names->next->data)->name : NULL;
1263 GtkTreeIter parent = last_parent;
1265 int common_length = 0;
1268 while(tokens[common_length] && last_tokens[common_length]
1269 && !g_strcmp0(tokens[common_length], last_tokens[common_length]))
1271 for(
int i = common_length;
i < last_tokens_length;
i++)
1273 gtk_tree_model_iter_parent(
model, &parent, &last_parent);
1274 last_parent = parent;
1282 for(
int i = 0;
i < common_length;
i++) pth =
dt_util_dstrcat(pth, format_separator, tokens[
i]);
1284 for(
char **token = &tokens[common_length]; *token; token++)
1290 gchar *pth2 = g_strdup(pth);
1291 pth2[strlen(pth2) - 1] =
'\0';
1292 const gboolean leaf = !*(token + 1);
1293 gtk_tree_store_insert_with_values(
store, &iter, common_length > 0 ? &parent : NULL, 0,
1309 if(last_tokens) g_strfreev(last_tokens);
1310 last_tokens = tokens;
1311 last_parent = parent;
1312 last_tokens_length = tokens_length;
1314 g_strfreev(last_tokens);
1322 char *format_separator =
"";
1327 format_separator =
"%s" G_DIR_SEPARATOR_S;
1331 format_separator =
"%s|";
1339 format_separator =
"%s:";
1345 GtkTreeModel *
model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
d->treefilter));
1346 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
model), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
1347 GTK_SORT_ASCENDING);
1349 GHashTable *saved_expanded = NULL;
1351 if(
d->view_rule != property)
1354 saved_expanded = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
1357 g_object_ref(
model);
1358 g_object_unref(
d->treefilter);
1359 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->view), NULL);
1360 gtk_tree_store_clear(GTK_TREE_STORE(
model));
1361 gtk_widget_hide(GTK_WIDGET(
d->view));
1373 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->view));
1374 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
1376 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->view),
d->treefilter);
1377 gtk_widget_set_no_show_all(GTK_WIDGET(
d->view),
FALSE);
1378 gtk_widget_show_all(GTK_WIDGET(
d->view));
1380 g_object_unref(
model);
1381 d->view_rule = property;
1390 GRegex *regex = g_regex_new(
"^\\s*\\[\\s*(.*)\\s*;\\s*(.*)\\s*\\]\\s*$", 0, 0, NULL);
1391 GMatchInfo *match_info;
1392 g_regex_match_full(regex, gtk_entry_get_text(GTK_ENTRY(dr->
text)), -1, 0, 0, &match_info, NULL);
1393 if(g_match_info_get_match_count(match_info) == 3)
1396 range->
start = g_match_info_fetch(match_info, 2);
1397 range->
stop = g_match_info_fetch(match_info, 1);
1399 g_match_info_free(match_info);
1400 g_regex_unref(regex);
1415 gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(
d->view));
1420 gtk_tree_view_expand_all(
d->view);
1422 gtk_tree_view_collapse_all(
d->view);
1423 else if(saved_expanded)
1428 if(saved_expanded) g_hash_table_destroy(saved_expanded);
1433 gtk_tree_model_foreach(
d->treefilter, (GtkTreeModelForeachFunc)
range_select, range);
1435 gtk_tree_selection_select_range(gtk_tree_view_get_selection(
d->view), range->
path1, range->
path2);
1438 gtk_tree_path_free(range->
path1);
1439 gtk_tree_path_free(range->
path2);
1443 gtk_tree_model_foreach(
d->treefilter, (GtkTreeModelForeachFunc)
tree_expand, dr);
1454 GtkTreeModel *
model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
d->listfilter));
1455 if(
d->view_rule != property)
1458 g_object_unref(
d->listfilter);
1459 g_object_ref(
model);
1460 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->view), NULL);
1461 gtk_list_store_clear(GTK_LIST_STORE(
model));
1462 gtk_widget_hide(GTK_WIDGET(
d->view));
1465 for(GList *
v = values;
v;
v = g_list_next(
v))
1474 gchar *text = g_strdup(
value);
1476 while(!g_utf8_validate(ptr, -1, (
const gchar **)&ptr)) ptr[0] =
'?';
1477 gchar *escaped_text = g_markup_escape_text(text, -1);
1479 gtk_list_store_append(GTK_LIST_STORE(
model), &iter);
1493 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->view));
1495 gtk_tree_selection_set_mode(selection, multi ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE);
1497 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->view),
d->listfilter);
1498 gtk_widget_set_no_show_all(GTK_WIDGET(
d->view),
FALSE);
1499 gtk_widget_show_all(GTK_WIDGET(
d->view));
1500 g_object_unref(
model);
1501 d->view_rule = property;
1514 gchar *needle = g_utf8_strdown(gtk_entry_get_text(GTK_ENTRY(dr->
text)), -1);
1515 if(g_str_has_suffix(needle,
"%")) needle[strlen(needle) - 1] =
'\0';
1521 gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(
d->view));
1525 GRegex *regex = g_regex_new(
"^\\s*\\[\\s*(.*)\\s*;\\s*(.*)\\s*\\]\\s*$", 0, 0, NULL);
1526 GMatchInfo *match_info;
1527 g_regex_match_full(regex, gtk_entry_get_text(GTK_ENTRY(dr->
text)), -1, 0, 0, &match_info, NULL);
1528 const int match_count = g_match_info_get_match_count(match_info);
1529 if(match_count == 3)
1532 range->
start = g_match_info_fetch(match_info, 1);
1533 range->
stop = g_match_info_fetch(match_info, 2);
1534 gtk_tree_model_foreach(
d->listfilter, (GtkTreeModelForeachFunc)
range_select, range);
1536 gtk_tree_selection_select_range(gtk_tree_view_get_selection(
d->view), range->
path1, range->
path2);
1539 gtk_tree_path_free(range->
path1);
1540 gtk_tree_path_free(range->
path2);
1544 gtk_tree_model_foreach(
d->listfilter, (GtkTreeModelForeachFunc)
list_select, dr);
1545 g_match_info_free(match_info);
1546 g_regex_unref(regex);
1549 gtk_tree_model_foreach(
d->listfilter, (GtkTreeModelForeachFunc)
list_select, dr);
1573 gchar *
n = g_strconcat(text,
"|%", NULL);
1579 gchar *
n = g_strconcat(text,
"*", NULL);
1597 gboolean descending =
FALSE;
1612 GtkTreeModel *
model = NULL;
1613 GtkTreeSelection *selection = gtk_tree_view_get_selection(
view);
1614 const int n_selected = gtk_tree_selection_count_selected_rows(selection);
1615 if(n_selected < 1)
return;
1617 GList *sels = gtk_tree_selection_get_selected_rows(selection, &
model);
1618 GtkTreePath *path1 = (GtkTreePath *)sels->data;
1619 if(!gtk_tree_model_get_iter(
model, &iter, path1))
1621 g_list_free_full(sels, (GDestroyNotify)gtk_tree_path_free);
1628 const int item =
d->view_rule;
1631 gboolean order_request =
FALSE;
1635 if(text && strlen(text) > 0)
1641 GtkTreePath *path2 = (GtkTreePath *)g_list_last(sels)->data;
1642 if(gtk_tree_model_get_iter(
model, &iter2, path2))
1647 ? g_strdup_printf(
"[%s;%s]", text2, text)
1648 : g_strdup_printf(
"[%s;%s]", text, text2);
1657 if(
d->recursive_check && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
d->recursive_check)))
1659 gchar *n_text = g_strconcat(text,
"*", NULL);
1666 if(gtk_tree_model_iter_has_child(
model, &iter))
1674 g_list_free_full(sels, (GDestroyNotify)gtk_tree_path_free);
1676 g_signal_handlers_block_matched(active_rule->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
1677 gtk_entry_set_text(GTK_ENTRY(active_rule->
text), text);
1678 gtk_editable_set_position(GTK_EDITABLE(active_rule->
text), -1);
1679 g_signal_handlers_unblock_matched(active_rule->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
1729 GtkTreeModel *
model = NULL;
1730 GList *paths = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(
d->view), &
model);
1732 for(GList *l = paths; l; l = g_list_next(l))
1735 if(gtk_tree_model_get_iter(
model, &it, (GtkTreePath *)l->data))
1742 g_list_free_full(paths, (GDestroyNotify)gtk_tree_path_free);
1743 return g_list_reverse(
out);
1750 GHashTable *seen = g_hash_table_new(g_direct_hash, g_direct_equal);
1752 for(GList *l = rows; l; l = g_list_next(l))
1757 text = recursive ? g_strconcat(
r->path,
"*", NULL) : g_strdup(
r->path);
1759 text = g_strdup(
r->path);
1764 for(GList *
i = ids;
i;
i = g_list_next(
i))
1765 if(!g_hash_table_contains(seen,
i->data))
1767 g_hash_table_add(seen,
i->data);
1768 out = g_list_prepend(
out,
i->data);
1772 g_hash_table_destroy(seen);
1773 return g_list_reverse(
out);
1777static gboolean
_confirm(
const char *title,
const char *message)
1780 GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
1781 GTK_BUTTONS_YES_NO,
"%s", message);
1782 gtk_window_set_title(GTK_WINDOW(dialog), title);
1783#ifdef GDK_WINDOWING_QUARTZ
1786 const gint res = gtk_dialog_run(GTK_DIALOG(dialog));
1787 gtk_widget_destroy(dialog);
1788 return res == GTK_RESPONSE_YES;
1791static gchar *
_ask_text(
const char *title,
const char *initial)
1795 = gtk_dialog_new_with_buttons(title, GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, _(
"_cancel"),
1796 GTK_RESPONSE_CANCEL, _(
"_ok"), GTK_RESPONSE_ACCEPT, NULL);
1797 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1799 gtk_entry_set_activates_default(GTK_ENTRY(entry),
TRUE);
1800 if(initial) gtk_entry_set_text(GTK_ENTRY(entry), initial);
1801 gtk_box_pack_start(GTK_BOX(area), entry,
TRUE,
TRUE, 0);
1802 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1804 gtk_widget_show_all(dialog);
1805#ifdef GDK_WINDOWING_QUARTZ
1808 gchar *result = NULL;
1809 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1811 const gchar *
t = gtk_entry_get_text(GTK_ENTRY(entry));
1812 if(
t && *
t) result = g_strdup(
t);
1814 gtk_widget_destroy(dialog);
1828 g_list_free(imgids);
1835 const int n = g_list_length(rows);
1836 const gboolean single = (
n == 1);
1839 GtkFileChooserNative *
fc = gtk_file_chooser_native_new(
1840 single ? _(
"select the new location of this folder") : _(
"select the new parent folder"), GTK_WINDOW(win),
1841 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, _(
"_open"), _(
"_cancel"));
1842 if(single && first->
path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(
fc), first->
path);
1844 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(
fc)) == GTK_RESPONSE_ACCEPT)
1846 gchar *uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(
fc));
1847 gchar *chosen = g_filename_from_uri(uri, NULL, NULL);
1851 for(GList *l = rows; l; l = g_list_next(l))
1859 gchar *base = g_path_get_basename(
r->path);
1860 gchar *dest = g_build_filename(chosen, base, NULL);
1880 const int n = g_list_length(rows);
1881 gchar *msg = g_strdup_printf(ngettext(
"Delete %d tag and detach it from all images?",
1882 "Delete %d tags and detach them from all images?",
n),
1884 const gboolean ok =
_confirm(_(
"delete tags"), msg);
1888 for(GList *l = rows; l; l = g_list_next(l))
1906 gchar *newname =
_ask_text(_(
"rename tag"),
r->path);
1937 const int n = g_list_length(
p->imgids);
1938 const float total = (
n > 0) ? (
float)(
n * (
max + 1)) : 1.0f;
1943 const int32_t imgid = GPOINTER_TO_INT(l->data);
2011 const collect_action_t *act = g_object_get_data(G_OBJECT(mi),
"collect-action");
2013 if(rows) act->
run(
d, rows);
2019 const int property =
d->view_rule;
2020 const int n = gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(
d->view));
2025 for(
size_t i = 0;
i < G_N_ELEMENTS(
ACTIONS);
i++)
2028 if(!act->
enabled(property,
n))
continue;
2029 if(!act->
multi &&
n > 1)
continue;
2031 g_object_set_data(G_OBJECT(mi),
"collect-action", (gpointer)act);
2033 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2038 gtk_widget_show_all(menu);
2039 gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
2042 gtk_widget_destroy(menu);
2055 const int n = g_list_length(imgs);
2056 gchar *msg = g_strdup_printf(ngettext(
"Physically move %d image to\n%s ?\n\nFiles are moved on disk.",
2057 "Physically move %d images to\n%s ?\n\nFiles are moved on disk.",
n),
2059 const gboolean ok =
_confirm(_(
"move images"), msg);
2061 if(!ok)
return FALSE;
2066 const int32_t filmid = film.
id;
2075 for(GList *l = imgs; l; l = g_list_next(l))
2076 if(
dt_image_move(GPOINTER_TO_INT(l->data), filmid) != -1) moved++;
2093 if(!tagid)
return FALSE;
2107 const int imgs_nb = gtk_selection_data_get_length(sel) / (int)
sizeof(uint32_t);
2108 if(imgs_nb <= 0)
return FALSE;
2110 GtkTreePath *path = NULL;
2111 if(!gtk_tree_view_get_path_at_pos(tree,
x, y, &path, NULL, NULL, NULL))
return FALSE;
2113 GtkTreeModel *
model = gtk_tree_view_get_model(tree);
2115 gboolean ok =
FALSE;
2116 if(gtk_tree_model_get_iter(
model, &iter, path))
2118 const uint32_t *imgt = (
const uint32_t *)gtk_selection_data_get_data(sel);
2120 for(
int i = 0;
i < imgs_nb;
i++) imgs = g_list_prepend(imgs, GINT_TO_POINTER((
int)imgt[
i]));
2122 gchar *rowpath = NULL;
2128 gtk_tree_path_free(path);
2133 GtkSelectionData *selection_data, guint target_type, guint time,
2136 GtkTreeView *tree = GTK_TREE_VIEW(widget);
2137 g_signal_stop_emission_by_name(tree,
"drag-data-received");
2140 gtk_drag_finish(context, success,
FALSE, time);
2147 if(event->button != 3 || event->type != GDK_BUTTON_PRESS)
return FALSE;
2150 GtkTreeView *
view = GTK_TREE_VIEW(treeview);
2151 GtkTreeSelection *sel = gtk_tree_view_get_selection(
view);
2155 GtkTreePath *path = NULL;
2156 if(gtk_tree_view_get_path_at_pos(
view, (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL) && path)
2158 if(!gtk_tree_selection_path_is_selected(sel, path))
2160 gtk_tree_selection_unselect_all(sel);
2161 gtk_tree_selection_select_path(sel, path);
2163 gtk_tree_path_free(path);
2167 if(gtk_tree_selection_count_selected_rows(sel) < 1)
return FALSE;
2181 GdkEvent *ev = gtk_get_current_event();
2185 = (ev && (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE))
2186 ? (GdkEventButton *)ev
2189 if(ev) gdk_event_free(ev);
2195 gtk_tree_view_scroll_to_cell(
view, path, NULL,
TRUE, 0.0, 0.0);
2206 gtk_widget_set_tooltip_text(dr->
text, _(
"use <, <=, >, >=, <>, =, [;] as operators"));
2208 gtk_widget_set_tooltip_text(dr->
text, _(
"use <, <=, >, >=, <>, =, [;] as operators\n"
2209 "star rating: 0-5\n"
2210 "rejected images: -1"));
2212 gtk_widget_set_tooltip_text(dr->
text,
2213 _(
"use <, <=, >, >=, <>, =, [;] as operators\n"
2214 "type dates in the form: YYYY:MM:DD hh:mm:ss.sss (only the year is mandatory)"));
2217 gtk_widget_set_tooltip_text(dr->
text, _(
"use `%' as wildcard and `,' to separate values"));
2220 gtk_widget_set_tooltip_text(dr->
text, _(
"use `%' as wildcard\n"
2221 "click to include hierarchy + sub-hierarchies (suffix `*')\n"
2222 "shift+click to include only the current hierarchy (no suffix)\n"
2223 "ctrl+click to include only sub-hierarchies (suffix `|%')"));
2226 gtk_widget_set_tooltip_text(dr->
text, _(
"use `%' as wildcard\n"
2227 "click to include location + sub-locations (suffix `*')\n"
2228 "shift+click to include only the current location (no suffix)\n"
2229 "ctrl+click to include only sub-locations (suffix `|%')"));
2232 gtk_widget_set_tooltip_text(dr->
text,
2233 _(
"use `%' as wildcard and append `*' to match sub-folders"));
2236 gtk_widget_set_tooltip_text(dr->
text, _(
"use `%' as wildcard"));
2238 gchar *tip = gtk_widget_get_tooltip_text(dr->
text);
2239 gtk_widget_set_tooltip_text(GTK_WIDGET(dr->
combo), tip);
2253 c->active_rule = dr->
num;
2266 c->active_rule = dr->
num;
2271 const gboolean transferable
2275 g_signal_handlers_block_matched(dr->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
2276 gtk_entry_set_text(GTK_ENTRY(dr->
text),
"");
2277 g_signal_handlers_unblock_matched(dr->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
2281 g_signal_handlers_block_matched(dr->
op_combo, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
_op_changed, NULL);
2282 gtk_combo_box_set_active(GTK_COMBO_BOX(dr->
op_combo), 0);
2283 g_signal_handlers_unblock_matched(dr->
op_combo, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
_op_changed, NULL);
2289 if(c->folders_controls && gtk_widget_get_visible(c->folders_controls))
2302 dr->
reveal = transferable;
2319 const gchar *
t = gtk_entry_get_text(GTK_ENTRY(dr->
text));
2320 const gboolean recursive = g_str_has_suffix(
t,
"*") || g_str_has_suffix(
t,
"%");
2321 g_signal_handlers_block_matched(
d->recursive_check, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
d);
2322 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->recursive_check), recursive);
2323 g_signal_handlers_unblock_matched(
d->recursive_check, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
d);
2337 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(c->view));
2338 if(gtk_tree_model_iter_n_children(
model, NULL) == 1)
2341 if(gtk_tree_model_get_iter_first(
model, &iter))
2345 g_signal_handlers_block_matched(dr->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
2346 gtk_entry_set_text(GTK_ENTRY(dr->
text), text);
2347 gtk_editable_set_position(GTK_EDITABLE(dr->
text), -1);
2348 g_signal_handlers_unblock_matched(dr->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
2373 gchar *
t = g_strdup(gtk_entry_get_text(GTK_ENTRY(dr->
text)));
2375 while(g_str_has_suffix(
t,
"*") || g_str_has_suffix(
t,
"%") || g_str_has_suffix(
t,
"|"))
t[strlen(
t) - 1] =
'\0';
2376 gchar *
n = gtk_toggle_button_get_active(b) ? g_strconcat(
t,
"*", NULL) : g_strdup(
t);
2379 g_signal_handlers_block_matched(dr->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
2380 gtk_entry_set_text(GTK_ENTRY(dr->
text),
n);
2381 gtk_editable_set_position(GTK_EDITABLE(dr->
text), -1);
2382 g_signal_handlers_unblock_matched(dr->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
2391 const gboolean desc = gtk_toggle_button_get_active(b);
2394 gtk_widget_queue_draw(GTK_WIDGET(b));
2411 dt_conf_set_int(
"show_folder_levels", (
int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)));
2418 dt_conf_set_bool(
"plugins/lighttable/tagging/no_uncategorized", gtk_toggle_button_get_active(b));
2440 const dt_lib_collect_mode_t mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem),
"menuitem_mode"));
2446 c->active_rule = active;
2454 const int num = dr->
num + 1;
2455 if(num < MAX_RULES && num > 0)
2456 _rule_set_mode(num, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem),
"menuitem_mode")));
2469 if(c->active_rule >= active - 1) c->active_rule = active - 2;
2496 if(event->button != 1)
return FALSE;
2502 mi = gtk_menu_item_new_with_label(_(
"clear this rule"));
2503 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2504 g_signal_connect(G_OBJECT(mi),
"activate", G_CALLBACK(
menuitem_clear), dr);
2506 if(dr->
num == active - 1)
2508 mi = gtk_menu_item_new_with_label(_(
"narrow down search"));
2510 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2511 g_signal_connect(G_OBJECT(mi),
"activate", G_CALLBACK(
menuitem_mode), dr);
2513 mi = gtk_menu_item_new_with_label(_(
"add more images"));
2515 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2516 g_signal_connect(G_OBJECT(mi),
"activate", G_CALLBACK(
menuitem_mode), dr);
2518 mi = gtk_menu_item_new_with_label(_(
"exclude images"));
2520 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2521 g_signal_connect(G_OBJECT(mi),
"activate", G_CALLBACK(
menuitem_mode), dr);
2523 else if(dr->
num < active - 1)
2525 mi = gtk_menu_item_new_with_label(_(
"change to: and"));
2527 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2530 mi = gtk_menu_item_new_with_label(_(
"change to: or"));
2532 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2535 mi = gtk_menu_item_new_with_label(_(
"change to: except"));
2537 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2541 gtk_widget_show_all(GTK_WIDGET(menu));
2542 gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
2584 gtk_button_set_label(GTK_BUTTON(dr->
button),
"-");
2585 gtk_widget_set_tooltip_text(GTK_WIDGET(dr->
button), _(
"clear this rule"));
2589 gtk_button_set_label(GTK_BUTTON(dr->
button),
"+");
2590 gtk_widget_set_tooltip_text(GTK_WIDGET(dr->
button), _(
"clear this rule or add new rules"));
2598 gtk_widget_set_tooltip_text(GTK_WIDGET(dr->
button), _(
"clear this rule"));
2606 gtk_widget_set_no_show_all(
d->rule[
i].hbox,
TRUE);
2607 gtk_widget_hide(
d->rule[
i].hbox);
2609 gtk_widget_set_no_show_all(
d->folders_controls,
TRUE);
2610 gtk_widget_hide(
d->folders_controls);
2611 gtk_widget_set_no_show_all(
d->collections_controls,
TRUE);
2612 gtk_widget_hide(
d->collections_controls);
2613 gtk_widget_set_no_show_all(
d->raw_box,
TRUE);
2614 gtk_widget_hide(
d->raw_box);
2615 gtk_widget_set_no_show_all(GTK_WIDGET(
d->view),
FALSE);
2616 gtk_widget_show(GTK_WIDGET(
d->view));
2637 gtk_widget_set_no_show_all(
d->rule[0].hbox,
FALSE);
2638 gtk_widget_show_all(
d->rule[0].hbox);
2639 gtk_widget_show(
d->rule[0].combo);
2640 gtk_widget_hide(
d->rule[0].button);
2641 gtk_entry_set_placeholder_text(GTK_ENTRY(
d->rule[0].text), _(
"Search a folder..."));
2645 gtk_widget_set_no_show_all(
d->folders_controls,
FALSE);
2646 gtk_widget_show_all(
d->folders_controls);
2649 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->sort_dir), desc);
2657 gtk_spin_button_set_value(GTK_SPIN_BUTTON(
d->folder_levels),
2660 const gchar *
t = gtk_entry_get_text(GTK_ENTRY(
d->rule[0].text));
2661 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->recursive_check),
2662 g_str_has_suffix(
t,
"*") || g_str_has_suffix(
t,
"%"));
2673 gtk_widget_set_no_show_all(
d->rule[0].hbox,
FALSE);
2674 gtk_widget_show_all(
d->rule[0].hbox);
2675 gtk_widget_hide(
d->rule[0].combo);
2676 gtk_widget_hide(
d->rule[0].button);
2677 gtk_entry_set_placeholder_text(GTK_ENTRY(
d->rule[0].text), _(
"Search a collection..."));
2681 gtk_widget_set_no_show_all(
d->collections_controls,
FALSE);
2682 gtk_widget_show_all(
d->collections_controls);
2683 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->no_uncategorized),
2691 gtk_widget_set_no_show_all(
d->raw_box,
FALSE);
2692 gtk_widget_show_all(
d->raw_box);
2693 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->raw_check), raw);
2698 gtk_entry_set_text(GTK_ENTRY(
d->raw_entry), s ? s :
"");
2700 gtk_widget_show(
d->raw_entry);
2701 gtk_widget_set_no_show_all(GTK_WIDGET(
d->view),
TRUE);
2702 gtk_widget_hide(GTK_WIDGET(
d->view));
2707 gtk_widget_hide(
d->raw_entry);
2708 for(
int i = 0;
i <=
d->active_rule;
i++)
2712 gtk_widget_set_no_show_all(
d->rule[
i].hbox,
FALSE);
2713 gtk_widget_show_all(
d->rule[
i].hbox);
2714 gtk_widget_show(
d->rule[
i].combo);
2715 gtk_widget_show(
d->rule[
i].button);
2717 gtk_entry_set_placeholder_text(GTK_ENTRY(
d->rule[
i].text), _(
"Search..."));
2729 if(gtk_toggle_button_get_active(b))
2772 if(
d->view_rule != -1)
return;
2786 g_signal_handlers_block_matched(
d->notebook, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
_on_tab_switch, NULL);
2787 gtk_notebook_set_current_page(GTK_NOTEBOOK(
d->notebook), tab);
2788 g_signal_handlers_unblock_matched(
d->notebook, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
_on_tab_switch, NULL);
2808 gboolean refresh =
TRUE;
2812 for(
int i = 0;
i <=
d->active_rule;
i++)
2845 gboolean uses_tag =
FALSE;
2846 for(
int i = 0;
i <
d->nb_rules;
i++)
2866static void geotag_changed(gpointer instance, GList *imgs,
const int locid, gpointer self)
2925 self->
data = (
void *)
d;
2936 dt_ui_notebook_page(GTK_NOTEBOOK(
d->notebook), _(
"Folders"), _(
"Browse and manage the folders known to Ansel"));
2938 dt_ui_notebook_page(GTK_NOTEBOOK(
d->notebook), _(
"Queries"), _(
"Build arbitrary collections"));
2939 gtk_widget_show_all(
d->notebook);
2940 gtk_box_pack_start(GTK_BOX(self->
widget),
d->notebook,
TRUE,
TRUE, 0);
2941 gtk_notebook_set_scrollable(GTK_NOTEBOOK(
d->notebook),
TRUE);
2942 g_signal_connect(G_OBJECT(
d->notebook),
"switch_page", G_CALLBACK(
_on_tab_switch), self);
2949 d->rule[
i].lib_collect = (
void *)
d;
2952 d->rule[
i].hbox = GTK_WIDGET(box);
2953 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(box),
TRUE,
TRUE, 0);
2954 gtk_widget_set_name(GTK_WIDGET(box),
"lib-dtbutton");
2959 g_signal_connect(G_OBJECT(
d->rule[
i].combo),
"value-changed", G_CALLBACK(
combo_changed),
d->rule +
i);
2960 gtk_box_pack_start(box,
d->rule[
i].combo,
FALSE,
FALSE, 0);
2963 gtk_box_pack_start(box, GTK_WIDGET(hbox),
FALSE,
FALSE, 0);
2966 d->rule[
i].op_combo = gtk_combo_box_text_new();
2968 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(
d->rule[
i].op_combo),
OP_LABELS[o]);
2969 gtk_combo_box_set_active(GTK_COMBO_BOX(
d->rule[
i].op_combo), 0);
2970 gtk_widget_set_no_show_all(
d->rule[
i].op_combo,
TRUE);
2971 gtk_widget_set_tooltip_text(
d->rule[
i].op_combo, _(
"comparison operator"));
2972 g_signal_connect(G_OBJECT(
d->rule[
i].op_combo),
"changed", G_CALLBACK(
_op_changed),
d->rule +
i);
2973 gtk_box_pack_start(hbox,
d->rule[
i].op_combo,
FALSE,
FALSE, 0);
2977 d->rule[
i].text = w;
2978 gtk_widget_add_events(w, GDK_FOCUS_CHANGE_MASK | GDK_KEY_PRESS_MASK);
2979 gtk_entry_set_placeholder_text(GTK_ENTRY(w), _(
"Search..."));
2980 g_signal_connect(G_OBJECT(w),
"focus-in-event", G_CALLBACK(
_entry_focus_in),
d->rule +
i);
2981 g_signal_connect(G_OBJECT(w),
"changed", G_CALLBACK(
entry_changed),
d->rule +
i);
2982 g_signal_connect(G_OBJECT(w),
"activate", G_CALLBACK(
entry_activated),
d->rule +
i);
2983 gtk_widget_set_name(GTK_WIDGET(w),
"lib-collect-entry");
2984 gtk_box_pack_start(hbox, w,
TRUE,
TRUE, 0);
2985 gtk_entry_set_width_chars(GTK_ENTRY(w), 5);
2987 d->rule[
i].button = gtk_button_new();
2988 gtk_widget_set_events(
d->rule[
i].button, GDK_BUTTON_PRESS_MASK);
2991 gtk_box_pack_start(hbox,
d->rule[
i].button,
FALSE,
FALSE, 0);
2996 d->recursive_check = gtk_check_button_new_with_label(_(
"include sub-folders"));
2997 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->recursive_check),
TRUE);
2999 gtk_box_pack_start(GTK_BOX(
d->folders_controls),
d->recursive_check,
FALSE,
FALSE, 0);
3007 gtk_widget_set_valign(
d->sort_by, GTK_ALIGN_CENTER);
3008 g_signal_connect(G_OBJECT(
d->sort_by),
"value-changed", G_CALLBACK(
_sort_by_changed),
d);
3009 gtk_box_pack_start(GTK_BOX(
d->folders_controls),
d->sort_by,
TRUE,
TRUE, 0);
3013 gtk_widget_set_tooltip_text(
d->sort_dir, _(
"toggle ascending / descending order"));
3015 gtk_box_pack_start(GTK_BOX(
d->folders_controls),
d->sort_dir,
FALSE,
FALSE, 0);
3017 d->folder_levels = gtk_spin_button_new_with_range(1, 5, 1);
3018 gtk_widget_set_tooltip_text(
d->folder_levels,
3019 _(
"number of folder levels to show in film-roll names, from the right"));
3021 gtk_box_pack_start(GTK_BOX(
d->folders_controls),
d->folder_levels,
FALSE,
FALSE, 0);
3022 gtk_box_pack_start(GTK_BOX(self->
widget),
d->folders_controls,
FALSE,
FALSE, 0);
3026 d->no_uncategorized = gtk_check_button_new_with_label(_(
"no 'uncategorized' group"));
3027 gtk_widget_set_tooltip_text(
d->no_uncategorized,
3028 _(
"do not group childless tags under an 'uncategorized' entry"));
3030 gtk_box_pack_start(GTK_BOX(
d->collections_controls),
d->no_uncategorized,
FALSE,
FALSE, 0);
3031 gtk_box_pack_start(GTK_BOX(self->
widget),
d->collections_controls,
FALSE,
FALSE, 0);
3035 d->raw_check = gtk_check_button_new_with_label(_(
"edit as raw SQL"));
3036 g_signal_connect(G_OBJECT(
d->raw_check),
"toggled", G_CALLBACK(
_raw_toggled),
d);
3037 gtk_box_pack_start(GTK_BOX(
d->raw_box),
d->raw_check,
FALSE,
FALSE, 0);
3038 d->raw_entry = gtk_entry_new();
3039 gtk_entry_set_placeholder_text(GTK_ENTRY(
d->raw_entry),
3040 _(
"SQL WHERE expression, e.g. iso > 800 AND lens LIKE '%50mm%'"));
3043 gtk_box_pack_start(GTK_BOX(
d->raw_box),
d->raw_entry,
FALSE,
FALSE, 0);
3047 GtkTreeView *
view = GTK_TREE_VIEW(gtk_tree_view_new());
3049 gtk_tree_view_set_headers_visible(
view,
FALSE);
3050 gtk_tree_view_set_activate_on_single_click(
view,
TRUE);
3051 gtk_widget_set_can_focus(GTK_WIDGET(
view),
TRUE);
3063 GtkTreeViewColumn *col = gtk_tree_view_column_new();
3064 gtk_tree_view_append_column(
view, col);
3065 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
3066 gtk_tree_view_column_pack_start(col, renderer,
TRUE);
3067 gtk_tree_view_column_set_cell_data_func(col, renderer,
tree_count_show, NULL, NULL);
3069 g_object_set(renderer,
"strikethrough",
TRUE,
"ellipsize", PANGO_ELLIPSIZE_MIDDLE, (gchar *)0);
3072 GtkTreeModel *listmodel = GTK_TREE_MODEL(
3074 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INT));
3075 d->listfilter = gtk_tree_model_filter_new(listmodel, NULL);
3078 GtkTreeModel *treemodel = GTK_TREE_MODEL(
3080 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INT));
3081 d->treefilter = gtk_tree_model_filter_new(treemodel, NULL);
3083 g_object_unref(treemodel);
3087 gtk_box_pack_start(GTK_BOX(self->
widget),
3099 d->vmonitor = g_volume_monitor_get();
3100 g_signal_connect(G_OBJECT(
d->vmonitor),
"mount-changed", G_CALLBACK(
_mount_changed), self);
3101 g_signal_connect(G_OBJECT(
d->vmonitor),
"mount-added", G_CALLBACK(
_mount_changed), self);
3103 d->vmonitor = g_unix_mount_monitor_get();
3104 g_signal_connect(G_OBJECT(
d->vmonitor),
"mounts-changed", G_CALLBACK(
_mount_changed), self);
3136 g_object_unref(
d->treefilter);
3137 g_object_unref(
d->listfilter);
3138 g_object_unref(
d->vmonitor);
void dt_bauhaus_combobox_clear(GtkWidget *widget)
void dt_bauhaus_combobox_set_selected_text_align(GtkWidget *widget, const dt_bauhaus_combobox_alignment_t text_align)
gboolean dt_bauhaus_combobox_set_from_value(GtkWidget *widget, int value)
int dt_bauhaus_combobox_get(GtkWidget *widget)
void dt_bauhaus_combobox_add_full(GtkWidget *widget, const char *text, dt_bauhaus_combobox_alignment_t align, gpointer data, void(free_func)(void *data), gboolean sensitive)
gpointer dt_bauhaus_combobox_get_data(GtkWidget *widget)
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
@ DT_BAUHAUS_COMBOBOX_ALIGN_RIGHT
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
static void get_properties(dt_lib_collect_rule_t *dr)
static gboolean _confirm(const char *title, const char *message)
void gui_reset(dt_lib_module_t *self)
int set_params(dt_lib_module_t *self, const void *params, int size)
static void _set_tooltip(dt_lib_collect_rule_t *dr)
static void _hide_all_widgets(dt_lib_collect_t *d)
static gboolean tree_expand(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
static void metadata_changed(gpointer instance, int type, gpointer self)
static void _folder_levels_changed(GtkWidget *spin, dt_lib_collect_t *d)
void * get_params(dt_lib_module_t *self, int *size)
static void _collect_expanded_cb(GtkTreeView *view, GtkTreePath *path, gpointer data)
static int _rule_get_mode(int n)
@ DT_LIB_COLLECT_COL_TOOLTIP
@ DT_LIB_COLLECT_COL_COUNT
@ DT_LIB_COLLECT_COL_UNREACHABLE
@ DT_LIB_COLLECT_NUM_COLS
@ DT_LIB_COLLECT_COL_FONT
@ DT_LIB_COLLECT_COL_INDEX
@ DT_LIB_COLLECT_COL_PATH
@ DT_LIB_COLLECT_COL_TEXT
@ DT_LIB_COLLECT_COL_VISIBLE
static void _view_drag_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint target_type, guint time, dt_lib_collect_t *d)
void * legacy_params(struct dt_lib_module_t *self, const void *const old_params, const size_t old_params_size, const int old_version, int *new_version, size_t *new_size)
static void _populate_collect_combo(GtkWidget *w)
static void _mount_changed(GUnixMountMonitor *monitor, dt_lib_module_t *self)
static void geotag_changed(gpointer instance, GList *imgs, const int locid, gpointer self)
#define PARAM_STRING_SIZE
static const char * UNCATEGORIZED_TAG
static void _free_row(gpointer p)
static int _rules_count()
static GList * _collect_sorted_tree_names(int property, int rule)
static void menuitem_clear(GtkMenuItem *menuitem, dt_lib_collect_rule_t *dr)
static void get_number_of_rules(dt_lib_collect_t *d)
static void _action_activate(GtkMenuItem *mi, dt_lib_collect_t *d)
static void _sort_dir_toggled(GtkToggleButton *b, dt_lib_collect_t *d)
static void _on_tab_switch(GtkNotebook *nb, GtkWidget *page, guint page_num, dt_lib_module_t *self)
static void _raw_entry_activated(GtkWidget *entry, dt_lib_collect_t *d)
static void _raw_toggled(GtkToggleButton *b, dt_lib_collect_t *d)
static char ** _split_tree_name(int property, const char *name)
static void _configure_tab(dt_lib_collect_t *d, dt_collect_tab_t tab)
static void _view_row_activated(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *col, dt_lib_collect_t *d)
static void _rule_set_mode(int n, int mode)
static int32_t _prerender_job(dt_job_t *job)
static void _split_operator(const char *text, int *op_idx, const char **value)
static gboolean item_is_tree(int item)
static gboolean _drop_move_to_folder(dt_lib_collect_t *d, const char *folder, GList *imgs)
static void tag_changed(gpointer instance, gpointer self)
static gboolean _view_button_pressed(GtkWidget *treeview, GdkEventButton *event, dt_lib_collect_t *d)
static gboolean _en_tags(int property, int n)
static void _build_tree_store(GtkTreeStore *store, int property, GList *sorted_names, gboolean no_uncategorized, const char *format_separator)
static gboolean list_match_string(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
static int string_array_length(char **list)
static gboolean item_is_tag(int item)
static void _lib_collect_gui_update(dt_lib_module_t *self)
static void _force_refresh(dt_lib_collect_t *d)
static void _op_changed(GtkWidget *w, dt_lib_collect_rule_t *dr)
static gboolean _view_popup_menu(GtkWidget *treeview, dt_lib_collect_t *d)
static void _combo_as_view_toggle(GtkWidget *combo)
static gboolean tree_match_string(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
void gui_cleanup(dt_lib_module_t *self)
static void _populate_list(dt_lib_collect_rule_t *dr)
static void row_activated(GtkTreeView *view, GtkTreePath *path, GdkEventButton *event, dt_lib_collect_t *d)
static void tree_count_show(GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
static void _show_context_menu(dt_lib_collect_t *d, GdkEventButton *event)
static gboolean _drop_attach_tag(dt_lib_collect_t *d, const char *tagpath, GList *imgs)
static GList * _selected_rows(dt_lib_collect_t *d)
static char * tag_collate_key(char *tag)
static const char *const OP_LABELS[]
static gboolean _do_drop(dt_lib_collect_t *d, GtkTreeView *tree, gint x, gint y, GtkSelectionData *sel)
static void _act_tags_remove(dt_lib_collect_t *d, GList *rows)
static void _no_uncategorized_toggled(GtkToggleButton *b, dt_lib_collect_t *d)
static gboolean _combo_set_active_collection(GtkWidget *combo, const int property)
static void _lib_collect_update_params(dt_lib_collect_t *d)
static gint sort_folder_tag(gconstpointer a, gconstpointer b)
static void menuitem_mode_change(GtkMenuItem *menuitem, dt_lib_collect_rule_t *dr)
static void entry_activated(GtkWidget *entry, dt_lib_collect_rule_t *dr)
static gboolean item_is_folder(int item)
void init_presets(dt_lib_module_t *self)
static void _rules_set_count(int n)
static GList * _rows_to_imgids(int property, GList *rows, gboolean recursive)
static void _act_folders_remove(dt_lib_collect_t *d, GList *rows)
static void _combo_as_collections(GtkWidget *combo)
static void _view_row_expanded(GtkTreeView *view, GtkTreeIter *iter, GtkTreePath *path, dt_lib_collect_t *d)
static void _prerender_free(void *p)
static dt_lib_collect_t * get_collect(dt_lib_collect_rule_t *r)
#define ADD_COLLECT_ENTRY(value)
uint32_t container(dt_lib_module_t *self)
static gboolean _entry_focus_in(GtkWidget *w, GdkEventFocus *event, dt_lib_collect_rule_t *dr)
static int is_time_property(int property)
static dt_lib_module_t * _self()
static gboolean _restore_expanded_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
static void set_properties(dt_lib_collect_rule_t *dr)
static void entry_changed(GtkEntry *entry, dt_lib_collect_rule_t *dr)
static void _act_tag_rename(dt_lib_collect_t *d, GList *rows)
static void filmrolls_removed(gpointer instance, gpointer self)
static const collect_action_t ACTIONS[]
static gboolean range_select(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
static void menuitem_mode(GtkMenuItem *menuitem, dt_lib_collect_rule_t *dr)
static int _rule_get_item(int n)
static void collection_updated(gpointer instance, dt_collection_change_t query_change, dt_collection_properties_t changed_property, gpointer imgs, int next, gpointer self)
static void preferences_changed(gpointer instance, gpointer self)
static void _act_folders_relocate(dt_lib_collect_t *d, GList *rows)
static void _rule_set_item(int n, int item)
static gboolean popup_button_callback(GtkWidget *widget, GdkEventButton *event, dt_lib_collect_rule_t *dr)
void gui_init(dt_lib_module_t *self)
static GtkTreeModel * _create_filtered_model(GtkTreeModel *model, dt_lib_collect_rule_t *dr)
static void _rule_set_string(int n, const char *s)
static void _commit_colllection()
const char ** views(dt_lib_module_t *self)
static gboolean _maybe_file_uncategorized(GtkTreeStore *store, const char *name, const char *next_name_raw, GtkTreeIter *uncategorized, guint *index, int count)
static gboolean list_select(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
static gboolean _en_folders(int property, int n)
static void combo_changed(GtkWidget *combo, dt_lib_collect_rule_t *dr)
static void tree_set_visibility(GtkTreeModel *model, gpointer data)
static void _set_rule_button(dt_lib_collect_rule_t *dr, gboolean last, gboolean active)
static gchar * _rule_get_string(int n)
static gchar * _ask_text(const char *title, const char *initial)
static dt_lib_collect_rule_t * get_active_rule(dt_lib_collect_t *d)
static void filmrolls_updated(gpointer instance, gpointer self)
static void _act_prerender(dt_lib_collect_t *d, GList *rows)
static gboolean _en_any(int property, int n)
static void _commit_quiet()
static void _update_op_combo(dt_lib_collect_rule_t *dr)
static void _recursive_toggled(GtkToggleButton *b, dt_lib_collect_t *d)
static const char *const OP_TOKENS[]
static gboolean item_is_numeric(int item)
static GtkTreePath * _folders_root_collapse_path(GtkTreeModel *model)
static gboolean tree_range_visible(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
static gboolean tree_reveal_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
static gboolean _en_tag_single(int property, int n)
static void update_view(dt_lib_collect_rule_t *dr)
static void free_tuple(gpointer data)
static void _propagate_count_to_ancestors(GtkTreeStore *store, GtkTreeIter *leaf, int count)
static gboolean _adopt_tag_order(const char *text, int *order)
static void _sort_by_changed(GtkWidget *combo, dt_lib_collect_t *d)
static void _combo_as_full(GtkWidget *combo)
static char ** split_path(const char *path)
static guint64 _date_key(const char *s, char pad)
static int _combo_get_active_collection(GtkWidget *combo)
static gchar * _decorate_hierarchy(gchar *text, GdkEventButton *event)
static void _populate_tree(dt_lib_collect_rule_t *dr)
@ DT_LIB_COLLECT_MODE_AND_NOT
@ DT_LIB_COLLECT_MODE_AND
void dt_collection_update_query(const dt_collection_t *collection, dt_collection_change_t query_change, dt_collection_properties_t changed_property, GList *list)
void dt_collection_set_query_flags(const dt_collection_t *collection, dt_collection_query_flags_t flags)
void dt_collection_memory_update()
void dt_collection_split_operator_number(const gchar *input, char **number1, char **number2, char **operator)
GList * dt_collection_get_images_for_rule(const dt_collection_properties_t property, const char *text)
void dt_collection_set_tag_id(dt_collection_t *collection, const uint32_t tagid)
void dt_collection_name_value_free(gpointer value)
GList * dt_collection_get_property_values(const dt_collection_properties_t property, const int rule)
dt_collection_properties_t
@ DT_COLLECTION_PROP_EXPOSURE
@ DT_COLLECTION_PROP_MODULE
@ DT_COLLECTION_PROP_RATING
@ DT_COLLECTION_PROP_QUERY
@ DT_COLLECTION_PROP_TIME
@ DT_COLLECTION_PROP_METADATA
@ DT_COLLECTION_PROP_GROUPING
@ DT_COLLECTION_PROP_FILMROLL
@ DT_COLLECTION_PROP_LENS
@ DT_COLLECTION_PROP_CAMERA
@ DT_COLLECTION_PROP_LOCAL_COPY
@ DT_COLLECTION_PROP_GEOTAGGING
@ DT_COLLECTION_PROP_FILENAME
@ DT_COLLECTION_PROP_COLORLABEL
@ DT_COLLECTION_PROP_UNDEF
@ DT_COLLECTION_PROP_ORDER
@ DT_COLLECTION_PROP_FOLDERS
@ DT_COLLECTION_PROP_APERTURE
@ DT_COLLECTION_PROP_IMPORT_TIMESTAMP
@ DT_COLLECTION_PROP_FOCAL_LENGTH
@ DT_COLLECTION_PROP_EXPORT_TIMESTAMP
@ DT_COLLECTION_PROP_CHANGE_TIMESTAMP
@ DT_COLLECTION_PROP_HISTORY
@ DT_COLLECTION_PROP_PRINT_TIMESTAMP
#define DT_COLLECTION_ORDER_FLAG
#define COLLECTION_QUERY_FULL
@ DT_COLLECTION_CHANGE_RELOAD
@ DT_COLLECTION_CHANGE_NEW_QUERY
@ DT_COLLECTION_SORT_FILENAME
@ DT_COLLECTION_SORT_NONE
const dt_colormatrix_t dt_aligned_pixel_t out
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
int32_t dt_image_move(const int32_t imgid, const int32_t filmid)
const char * dt_image_film_roll_name(const char *path)
void dt_image_synch_xmp(const int selected)
void dt_conf_set_bool(const char *name, int val)
int dt_conf_get_bool(const char *name)
gchar * dt_conf_get_string(const char *name)
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
void dt_conf_set_string(const char *name, const char *val)
const char * dt_conf_get_string_const(const char *name)
void dt_control_log(const char *msg,...)
void dt_control_queue_redraw_center()
request redraw of center window. This redraws the center view within a gdk critical section to preven...
gboolean dt_control_remove_images()
uint32_t view(const dt_view_t *self)
#define DT_MODULE(MODVER)
static void dt_free_gpointer(gpointer ptr)
static const dt_aligned_pixel_simd_t value
static gboolean dt_modifier_is(const GdkModifierType state, const GdkModifierType desired_modifier_mask)
#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)
static const GtkTargetEntry target_list_internal[]
static const guint n_targets_internal
void dtgtk_cairo_paint_sortby(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dt_film_init(dt_film_t *film)
void dt_film_relocate(const char *old_path, const char *new_path)
int dt_film_new(dt_film_t *film, const char *directory)
int32_t dt_film_get_id(const char *folder)
void dt_film_set_folder_status()
void dt_film_cleanup(dt_film_t *film)
GtkWidget * dt_ui_notebook_page(GtkNotebook *notebook, const char *text, const char *tooltip)
GtkNotebook * dt_ui_notebook_new()
void dt_gui_refocus_center()
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.
void dt_accels_disconnect_on_text_input(GtkWidget *widget)
Disconnects accels when a text or search entry gets the focus, and reconnects them when it looses it....
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
#define DT_GUI_BOX_SPACING
dt_job_state_t dt_control_job_get_state(_dt_job_t *job)
dt_job_t * dt_control_job_create(dt_job_execute_callback execute, const char *msg,...)
int dt_control_add_job(dt_control_t *control, dt_job_queue_t queue_id, _dt_job_t *job)
void * dt_control_job_get_params(const _dt_job_t *job)
void dt_control_job_set_progress(dt_job_t *job, double value)
void dt_control_job_add_progress(dt_job_t *job, const char *message, gboolean cancellable)
void dt_control_job_set_params(_dt_job_t *job, void *params, dt_job_destroy_callback callback)
gboolean dt_handle_dialog_enter(GtkWidget *widget, GdkEventKey *event, gpointer data)
void dt_lib_presets_add(const char *name, const char *plugin_name, const int32_t version, const void *params, const int32_t params_size, gboolean readonly)
float *const restrict const size_t k
void dt_mipmap_get_cache_filename(char path[PATH_MAX], const dt_mipmap_cache_t *cache, dt_mipmap_size_t mip, const int32_t imgid)
void dt_mimap_cache_evict(dt_mipmap_cache_t *cache, const int32_t imgid)
#define dt_mipmap_cache_get(A, B, C, D, E, F)
#define dt_mipmap_cache_release(A, B)
void dt_osx_disallow_fullscreen(GtkWidget *widget)
void dt_selection_select_list(struct dt_selection_t *selection, const GList *const l)
void dt_selection_clear(dt_selection_t *selection)
void dt_control_signal_unblock_by_func(const struct dt_control_signal_t *ctlsig, GCallback cb, gpointer user_data)
void dt_control_signal_block_by_func(const struct dt_control_signal_t *ctlsig, GCallback cb, gpointer user_data)
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
@ DT_SIGNAL_METADATA_CHANGED
This signal is raised when metadata status (shown/hidden) or value has changed.
@ DT_SIGNAL_IMAGES_ORDER_CHANGE
This signal is raised to request image order change.
@ DT_SIGNAL_FILMROLLS_CHANGED
This signal is raised when a filmroll is deleted/changed but not imported.
@ DT_SIGNAL_GEOTAG_CHANGED
This signal is raised when a geotag is added/deleted/changed
@ DT_SIGNAL_PREFERENCES_CHANGE
This signal is raised after preferences have been changed no parameters no return.
@ DT_SIGNAL_FILMROLLS_REMOVED
This signal is raised only when a filmroll is removed.
@ DT_SIGNAL_TAG_CHANGED
This signal is raised when a tag is added/deleted/changed
@ 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
const float uint32_t state[4]
gboolean(* enabled)(int property, int n)
void(* run)(dt_lib_collect_t *d, GList *rows)
dt_mipmap_size_t max_size
struct dt_gui_gtk_t * gui
struct dt_collection_t * collection
struct dt_mipmap_cache_t * mipmap_cache
struct dt_selection_t * selection
struct dt_control_signal_t * signals
struct dt_bauhaus_t * bauhaus
struct dt_view_manager_t * view_manager
struct dt_control_t * control
dt_lib_collect_params_rule_t rule[10]
GtkWidget * recursive_check
struct dt_lib_collect_params_t * params
GtkWidget * collections_controls
GtkTreeModel * treefilter
dt_lib_collect_rule_t rule[10]
GtkTreeModel * listfilter
GtkWidget * no_uncategorized
GtkWidget * folder_levels
GUnixMountMonitor * vmonitor
GtkWidget * folders_controls
struct dt_view_manager_t::@67 proxy
struct dt_view_manager_t::@67::@69 module_collect
struct dt_lib_module_t *void(* update)(struct dt_lib_module_t *)
GList * dt_util_str_to_glist(const gchar *separator, const gchar *text)
gboolean dt_util_test_image_file(const char *filename)
gchar * dt_util_dstrcat(gchar *str, const gchar *format,...)
@ DT_UI_CONTAINER_PANEL_LEFT_CENTER