Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
filter.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2011 Henrik Andersson.
4 Copyright (C) 2011, 2013 johannes hanika.
5 Copyright (C) 2011 Robert Bieber.
6 Copyright (C) 2011-2018 Tobias Ellinghaus.
7 Copyright (C) 2012-2013 José Carlos García Sogo.
8 Copyright (C) 2012 marcel.
9 Copyright (C) 2012 Mika Boström.
10 Copyright (C) 2012 Richard Wonka.
11 Copyright (C) 2012 Simon Spannagel.
12 Copyright (C) 2013 Benjamin Cahill.
13 Copyright (C) 2013-2014, 2016 Roman Lebedev.
14 Copyright (C) 2015 JohnnyRun.
15 Copyright (C) 2016, 2019-2022 Aldric Renaudin.
16 Copyright (C) 2017 Dan Torop.
17 Copyright (C) 2018 Mario Lueder.
18 Copyright (C) 2018-2020, 2022 Pascal Obry.
19 Copyright (C) 2018 Sam Smith.
20 Copyright (C) 2018 Simon Legner.
21 Copyright (C) 2019, 2022-2023, 2025 Aurélien PIERRE.
22 Copyright (C) 2019, 2021 Bill Ferguson.
23 Copyright (C) 2020 Chris Elston.
24 Copyright (C) 2020 Hubert Kowalski.
25 Copyright (C) 2020 jpverrue.
26 Copyright (C) 2020-2022 Philippe Weyland.
27 Copyright (C) 2021 Davide.
28 Copyright (C) 2021-2022 Diederik Ter Rahe.
29 Copyright (C) 2022 Martin Bařinka.
30 Copyright (C) 2022 Nicolas Auffray.
31 Copyright (C) 2022 Victor Forsiuk.
32 Copyright (C) 2023 Luca Zulberti.
33
34 darktable is free software: you can redistribute it and/or modify
35 it under the terms of the GNU General Public License as published by
36 the Free Software Foundation, either version 3 of the License, or
37 (at your option) any later version.
38
39 darktable is distributed in the hope that it will be useful,
40 but WITHOUT ANY WARRANTY; without even the implied warranty of
41 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
42 GNU General Public License for more details.
43
44 You should have received a copy of the GNU General Public License
45 along with darktable. If not, see <http://www.gnu.org/licenses/>.
46*/
47
48#include "common/collection.h"
49#include "common/selection.h"
50#include "common/darktable.h"
51#include "control/conf.h"
52#include "control/control.h"
53#include "develop/develop.h"
54
55#include "gui/gtk.h"
56#include "dtgtk/button.h"
57#include "libs/lib.h"
58#include "libs/lib_api.h"
59#include "bauhaus/bauhaus.h"
60
61DT_MODULE(1)
62
79
80/* callback for sort combobox change */
81static void _lib_filter_sort_combobox_changed(GtkWidget *widget, gpointer user_data);
82/* callback for reverse sort check button change */
83static void _lib_filter_reverse_button_changed(GtkDarktableToggleButton *widget, gpointer user_data);
84/* updates the query and redraws the view */
86
87/* save the images order if the first collect filter is on tag*/
89/* images order change from outside */
90static void _lib_filter_images_order_change(gpointer instance, int order, dt_lib_module_t *self);
91
93static gboolean _show_popover_menu(dt_lib_module_t *self, GtkWidget *w);
94
110#define NB_ITEMS (sizeof(items) / sizeof(dt_collection_sort_t))
111
112static const char *_sort_names[]
113 = { N_("filename"),
114 N_("captured"),
115 N_("imported"),
116 N_("modified"),
117 N_("exported"),
118 N_("printed"),
119 N_("rating"),
120 N_("id"),
121 N_("color label"),
122 N_("group"),
123 N_("full path"),
124 N_("title"),
125 NULL };
126
128{
129 for(int i = 0; i < NB_ITEMS; i++)
130 {
131 if(sort == items[i])
132 return i;
133 }
134 return 0;
135}
136
137const char *name(struct dt_lib_module_t *self)
138{
139 return _("filter");
140}
141
142const char **views(dt_lib_module_t *self)
143{
144 static const char *v[] = {"lighttable", NULL};
145 return v;
146}
147
152
154{
155 return 0;
156}
157
159{
160 return 2001;
161}
162
163static void _set_widget_dimmed(GtkWidget *widget, const gboolean dimmed)
164{
165 if(dimmed) dt_gui_add_class(widget, "dt_dimmed");
166 else dt_gui_remove_class(widget, "dt_dimmed");
167 gtk_widget_queue_draw(GTK_WIDGET(widget));
168}
169
170static char *_encode_text_filter(const char *entry)
171{
172 // by default adds start and end wildcard
173 // " removes the corresponding wildcard
174 char start[2] = {0};
175 char *text = NULL;
176 char *p = (char *)entry;
177 if(strlen(entry) > 1 && !(entry[0] == '"' && entry[1] == '"'))
178 {
179 if(entry[0] == '"')
180 p++;
181 else if(entry[0])
182 start[0] = '%';
183 if(entry[strlen(entry) - 1] == '"')
184 {
185 text = g_strconcat(start, (char *)p, NULL);
186 text[strlen(text) - 1] = '\0';
187 }
188 else if(entry[0])
189 text = g_strconcat(start, (char *)p, "%", NULL);
190 }
191 return text;
192}
193
194static char *_decode_text_filter(const char *text)
195{
196 // revert the encoded filter for display
197 char start[2] = {0};
198 char *text1 = g_strdup(text);
199 char *p = text1;
200 char *text2;
201 if(text1[0])
202 {
203 if(text1[0] == '%')
204 p++;
205 else
206 start[0] = '\"';
207 if(strlen(text1) > 1 && text1[strlen(text1) - 1] == '%')
208 {
209 text1[strlen(text1) - 1] = '\0';
210 text2 = g_strconcat(start, (char *)p, NULL);
211 }
212 else
213 text2 = g_strconcat(start, (char *)p, "\"", NULL);
214 dt_free(text1);
215 return text2;
216 }
217 else return text1;
218}
219
220static gboolean _text_entry_changed_wait(gpointer user_data)
221{
222 dt_lib_module_t *self = (dt_lib_module_t *)user_data;
224 if(d->time_out)
225 {
226 d->time_out--;
227 double clock = dt_get_wtime();
228 if(clock - d->last_key_time >= 0.4)
229 {
230 d->time_out = 1; // force the query execution
231 d->last_key_time = clock;
232 }
233
234 if(d->time_out == 1)
235 { // tell we are busy
236 _set_widget_dimmed(d->text, TRUE);
237 }
238 else if(!d->time_out)
239 {
240 char *text = _encode_text_filter(gtk_entry_get_text(GTK_ENTRY(d->text)));
241
242 // avoids activating twice the same query
244 {
247 }
248 else dt_free(text);
249 _set_widget_dimmed(d->text, FALSE);
250 return FALSE;
251 }
252 }
253 return TRUE;
254}
255
257{
258 // two timeouts 1) 0.4 sec after the last key, 2) 1.5 sec of successive keys
260 d->last_key_time = dt_get_wtime();
261 if(!d->time_out)
262 {
263 d->time_out = 15;
264 g_timeout_add(100, _text_entry_changed_wait, self);
265 }
266}
267
268static void _text_entry_changed(GtkEntry *entry, dt_lib_module_t *self)
269{
270 _launch_text_query(self);
271}
272
274{
277 gtk_entry_set_text(GTK_ENTRY(d->text), "");
278}
279
285
286gboolean _focus_search_action(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval,
287 GdkModifierType modifier, gpointer data)
288{
289 dt_lib_module_t *self = (dt_lib_module_t *)data;
291 gtk_widget_grab_focus(GTK_WIDGET(d->text));
292 return TRUE;
293}
294
304
305static void _dtgtk_button_set_active(GtkWidget *w, gboolean active)
306{
307 // shitty design: the active rejected state is signaled as a right orientation...
308 if(active)
309 DTGTK_BUTTON(w)->icon_flags |= CPF_DIRECTION_RIGHT;
310 else
311 DTGTK_BUTTON(w)->icon_flags &= ~CPF_DIRECTION_RIGHT;
312
314 gtk_widget_queue_draw(w);
315}
316
317
325
326static gboolean _colorlabel_clicked(GtkWidget *w, GdkEventButton *e, dt_lib_module_t *self)
327{
329
330 if(e->button == 3)
331 {
332 _show_popover_menu(self, w);
333 return TRUE;
334 }
335
337
338 // Toggle state
340
341 // Update collection flags
342 for(int i = 0; i <= DT_COLORLABELS_LAST; i++)
343 {
345 flags |= colors[i];
346 else
347 flags &= ~colors[i];
348 }
349
353 return TRUE;
354}
355
363
364
365static gboolean _altered_clicked(GtkWidget *w, GdkEventButton *e, dt_lib_module_t *self)
366{
367 if(e->button == 3)
368 {
369 _show_popover_menu(self, w);
370 return TRUE;
371 }
372
374
375 // Toggle state
377
378 // Update collection flags
381 else
382 flags &= ~COLLECTION_FILTER_ALTERED;
383
387 return TRUE;
388}
389
390static gboolean _unaltered_clicked(GtkWidget *w, GdkEventButton *e, dt_lib_module_t *self)
391{
392 if(e->button == 3)
393 {
394 _show_popover_menu(self, w);
395 return TRUE;
396 }
397
399
400 // Toggle state
402
403 // Update collection flags
406 else
407 flags &= ~COLLECTION_FILTER_UNALTERED;
408
412 return TRUE;
413}
414
415static void _culling_mode(GtkWidget *widget, gpointer data)
416{
417 darktable.gui->culling_mode = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
418
419 // If we are exiting culling mode, we need to pop the selection before resetting the thumbtable collection
421
422 // Anchor the re-scrollings to the right image
423 const int32_t imgid = dt_selection_get_first_id(darktable.selection);
426
427 // Force-rebuild the whole thumbtable on the next collection update
429
432}
433
438
440{
441 gtk_widget_set_halign(widget, GTK_ALIGN_FILL);
442 gtk_widget_set_hexpand(widget, TRUE);
443
444 gtk_widget_set_valign(widget, GTK_ALIGN_CENTER);
445 gtk_widget_set_vexpand(widget, FALSE);
446}
447
457
458
460{
463
464 // Update GUI button state
465 for(int i = 0; i < 7; i++)
466 {
467 gboolean active = flags & ratings[i];
468 if(i != 1)
469 {
470 // fill stars if active
471 if(active)
472 DTGTK_BUTTON(d->stars[i])->icon_data = &darktable.bauhaus->color_fg;
473 else
474 DTGTK_BUTTON(d->stars[i])->icon_data = NULL;
475 }
476
477 _dtgtk_button_set_active(d->stars[i], active);
478 }
479}
480
481
482static gboolean _rating_clicked(GtkWidget *w, GdkEventButton *e, dt_lib_module_t *self)
483{
485
486 if(e->button == 3)
487 {
488 _show_popover_menu(self, w);
489 return TRUE;
490 }
491
493
494 // Do range selection for >= rating if Shift + Click
495 if(dt_modifier_is(e->state, GDK_SHIFT_MASK))
496 {
497 gboolean include = TRUE;
498 for(int i = 6; i > 1; i--)
499 {
500 dtgtk_button_set_active(DTGTK_BUTTON(d->stars[i]), include);
501 if(w == d->stars[i]) include = FALSE;
502 }
503 }
504 else
505 {
506 // Toggle state for clicked button
508 }
509
510 // Update collection flags
511 for(int i = 0; i < 7; i++)
512 {
514 flags |= ratings[i];
515 else
516 flags &= ~ratings[i];
517 }
518
522 return TRUE;
523}
524
525
534
543
544
546{
548 dt_gui_menu_popup(GTK_MENU(d->menu), w, GDK_GRAVITY_SOUTH, GDK_GRAVITY_NORTH);
549 return TRUE;
550}
551
553{
554 GtkWidget *spacer = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
555 gtk_box_pack_start(GTK_BOX(self->widget), spacer, FALSE, FALSE, 0);
556}
557
559{
560 GtkWidget *spacer = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
561 dt_gui_add_class(spacer, "subsection");
562 gtk_box_pack_start(GTK_BOX(self->widget), spacer, FALSE, FALSE, 0);
563}
564
566{
567 /* initialize ui widgets */
569 self->data = (void *)d;
570
571 self->widget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
573 dt_gui_add_class(self->widget, "quick_filter_box");
574
575 GtkWidget *label;
576
577 d->refresh = dtgtk_button_new(dtgtk_cairo_paint_refresh, 0, NULL);
578 gtk_widget_set_tooltip_text(d->refresh, _("Refresh the current collection to evict images\n"
579 "which properties have been changed\n"
580 "and don't match the current filters anymore."));
581 g_signal_connect(G_OBJECT(d->refresh), "clicked", G_CALLBACK(_refresh_collection_callback), NULL);
582 gtk_widget_set_name(d->refresh, "quick-filter-reload");
583 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->refresh), FALSE, FALSE, 0);
584
585 gchar *path = dt_accels_build_path(_("Lighttable/Actions"), _("Reload current collection"));
586 dt_accels_new_widget_shortcut(darktable.gui->accels, d->refresh, "activate",
587 darktable.gui->accels->lighttable_accels, path, GDK_KEY_r, GDK_CONTROL_MASK,
588 FALSE);
589 dt_free(path);
590
592
593 label = gtk_label_new(_("Include"));
594 gtk_box_pack_start(GTK_BOX(self->widget), label, FALSE, FALSE, 0);
595
596 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
597 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(hbox), FALSE, FALSE, 0);
598 gtk_widget_set_name(hbox, "quick-filter-ratings");
599
600 // star buttons
601 for(int k = 0; k < 7; k++)
602 {
603 if(k == 0)
604 {
606 gtk_widget_set_name(d->stars[k], "no-star-filter");
607 }
608 else if(k == 1)
609 {
611 gtk_widget_set_name(d->stars[k], "rejected-filter");
612 }
613 else
614 d->stars[k] = dtgtk_button_new(dtgtk_cairo_paint_star, k, NULL);
615
616 dt_gui_add_class(d->stars[k], "star");
617 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(d->stars[k]), FALSE, FALSE, 0);
618 g_signal_connect(G_OBJECT(d->stars[k]), "button-press-event", G_CALLBACK(_rating_clicked), self);
619
620 if(k == 1)
621 {
622 GtkWidget *spacer = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
623 dt_gui_add_class(spacer, "subsection");
624 gtk_box_pack_start(GTK_BOX(hbox), spacer, FALSE, FALSE, 0);
625 }
626 }
628
629 gtk_widget_set_tooltip_text(d->stars[0], _("Toggle filtering in/out unrated images (0 star)"));
630 gtk_widget_set_tooltip_text(d->stars[1], _("Toggle filtering in/out rejected images"));
631 gtk_widget_set_tooltip_text(d->stars[2], _("Toggle filtering in/out images rated 1 star"));
632 gtk_widget_set_tooltip_text(d->stars[3], _("Toggle filtering in/out images rated 2 stars"));
633 gtk_widget_set_tooltip_text(d->stars[4], _("Toggle filtering in/out images rated 3 stars"));
634 gtk_widget_set_tooltip_text(d->stars[5], _("Toggle filtering in/out images rated 4 stars"));
635 gtk_widget_set_tooltip_text(d->stars[6], _("Toggle filtering in/out images rated 5 stars"));
636
638
639 // colorlabels filter
640 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
641 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(hbox), FALSE, FALSE, 0);
642 gtk_widget_set_name(hbox, "quickfilters-colors");
643
646
647 for(int k = 0; k < DT_COLORLABELS_LAST + 1; k++)
648 {
649 d->colors[k] = dtgtk_button_new(dtgtk_cairo_paint_label_sel, col[k], NULL);
650 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(d->colors[k]), FALSE, FALSE, 0);
651 g_signal_connect(G_OBJECT(d->colors[k]), "button-press-event", G_CALLBACK(_colorlabel_clicked), self);
652 }
654
655 gtk_widget_set_tooltip_text(d->colors[0], _("Toggle filtering in/out images without color label"));
656 gtk_widget_set_tooltip_text(d->colors[1], _("Toggle filtering in/out images with red label"));
657 gtk_widget_set_tooltip_text(d->colors[2], _("Toggle filtering in/out images with yellow label"));
658 gtk_widget_set_tooltip_text(d->colors[3], _("Toggle filtering in/out images with green label"));
659 gtk_widget_set_tooltip_text(d->colors[4], _("Toggle filtering in/out images with blue label"));
660 gtk_widget_set_tooltip_text(d->colors[5], _("Toggle filtering in/out images with purple label"));
661
663
664 // changed filter
665 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
666 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(hbox), FALSE, FALSE, 0);
667 gtk_widget_set_name(hbox, "quickfilters-altered");
668
669 d->unaltered = dtgtk_button_new(dtgtk_cairo_paint_unaltered, 0, NULL);
670 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(d->unaltered), FALSE, FALSE, 0);
671 g_signal_connect(G_OBJECT(d->unaltered), "button-press-event", G_CALLBACK(_unaltered_clicked), self);
672 gtk_widget_set_tooltip_text(d->unaltered, _("Toggle filtering in/out unedited images"));
673
674 d->altered = dtgtk_button_new(dtgtk_cairo_paint_altered, 0, NULL);
675 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(d->altered), FALSE, FALSE, 0);
676 g_signal_connect(G_OBJECT(d->altered), "button-press-event", G_CALLBACK(_altered_clicked), self);
677 gtk_widget_set_tooltip_text(d->altered, _("Toggle filtering in/out edited images"));
678
680
682
683 // Culling mode
684 d->culling = gtk_toggle_button_new_with_label(_("Restrict to selection"));
685 gtk_widget_set_tooltip_text(d->culling, _("Restrict the current view to only selected pictures"));
686 g_signal_connect(G_OBJECT(d->culling), "toggled", G_CALLBACK(_culling_mode), (gpointer)self);
687 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->culling), FALSE, FALSE, 0);
688 gtk_widget_set_name(d->culling, "quickfilter-culling");
689
690 path = dt_accels_build_path(_("Lighttable/Actions"), _("Toggle culling mode"));
691 dt_accels_new_widget_shortcut(darktable.gui->accels, d->culling, "activate",
692 darktable.gui->accels->lighttable_accels, path, GDK_KEY_s, GDK_CONTROL_MASK,
693 FALSE);
694 dt_free(path);
695
697
698 label = gtk_label_new(_("Sort by"));
699 gtk_box_pack_start(GTK_BOX(self->widget), label, FALSE, FALSE, 0);
700
701 /* sort combobox */
703
704 d->sort = gtk_combo_box_text_new();
705
706 for(int i = 0; i < NB_ITEMS; i++)
707 gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(d->sort), NULL, _(_sort_names[i]));
708
709 gtk_combo_box_set_active(GTK_COMBO_BOX(d->sort ), _filter_get_items(sort));
710 g_signal_connect(G_OBJECT(d->sort), "changed", G_CALLBACK(_lib_filter_sort_combobox_changed), (gpointer)self);
711 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->sort), FALSE, FALSE, 0);
712 gtk_widget_set_name(d->sort, "quick-filter-sort");
713
714 /* reverse order checkbutton */
718 CPF_DIRECTION_DOWN, NULL);
719 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->reverse), FALSE, FALSE, 0);
720 dt_gui_add_class(d->reverse, "dt_ignore_fg_state");
721
722 /* select the last value and connect callback */
723 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(d->reverse),
725 g_signal_connect(G_OBJECT(d->reverse), "toggled", G_CALLBACK(_lib_filter_reverse_button_changed),
726 (gpointer)self);
727
729
730 // text filter
731 d->text = gtk_search_entry_new();
733 gtk_widget_set_hexpand(d->text, TRUE);
734 dt_gui_add_class(GTK_WIDGET(d->text), "menu-text-entry");
736 gtk_entry_set_text(GTK_ENTRY(d->text), text);
737 gtk_entry_set_placeholder_text(GTK_ENTRY(d->text), _("Search an image..."));
738 dt_free(text);
739 g_signal_connect(G_OBJECT(d->text), "search-changed", G_CALLBACK(_text_entry_changed), self);
740 g_signal_connect(G_OBJECT(d->text), "stop-search", G_CALLBACK(_reset_text_entry), self);
741 gtk_entry_set_width_chars(GTK_ENTRY(d->text), 24);
742 gtk_widget_set_tooltip_text(d->text,
743 /* xgettext:no-c-format */
744 _("filter by text from images metadata, tags, file path and name"
745 /* xgettext:no-c-format */
746 "\n`%' is the wildcard character"
747 /* xgettext:no-c-format */
748 "\nby default start and end wildcards are auto-applied"
749 /* xgettext:no-c-format */
750 "\nstarting or ending with a double quote disables the corresponding wildcard"
751 /* xgettext:no-c-format */
752 "\nis dimmed during the search execution"));
753 //dt_gui_add_class(d->text, "dt_transparent_background");
754 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->text), TRUE, TRUE, 0);
755 gtk_widget_set_name(d->text, "quickfilter-search-box");
756
757 dt_accels_new_lighttable_action(_focus_search_action, self, N_("Lighttable/Actions"), N_("Search a picture"),
758 GDK_KEY_f, GDK_CONTROL_MASK, _("Focuses the control"));
759
761
763 G_CALLBACK(_lib_filter_images_order_change), self);
764
765 // context menu
766 d->menu = gtk_menu_new();
767
768 GtkWidget *first_entry = gtk_menu_item_new_with_label(_("Select all filters"));
769 gtk_menu_shell_append(GTK_MENU_SHELL(d->menu), first_entry);
770 g_signal_connect(G_OBJECT(first_entry), "activate", G_CALLBACK(_select_all_callback), self);
771 path = dt_accels_build_path(_("Lighttable/Actions"), _("Select all filters"));
772 dt_accels_new_widget_shortcut(darktable.gui->accels, first_entry, "activate",
774 FALSE);
775 dt_free(path);
776
777 GtkWidget *second_entry = gtk_menu_item_new_with_label(_("Deselect all filters"));
778 gtk_menu_shell_append(GTK_MENU_SHELL(d->menu), second_entry);
779 g_signal_connect(G_OBJECT(second_entry), "activate", G_CALLBACK(_select_none_callback), self);
780 path = dt_accels_build_path(_("Lighttable/Actions"), _("Deselect all filters"));
781 dt_accels_new_widget_shortcut(darktable.gui->accels, second_entry, "activate",
783 FALSE);
784 dt_free(path);
785
786 gtk_widget_show_all(d->menu);
787}
788
790{
791 gchar *path = dt_accels_build_path(_("Lighttable/Actions"), _("Reload current collection"));
793 dt_free(path);
794
795 path = dt_accels_build_path(_("Lighttable/Actions"), _("Toggle culling mode"));
797 dt_free(path);
798
799 path = dt_accels_build_path(_("Lighttable/Actions"), _("Select all filters"));
801 dt_free(path);
802
803 path = dt_accels_build_path(_("Lighttable/Actions"), _("Deselect all filters"));
805 dt_free(path);
806
809 dt_free(self->data);
810}
811
812/* save the images order if the first collect filter is on tag*/
814{
817 {
818 const uint32_t sort = items[gtk_combo_box_get_active(GTK_COMBO_BOX(d->sort))];
819 const gboolean descending = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(d->reverse));
821 }
822}
823
824static void _lib_filter_images_order_change(gpointer instance, const int order, dt_lib_module_t *self)
825{
827 gtk_combo_box_set_active(GTK_COMBO_BOX(d->sort), _filter_get_items(order & ~DT_COLLECTION_ORDER_FLAG));
828 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(d->reverse), order & DT_COLLECTION_ORDER_FLAG);
829}
830
831static void _lib_filter_reverse_button_changed(GtkDarktableToggleButton *widget, gpointer user_data)
832{
833 const gboolean reverse = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
834
835 if(reverse)
837 else
839 gtk_widget_queue_draw(GTK_WIDGET(widget));
840
841 /* update last settings */
843
844 /* save the images order */
845 _lib_filter_set_tag_order(user_data);
846
847 /* update query and view */
849}
850
851static void _lib_filter_sort_combobox_changed(GtkWidget *widget, gpointer user_data)
852{
853 /* update the ui last settings */
854 dt_collection_set_sort(darktable.collection, items[gtk_combo_box_get_active(GTK_COMBO_BOX(widget))], -1);
855
856 /* save the images order */
857 _lib_filter_set_tag_order(user_data);
858
859 /* update the query and view */
861}
862
864{
865 /* sometimes changes */
867
868 /* updates query */
870}
871
872// clang-format off
873// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
874// vim: shiftwidth=2 expandtab tabstop=2 cindent
875// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
876// clang-format on
void dt_accels_remove_shortcut(dt_accels_t *accels, const char *path)
Remove the shortcut object identified by path and all its accels.
gchar * dt_accels_build_path(const gchar *scope, const gchar *feature)
void dt_accels_new_widget_shortcut(dt_accels_t *accels, GtkWidget *widget, const gchar *signal, GtkAccelGroup *accel_group, const gchar *accel_path, guint key_val, GdkModifierType accel_mods, const gboolean lock)
Register a new shortcut for a widget, setting up its path, default keys and accel group....
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dtgtk_button_set_active(GtkDarktableButton *button, gboolean active)
Definition button.c:176
GtkWidget * dtgtk_button_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
Definition button.c:134
gboolean dtgtk_button_get_active(GtkDarktableButton *button)
Definition button.c:185
#define DTGTK_BUTTON(obj)
Definition button.h:39
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
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_culling_mode_to_selection()
void dt_collection_set_query_flags(const dt_collection_t *collection, dt_collection_query_flags_t flags)
Definition collection.c:588
void dt_collection_set_text_filter(const dt_collection_t *collection, char *text_filter)
Definition collection.c:576
char * dt_collection_get_text_filter(const dt_collection_t *collection)
Definition collection.c:571
gboolean dt_collection_get_sort_descending(const dt_collection_t *collection)
Definition collection.c:652
void dt_collection_set_filter_flags(const dt_collection_t *collection, dt_collection_filter_flag_t flags)
Definition collection.c:565
dt_collection_filter_flag_t dt_collection_get_filter_flags(const dt_collection_t *collection)
Definition collection.c:560
dt_collection_sort_t dt_collection_get_sort_field(const dt_collection_t *collection)
Definition collection.c:647
void dt_collection_set_sort(const dt_collection_t *collection, dt_collection_sort_t sort, gboolean reverse)
Definition collection.c:637
dt_collection_properties_t
Definition collection.h:107
@ DT_COLLECTION_PROP_RATING
Definition collection.h:136
@ DT_COLLECTION_PROP_SORT
Definition collection.h:143
@ DT_COLLECTION_PROP_COLORLABEL
Definition collection.h:128
@ DT_COLLECTION_PROP_UNDEF
Definition collection.h:142
#define DT_COLLECTION_ORDER_FLAG
Definition collection.h:103
#define COLLECTION_QUERY_FULL
Definition collection.h:63
dt_collection_filter_flag_t
Definition collection.h:66
@ COLLECTION_FILTER_ALTERED
Definition collection.h:68
@ COLLECTION_FILTER_UNALTERED
Definition collection.h:69
@ COLLECTION_FILTER_GREEN
Definition collection.h:79
@ COLLECTION_FILTER_NONE
Definition collection.h:67
@ COLLECTION_FILTER_2_STAR
Definition collection.h:73
@ COLLECTION_FILTER_MAGENTA
Definition collection.h:81
@ COLLECTION_FILTER_0_STAR
Definition collection.h:71
@ COLLECTION_FILTER_1_STAR
Definition collection.h:72
@ COLLECTION_FILTER_BLUE
Definition collection.h:80
@ COLLECTION_FILTER_5_STAR
Definition collection.h:76
@ COLLECTION_FILTER_YELLOW
Definition collection.h:78
@ COLLECTION_FILTER_ALL
Definition collection.h:83
@ COLLECTION_FILTER_REJECTED
Definition collection.h:70
@ COLLECTION_FILTER_4_STAR
Definition collection.h:75
@ COLLECTION_FILTER_3_STAR
Definition collection.h:74
@ COLLECTION_FILTER_RED
Definition collection.h:77
@ COLLECTION_FILTER_WHITE
Definition collection.h:82
@ DT_COLLECTION_CHANGE_RELOAD
Definition collection.h:151
dt_collection_sort_t
Definition collection.h:87
@ DT_COLLECTION_SORT_EXPORT_TIMESTAMP
Definition collection.h:93
@ DT_COLLECTION_SORT_IMPORT_TIMESTAMP
Definition collection.h:91
@ DT_COLLECTION_SORT_DATETIME
Definition collection.h:90
@ DT_COLLECTION_SORT_GROUP
Definition collection.h:98
@ DT_COLLECTION_SORT_FILENAME
Definition collection.h:89
@ DT_COLLECTION_SORT_RATING
Definition collection.h:95
@ DT_COLLECTION_SORT_PATH
Definition collection.h:99
@ DT_COLLECTION_SORT_TITLE
Definition collection.h:100
@ DT_COLLECTION_SORT_CHANGE_TIMESTAMP
Definition collection.h:92
@ DT_COLLECTION_SORT_NONE
Definition collection.h:88
@ DT_COLLECTION_SORT_PRINT_TIMESTAMP
Definition collection.h:94
@ DT_COLLECTION_SORT_ID
Definition collection.h:96
@ DT_COLLECTION_SORT_COLOR
Definition collection.h:97
@ DT_COLORLABELS_PURPLE
Definition colorlabels.h:45
@ DT_COLORLABELS_GREEN
Definition colorlabels.h:43
@ DT_COLORLABELS_YELLOW
Definition colorlabels.h:42
@ DT_COLORLABELS_BLUE
Definition colorlabels.h:44
@ DT_COLORLABELS_LAST
Definition colorlabels.h:46
@ DT_COLORLABELS_RED
Definition colorlabels.h:41
char * name
void dt_control_set_mouse_over_id(int32_t value)
Definition control.c:931
void dt_control_set_keyboard_over_id(int32_t value)
Definition control.c:957
darktable_t darktable
Definition darktable.c:181
#define DT_MODULE(MODVER)
Definition darktable.h:140
#define dt_free(ptr)
Definition darktable.h:456
static double dt_get_wtime(void)
Definition darktable.h:914
static gboolean dt_modifier_is(const GdkModifierType state, const GdkModifierType desired_modifier_mask)
Definition darktable.h:893
void dtgtk_cairo_paint_refresh(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_label_sel(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_sortby(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_reject(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_star(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_unaltered(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_altered(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_unratestar(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
@ CPF_DIRECTION_UP
Definition dtgtk/paint.h:61
@ CPF_DIRECTION_RIGHT
Definition dtgtk/paint.h:64
@ CPF_DIRECTION_DOWN
Definition dtgtk/paint.h:62
static gboolean _text_entry_changed_wait(gpointer user_data)
Definition filter.c:220
static void _launch_text_query(dt_lib_module_t *self)
Definition filter.c:256
static char * _encode_text_filter(const char *entry)
Definition filter.c:170
static void _reset_text_filter(dt_lib_module_t *self)
Definition filter.c:273
const dt_collection_filter_flag_t colors[6]
Definition filter.c:295
static gboolean _show_popover_menu(dt_lib_module_t *self, GtkWidget *w)
Definition filter.c:545
void _widget_align_left(GtkWidget *widget)
Definition filter.c:439
static void _culling_mode(GtkWidget *widget, gpointer data)
Definition filter.c:415
static int _filter_get_items(const dt_collection_sort_t sort)
Definition filter.c:127
const dt_collection_filter_flag_t ratings[7]
Definition filter.c:448
gboolean _focus_search_action(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval, GdkModifierType modifier, gpointer data)
Definition filter.c:286
static void _update_altered_filters(dt_lib_module_t *self)
Definition filter.c:356
static gboolean _rating_clicked(GtkWidget *w, GdkEventButton *e, dt_lib_module_t *self)
Definition filter.c:482
const dt_collection_sort_t items[]
Definition filter.c:95
static void _lib_filter_images_order_change(gpointer instance, int order, dt_lib_module_t *self)
Definition filter.c:824
static const char * _sort_names[]
Definition filter.c:113
void gui_cleanup(dt_lib_module_t *self)
Definition filter.c:789
static void _reset_text_entry(GtkButton *button, dt_lib_module_t *self)
Definition filter.c:280
static void _refresh_collection_callback(GtkButton *button, gpointer user_data)
Definition filter.c:434
static void _update_colors_filter(dt_lib_module_t *self)
Definition filter.c:318
static char * _decode_text_filter(const char *text)
Definition filter.c:194
#define NB_ITEMS
Definition filter.c:110
static void _lib_filter_sort_combobox_changed(GtkWidget *widget, gpointer user_data)
Definition filter.c:851
static gboolean _colorlabel_clicked(GtkWidget *w, GdkEventButton *e, dt_lib_module_t *self)
Definition filter.c:326
static void _update_rating_filter(dt_lib_module_t *self)
Definition filter.c:459
static void _select_all_callback(GtkWidget *widget, dt_lib_module_t *self)
Definition filter.c:526
static void _select_none_callback(GtkWidget *widget, dt_lib_module_t *self)
Definition filter.c:535
uint32_t container(dt_lib_module_t *self)
Definition filter.c:148
static void _insert_subsection_sep(dt_lib_module_t *self)
Definition filter.c:558
void gui_init(dt_lib_module_t *self)
Definition filter.c:565
int position()
Definition filter.c:158
static gboolean _unaltered_clicked(GtkWidget *w, GdkEventButton *e, dt_lib_module_t *self)
Definition filter.c:390
const char ** views(dt_lib_module_t *self)
Definition filter.c:142
int expandable(dt_lib_module_t *self)
Definition filter.c:153
static void _set_widget_dimmed(GtkWidget *widget, const gboolean dimmed)
Definition filter.c:163
static void _dtgtk_button_set_active(GtkWidget *w, gboolean active)
Definition filter.c:305
static void _insert_section_sep(dt_lib_module_t *self)
Definition filter.c:552
static void _lib_filter_update_query(dt_lib_module_t *self, dt_collection_properties_t changed_property)
Definition filter.c:863
static gboolean _altered_clicked(GtkWidget *w, GdkEventButton *e, dt_lib_module_t *self)
Definition filter.c:365
static void _lib_filter_set_tag_order(dt_lib_module_t *self)
Definition filter.c:813
static void _text_entry_changed(GtkEntry *entry, dt_lib_module_t *self)
Definition filter.c:268
static void _lib_filter_reverse_button_changed(GtkDarktableToggleButton *widget, gpointer user_data)
Definition filter.c:831
void dt_gui_menu_popup(GtkMenu *menu, GtkWidget *button, GdkGravity widget_anchor, GdkGravity menu_anchor)
Definition gtk.c:2953
void dt_gui_remove_class(GtkWidget *widget, const gchar *class_name)
Definition gtk.c:143
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....
Definition gtk.c:3225
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
Definition gtk.c:133
#define dt_accels_new_lighttable_action(a, b, c, d, e, f, g)
Definition gtk.h:432
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
const float v
float *const restrict const size_t k
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
int32_t dt_selection_get_first_id(struct dt_selection_t *selection)
Definition selection.c:69
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
Definition signal.h:368
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:347
@ DT_SIGNAL_IMAGES_ORDER_CHANGE
This signal is raised to request image order change.
Definition signal.h:150
@ DT_SIGNAL_SELECTION_CHANGED
This signal is raised when the selection is changed no param, no returned value.
Definition signal.h:127
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
Definition signal.h:357
struct _GtkWidget GtkWidget
Definition splash.h:29
struct dt_gui_gtk_t * gui
Definition darktable.h:775
struct dt_collection_t * collection
Definition darktable.h:781
struct dt_selection_t * selection
Definition darktable.h:782
struct dt_control_signal_t * signals
Definition darktable.h:774
struct dt_bauhaus_t * bauhaus
Definition darktable.h:778
GtkAccelGroup * lighttable_accels
GdkRGBA color_fg
Definition bauhaus.h:277
dt_collection_params_t params
Definition collection.h:177
unsigned int tagid
Definition collection.h:176
dt_accels_t * accels
Definition gtk.h:194
dt_ui_t * ui
Definition gtk.h:164
gboolean culling_mode
Definition gtk.h:187
GModule *void * data
Definition lib.h:80
GtkWidget * widget
Definition lib.h:84
GtkWidget * reverse
Definition filter.c:68
GtkWidget * culling
Definition filter.c:71
GtkWidget * comparator
Definition filter.c:66
GtkWidget * menu
Definition filter.c:75
GtkWidget * refresh
Definition filter.c:72
GtkWidget * unaltered
Definition filter.c:74
GtkWidget * sort
Definition filter.c:67
double last_key_time
Definition filter.c:77
GtkWidget * altered
Definition filter.c:73
GtkWidget * text
Definition filter.c:69
dt_thumbtable_t * thumbtable_lighttable
void dt_tag_set_tag_order_by_id(const uint32_t tagid, const uint32_t sort, const gboolean descending)
Definition tags.c:1911
void dt_thumbtable_reset_collection(dt_thumbtable_t *table)
void dtgtk_togglebutton_set_paint(GtkDarktableToggleButton *button, DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
GtkWidget * dtgtk_togglebutton_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
#define DTGTK_TOGGLEBUTTON(obj)
@ DT_UI_CONTAINER_PANEL_TOP_SECOND_ROW