Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
gui/actions/image.c
Go to the documentation of this file.
1/*
2 This file is part of the Ansel project.
3 Copyright (C) 2023, 2025 Aurélien PIERRE.
4 Copyright (C) 2023 Luca Zulberti.
5
6 Ansel is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Ansel is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
18*/
19#include "gui/actions/menu.h"
20#include "common/grouping.h"
21#include "common/colorlabels.h"
22#include "common/ratings.h"
23#include "control/control.h"
24#include "common/collection.h"
25
26static gboolean rotate_counterclockwise_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
27{
29 return TRUE;
30}
31
32static gboolean rotate_clockwise_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
33{
35 return TRUE;
36}
37
38static gboolean reset_rotation_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
39{
41 return TRUE;
42}
43
46static gboolean group_images_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
47{
48 GList *imgs = NULL;
49 sqlite3_stmt *stmt;
50 int32_t new_group_id = UNKNOWN_IMAGE;
51 DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT imgid FROM main.selected_images", -1, &stmt,
52 NULL);
53 while(sqlite3_step(stmt) == SQLITE_ROW)
54 {
55 int id = sqlite3_column_int(stmt, 0);
56
57 // The new group leader will be the first image in the selection
58 if(new_group_id == UNKNOWN_IMAGE) new_group_id = id;
59
60 dt_grouping_add_to_group(new_group_id, id);
61
62 imgs = g_list_prepend(imgs, GINT_TO_POINTER(id));
63 }
64 sqlite3_finalize(stmt);
66 return TRUE;
67}
68
70static gboolean ungroup_images_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
71{
72 GList *imgs = NULL;
73 sqlite3_stmt *stmt;
74 DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT imgid FROM main.selected_images", -1,
75 &stmt, NULL);
76 while(sqlite3_step(stmt) == SQLITE_ROW)
77 {
78 const int id = sqlite3_column_int(stmt, 0);
79 const int new_group_id = dt_grouping_remove_from_group(id);
80 if(new_group_id != -1)
81 {
82 // new_group_id == -1 if image to be ungrouped was a single image and no change to any group was made
83 imgs = g_list_prepend(imgs, GINT_TO_POINTER(id));
84 }
85 }
86 sqlite3_finalize(stmt);
87 if(!IS_NULL_PTR(imgs))
88 {
90 g_list_reverse(imgs));
92 }
93 return TRUE;
94}
95
96/* Those operations are dangerous, don't allow them in darkroom aka outside of selection */
97
98static gboolean _colorlabels_callback(int color)
99{
100 GList *imgs = dt_act_on_get_images();
102 g_list_free(imgs);
103 return TRUE;
104}
105
106static gboolean _rating_callback(int value)
107{
108 GList *imgs = dt_act_on_get_images();
110 g_list_free(imgs);
111 return TRUE;
112}
113
114static gboolean red_label_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
115{
117 return TRUE;
118}
119
120static gboolean yellow_label_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
121{
123 return TRUE;
124}
125
126static gboolean green_label_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
127{
129 return TRUE;
130}
131
132static gboolean blue_label_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
133{
135 return TRUE;
136}
137
138static gboolean magenta_label_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
139{
141 return TRUE;
142}
143
144static gboolean reset_label_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
145{
147 return TRUE;
148}
149
150static gboolean rating_one_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
151{
153 return TRUE;
154}
155
156static gboolean rating_two_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
157{
159 return TRUE;
160}
161
162static gboolean rating_three_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
163{
165 return TRUE;
166}
167
168static gboolean rating_four_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
169{
171 return TRUE;
172}
173
174static gboolean rating_five_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
175{
177 return TRUE;
178}
179
180static gboolean rating_reset_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
181{
183 return TRUE;
184}
185
186static gboolean rating_reject_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
187{
189 return TRUE;
190}
191
192/* Rotation has a module in darkroom, don't support it there */
194{
195 return has_active_images() && _is_lighttable();
196}
197
199
200void append_image(GtkWidget **menus, GList **lists, const dt_menus_t index)
201{
202 /* Rotation */
203 add_top_submenu_entry(menus, lists, _("Rotate"), index);
204 GtkWidget *parent = get_last_widget(lists);
205
206 add_sub_sub_menu_entry(menus, parent, lists, _("90\302\260 counter-clockwise"), index, NULL,
208
209 add_sub_sub_menu_entry(menus, parent, lists, _("90\302\260 clockwise"), index, NULL,
210 rotate_clockwise_callback, NULL, NULL, _can_be_rotated, 0, 0);
211
213
214 add_sub_sub_menu_entry(menus, parent, lists, _("Reset rotation"), index, NULL,
215 reset_rotation_callback, NULL, NULL, _can_be_rotated, 0, 0);
216
217 /* Color labels */
218 add_top_submenu_entry(menus, lists, _("Color labels"), index);
219 parent = get_last_widget(lists);
220
221 add_sub_sub_menu_entry(menus, parent, lists, _("<span foreground='#BB2222'>\342\254\244</span> Red"), index, NULL,
222 red_label_callback, NULL, NULL, has_active_images, GDK_KEY_F1, 0);
223
224 add_sub_sub_menu_entry(menus, parent, lists, _("<span foreground='#BBBB22'>\342\254\244</span> Yellow"), index, NULL,
225 yellow_label_callback, NULL, NULL, has_active_images, GDK_KEY_F2, 0);
226
227 add_sub_sub_menu_entry(menus, parent, lists, _("<span foreground='#22BB22'>\342\254\244</span> Green"), index, NULL,
228 green_label_callback, NULL, NULL, has_active_images, GDK_KEY_F3, 0);
229
230 add_sub_sub_menu_entry(menus, parent, lists, _("<span foreground='#2222BB'>\342\254\244</span> Blue"), index, NULL,
231 blue_label_callback, NULL, NULL, has_active_images, GDK_KEY_F4, 0);
232
233 add_sub_sub_menu_entry(menus, parent, lists, _("<span foreground='#BB22BB'>\342\254\244</span> Purple"), index, NULL,
234 magenta_label_callback, NULL, NULL, has_active_images, GDK_KEY_F5, 0);
235
237
238 add_sub_sub_menu_entry(menus, parent, lists, _("<span foreground='#BBBBBB'>\342\254\244</span> Clear labels"), index, NULL,
239 reset_label_callback, NULL, NULL, has_active_images, GDK_KEY_F6, 0);
240
241 /* Ratings */
242 add_top_submenu_entry(menus, lists, _("Ratings"), index);
243 parent = get_last_widget(lists);
244
245 add_sub_sub_menu_entry(menus, parent, lists, _("Reject"), index, NULL,
246 rating_reject_callback, NULL, NULL, has_active_images, GDK_KEY_r, 0);
247
248 add_sub_sub_menu_entry(menus, parent, lists, _("\342\230\205"), index, NULL,
249 rating_one_callback, NULL, NULL, has_active_images, GDK_KEY_1, 0);
250
251 add_sub_sub_menu_entry(menus, parent, lists, _("\342\230\205\342\230\205"), index, NULL,
252 rating_two_callback, NULL, NULL, has_active_images, GDK_KEY_2, 0);
253
254 add_sub_sub_menu_entry(menus, parent, lists, _("\342\230\205\342\230\205\342\230\205"), index, NULL,
255 rating_three_callback, NULL, NULL, has_active_images, GDK_KEY_3, 0);
256
257 add_sub_sub_menu_entry(menus, parent, lists, _("\342\230\205\342\230\205\342\230\205\342\230\205"), index, NULL,
258 rating_four_callback, NULL, NULL, has_active_images, GDK_KEY_4, 0);
259
260 add_sub_sub_menu_entry(menus, parent, lists, _("\342\230\205\342\230\205\342\230\205\342\230\205\342\230\205"), index, NULL,
261 rating_five_callback, NULL, NULL, has_active_images, GDK_KEY_5, 0);
262
264
265 add_sub_sub_menu_entry(menus, parent, lists, _("Clear rating"), index, NULL,
266 rating_reset_callback, NULL, NULL, has_active_images, GDK_KEY_0, 0);
267
268 add_menu_separator(menus[index]);
269
270 /* Reload EXIF */
271 add_sub_menu_entry(menus, lists, _("Reload EXIF from file"), index, NULL, GET_ACCEL_WRAPPER(dt_control_refresh_exif)
272 , NULL, NULL,
273 has_active_images, 0, 0);
274
275 add_menu_separator(menus[index]);
276
277 /* Group/Ungroup */
278 add_sub_menu_entry(menus, lists, _("Group images"), index, NULL, group_images_callback, NULL, NULL,
279 has_active_images, GDK_KEY_g, GDK_CONTROL_MASK);
280
281 add_sub_menu_entry(menus, lists, _("Ungroup images"), index, NULL, ungroup_images_callback, NULL, NULL,
282 has_active_images, GDK_KEY_g, GDK_CONTROL_MASK | GDK_SHIFT_MASK);
283}
GList * dt_act_on_get_images()
Definition act_on.c:39
#define TRUE
Definition ashift_lsd.c:162
void dt_collection_update_query(const dt_collection_t *collection, dt_collection_change_t query_change, dt_collection_properties_t changed_property, GList *list)
@ DT_COLLECTION_PROP_GROUPING
Definition collection.h:130
@ DT_COLLECTION_CHANGE_RELOAD
Definition collection.h:151
void dt_colorlabels_toggle_label_on_list(GList *list, const int color, const gboolean undo_on)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_control_queue_redraw_center()
request redraw of center window. This redraws the center view within a gdk critical section to preven...
Definition control.c:861
void dt_control_refresh_exif()
void dt_control_flip_images(const int32_t cw)
darktable_t darktable
Definition darktable.c:181
#define UNKNOWN_IMAGE
Definition darktable.h:182
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
sqlite3 * dt_database_get(const dt_database_t *db)
Definition database.c:3646
#define DT_DEBUG_SQLITE3_PREPARE_V2(a, b, c, d, e)
Definition debug.h:107
int dt_grouping_remove_from_group(const int32_t image_id)
Definition grouping.c:59
void dt_grouping_add_to_group(const int32_t group_id, const int32_t image_id)
Definition grouping.c:48
static gboolean green_label_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
static gboolean group_images_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
static gboolean rating_four_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
static gboolean rating_reset_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
static gboolean _colorlabels_callback(int color)
static gboolean reset_rotation_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
void append_image(GtkWidget **menus, GList **lists, const dt_menus_t index)
static gboolean _rating_callback(int value)
static gboolean blue_label_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
gboolean _can_be_rotated()
static gboolean rotate_clockwise_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
static gboolean reset_label_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
static gboolean rating_two_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
static gboolean yellow_label_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
static gboolean ungroup_images_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
static gboolean rating_one_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
static gboolean magenta_label_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
static gboolean rating_reject_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
static gboolean rotate_counterclockwise_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
static gboolean red_label_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
static gboolean rating_five_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
static gboolean rating_three_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
void add_sub_sub_menu_entry(GtkWidget **menus, GtkWidget *parent, GList **lists, const gchar *label, const dt_menus_t index, void *data, gboolean(*action_callback)(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data), gboolean(*checked_callback)(GtkWidget *widget), gboolean(*active_callback)(GtkWidget *widget), gboolean(*sensitive_callback)(GtkWidget *widget), guint key_val, GdkModifierType mods)
Definition menu.c:584
gboolean _is_lighttable()
Definition menu.c:641
GtkWidget * get_last_widget(GList **list)
Definition menu.c:618
void add_sub_menu_entry(GtkWidget **menus, GList **lists, const gchar *label, const dt_menus_t index, void *data, gboolean(*action_callback)(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data), gboolean(*checked_callback)(GtkWidget *widget), gboolean(*active_callback)(GtkWidget *widget), gboolean(*sensitive_callback)(GtkWidget *widget), guint key_val, GdkModifierType mods)
Definition menu.c:542
void add_sub_menu_separator(GtkWidget *parent)
Definition menu.c:605
void add_top_submenu_entry(GtkWidget **menus, GList **lists, const gchar *label, const dt_menus_t index)
Definition menu.c:515
void add_menu_separator(GtkWidget *menu)
Definition menu.c:598
gboolean has_active_images()
Definition menu.c:636
#define GET_ACCEL_WRAPPER(cb)
Definition menu.h:244
#define MAKE_ACCEL_WRAPPER(cb)
Definition menu.h:232
dt_menus_t
Definition menu.h:42
void dt_ratings_apply_on_list(GList *img, const int rating, const gboolean undo_on)
Definition ratings.c:200
struct _GtkWidget GtkWidget
Definition splash.h:29
struct dt_collection_t * collection
Definition darktable.h:781
const struct dt_database_t * db
Definition darktable.h:779