diff --git a/src/common/collection.c b/src/common/collection.c index db6cc11df846..800c39e2eafb 100644 --- a/src/common/collection.c +++ b/src/common/collection.c @@ -656,6 +656,8 @@ const char *dt_collection_name_untranslated(const dt_collection_properties_t pro return N_("group"); case DT_COLLECTION_PROP_DUPLICATES: return N_("duplicates"); + case DT_COLLECTION_PROP_DIMENSIONS: + return N_("image dimensions"); case DT_COLLECTION_PROP_LOCAL_COPY: return N_("local copy"); case DT_COLLECTION_PROP_MODULE: @@ -1600,10 +1602,22 @@ static gchar *get_query_string(const dt_collection_properties_t property, const ("(mi.version > (SELECT MIN(version) FROM main.images" " WHERE film_id = mi.film_id AND filename = mi.filename)) "); } - else // by default, we select all the images + break; + + case DT_COLLECTION_PROP_DIMENSIONS: // image dimensions + query = g_strdup("("); + // handle the possibility of multiple values + elems = _strsplit_quotes(escaped_text, ",", -1); + for(int i = 0; i < g_strv_length(elems); i++) { - query = g_strdup("1 = 1"); + gchar *dims = _add_wildcards(elems[i]); + dt_util_str_cat(&query, + "%smi.width || 'x' || mi.height LIKE '%%%s%%'", + i>0?" OR ":"", dims); + g_free(dims); } + g_strfreev(elems); + dt_util_str_cat(&query, ")"); break; case DT_COLLECTION_PROP_ASPECT_RATIO: // aspect ratio diff --git a/src/common/collection.h b/src/common/collection.h index f9965163e2a5..d0f54315db3e 100644 --- a/src/common/collection.h +++ b/src/common/collection.h @@ -123,6 +123,8 @@ typedef enum dt_collection_properties_t DT_COLLECTION_PROP_MONTH, + DT_COLLECTION_PROP_DIMENSIONS, + // all new collection types need to be added before DT_COLLECTION_PROP_LAST, // which separates actual collection types from special flag values DT_COLLECTION_PROP_LAST, diff --git a/src/libs/collect.c b/src/libs/collect.c index e0306005bd89..0d2127f1bc77 100644 --- a/src/libs/collect.c +++ b/src/libs/collect.c @@ -4369,7 +4369,9 @@ void init(struct dt_lib_module_t *self) luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_LOCAL_COPY); luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_MODULE); luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_ORDER); + luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_DUPLICATES); luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_MONTH); + luaA_enum_value(L, dt_collection_properties_t, DT_COLLECTION_PROP_DIMENSIONS); } #endif #undef MAX_RULES diff --git a/src/libs/filtering.c b/src/libs/filtering.c index 978a4d869d08..4a372428a183 100644 --- a/src/libs/filtering.c +++ b/src/libs/filtering.c @@ -242,6 +242,7 @@ static _filter_t filters[] { DT_COLLECTION_PROP_EXPOSURE_BIAS, _exposure_bias_widget_init, _exposure_bias_update }, { DT_COLLECTION_PROP_GROUP_ID, _misc_widget_init, _misc_update }, { DT_COLLECTION_PROP_DUPLICATES, _duplicates_widget_init, _duplicates_update }, + { DT_COLLECTION_PROP_DIMENSIONS, _misc_widget_init, _misc_update }, { DT_COLLECTION_PROP_LOCAL_COPY, _local_copy_widget_init, _local_copy_update }, { DT_COLLECTION_PROP_HISTORY, _history_widget_init, _history_update }, { DT_COLLECTION_PROP_ORDER, _module_order_widget_init, _module_order_update }, @@ -921,6 +922,7 @@ static gboolean _rule_show_popup(GtkWidget *widget, dt_lib_filtering_rule_t *rul ADD_COLLECT_ENTRY(spop, DT_COLLECTION_PROP_FLASH); ADD_COLLECT_ENTRY(spop, DT_COLLECTION_PROP_EXPOSURE_PROGRAM); ADD_COLLECT_ENTRY(spop, DT_COLLECTION_PROP_METERING_MODE); + ADD_COLLECT_ENTRY(spop, DT_COLLECTION_PROP_DIMENSIONS); _popup_add_item(spop, _("darktable"), 0, TRUE, NULL, NULL, self, 0.0); ADD_COLLECT_ENTRY(spop, DT_COLLECTION_PROP_GROUP_ID); @@ -982,6 +984,7 @@ static void _populate_rules_combo(GtkWidget *w) ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_FLASH); ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_EXPOSURE_PROGRAM); ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_METERING_MODE); + ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_DIMENSIONS); dt_bauhaus_combobox_add_section(w, _("darktable")); ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_GROUP_ID); @@ -1648,6 +1651,7 @@ static void _topbar_populate_rules_combo(GtkWidget *w, dt_lib_filtering_t *d) ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_FLASH); ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_EXPOSURE_PROGRAM); ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_METERING_MODE); + ADD_COLLECT_ENTRY(DT_COLLECTION_PROP_DIMENSIONS); // if we have not added any entry, remove the section if(nb == dt_bauhaus_combobox_length(w)) dt_bauhaus_combobox_remove_at(w, nb - 1); diff --git a/src/libs/filters/misc.c b/src/libs/filters/misc.c index 2b6172bc932d..94558b966b2a 100644 --- a/src/libs/filters/misc.c +++ b/src/libs/filters/misc.c @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2024 darktable developers. + Copyright (C) 2024-2026 darktable developers. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ This file implements the necessary routines for all text baseed filters for the filtering module */ +#include "common/collection.h" typedef struct _widgets_misc_t { dt_lib_filtering_rule_t *rule; @@ -113,6 +114,10 @@ void _misc_tree_update(_widgets_misc_t *misc) table = g_strdup("metering_mode"); tooltip = g_strdup(_("no metering mode defined")); } + else if(misc->prop == DT_COLLECTION_PROP_DIMENSIONS) + { + tooltip = g_strdup(_("no image dimensions defined")); + } // SQL if(misc->prop == DT_COLLECTION_PROP_CAMERA) @@ -155,6 +160,18 @@ void _misc_tree_update(_widgets_misc_t *misc) d->last_where_ext); // clang-format on } + else if(misc->prop == DT_COLLECTION_PROP_DIMENSIONS) + { + // clang-format off + g_snprintf(query, sizeof(query), + "SELECT mi.width || 'x' || mi.height AS dim, COUNT(*) AS count" + " FROM main.images AS mi" + " WHERE %s" + " GROUP BY dim" + " ORDER BY dim", + d->last_where_ext); + // clang-format on + } else // white balance, flash, exposure program, metering mode { // clang-format off @@ -449,6 +466,17 @@ static void _misc_widget_init(dt_lib_filtering_rule_t *rule, "multiple values can be separated by ','\n" "\nright-click to get existing group ids")); } + else if(prop == DT_COLLECTION_PROP_DIMENSIONS) + { + name = g_strdup(_("image dimensions")); + tooltip = g_strdup(_("enter the image dimensions to search.\n" + "use the format widthxheight, i.e.\n" + "'6000x4000' for a full match,\n" + "'6000x' for width only,\n" + "'x4000' for height only.\n" + "multiple values can be separated by ','\n" + "\nright-click to get existing image dimensions")); + } gtk_entry_set_placeholder_text(GTK_ENTRY(misc->name), name); gtk_widget_set_tooltip_text(misc->name, tooltip);