Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
colorlabels.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010 Alexandre Prokoudine.
4 Copyright (C) 2010-2011 Henrik Andersson.
5 Copyright (C) 2010-2011 johannes hanika.
6 Copyright (C) 2011 Robert Bieber.
7 Copyright (C) 2011-2014, 2016 Tobias Ellinghaus.
8 Copyright (C) 2012 Richard Wonka.
9 Copyright (C) 2013 José Carlos García Sogo.
10 Copyright (C) 2013 Jérémy Rosen.
11 Copyright (C) 2014 Ulrich Pegelow.
12 Copyright (C) 2016 Roman Lebedev.
13 Copyright (C) 2019 Heiko Bauke.
14 Copyright (C) 2019-2022 Pascal Obry.
15 Copyright (C) 2019-2020 Philippe Weyland.
16 Copyright (C) 2020-2021 Aldric Renaudin.
17 Copyright (C) 2020 Hubert Kowalski.
18 Copyright (C) 2021 Diederik Ter Rahe.
19 Copyright (C) 2021 Ralf Brown.
20 Copyright (C) 2021 solarer.
21 Copyright (C) 2022-2023, 2025-2026 Aurélien PIERRE.
22 Copyright (C) 2022 Martin Bařinka.
23
24 darktable is free software: you can redistribute it and/or modify
25 it under the terms of the GNU General Public License as published by
26 the Free Software Foundation, either version 3 of the License, or
27 (at your option) any later version.
28
29 darktable is distributed in the hope that it will be useful,
30 but WITHOUT ANY WARRANTY; without even the implied warranty of
31 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 GNU General Public License for more details.
33
34 You should have received a copy of the GNU General Public License
35 along with darktable. If not, see <http://www.gnu.org/licenses/>.
36*/
38#include "metadata/notify.h"
39#include "common/collection.h"
40#include "system/macros.h"
42#include "caches/image_cache.h"
43#include "common/undo.h"
44
45
46const char *dt_colorlabels_name[] = {
47 "red", "yellow", "green", "blue", "purple",
48 NULL // termination
49};
50
51char * dt_colorlabels_get_name(const int label)
52{
53 switch(label)
54 {
55 case 0:
56 return _("red");
57 case 1:
58 return _("yellow");
59 case 2:
60 return _("green");
61 case 3:
62 return _("blue");
63 case 4:
64 return _("purple");
65 case 5:
66 return _("empty");
67 default:
68 return _("unknown/invalid");
69 }
70}
71
78
79int dt_colorlabels_get_labels(const int32_t imgid)
80{
81 return dt_colorlabel_repository_get(imgid);
82}
83
84void dt_colorlabels_set_labels(const int32_t imgid, const int colors)
85{
86 for(int color = 0; color < 5; color++)
87 {
88 if(colors & (1 << color))
90 else
92 }
93}
94
95static void _pop_undo_execute(const int32_t imgid, const int before, const int after)
96{
97 dt_image_t *image = dt_image_cache_get(imgid, 'w');
98 if(IS_NULL_PTR(image)) return;
99
100 // Write to image
101 for(int color = 0; color < 5; color++)
102 {
103 if(after & (1 << color))
104 {
105 if (!(before & (1 << color)))
106 image->color_labels |= (1 << color);
107 }
108 else if (before & (1 << color))
109 image->color_labels &= ~(1 << color);
110 }
111
112 // Update image cache object and write to DB in _write_release
115}
116
117static void _pop_undo(gpointer user_data, dt_undo_type_t type, dt_undo_data_t data, dt_undo_action_t action, GList **imgs)
118{
120 {
121 for(GList *list = (GList *)data; list; list = g_list_next(list))
122 {
123 dt_undo_colorlabels_t *undocolorlabels = (dt_undo_colorlabels_t *)list->data;
124
125 const int before = (action == DT_ACTION_UNDO) ? undocolorlabels->after : undocolorlabels->before;
126 const int after = (action == DT_ACTION_UNDO) ? undocolorlabels->before : undocolorlabels->after;
127 _pop_undo_execute(undocolorlabels->imgid, before, after);
128 *imgs = g_list_prepend(*imgs, GINT_TO_POINTER(undocolorlabels->imgid));
129 }
131 }
132}
133
134static void _colorlabels_undo_data_free(gpointer data)
135{
136 GList *l = (GList *)data;
137 g_list_free(l);
138 l = NULL;
139}
140
141void dt_colorlabels_remove_labels(const int32_t imgid)
142{
144}
145
146void dt_colorlabels_set_label(const int32_t imgid, const int color)
147{
149}
150
151void dt_colorlabels_remove_label(const int32_t imgid, const int color)
152{
154}
155
160
167
168
169// Returns the action actually performed: DT_CA_ADD when the labels were added to the images,
170// DT_CA_TOGGLE when they were removed from all of them, DT_CA_SET when they were set verbatim.
171static int _colorlabels_execute(GList *imgs, const int labels, GList **undo, const gboolean undo_on, int action)
172{
173 if(action == DT_CA_TOGGLE)
174 {
175 // if we are supposed to toggle color labels, first check if all images have that label
176 for(const GList *image = g_list_first(imgs); image; image = g_list_next((GList *)image))
177 {
178 const int32_t image_id = GPOINTER_TO_INT(image->data);
179
180 dt_image_t *img = dt_image_cache_get(image_id, 'r');
181 if(IS_NULL_PTR(img)) continue;
182
183 const int before = img->color_labels;
185
186 // as long as a single image does not have the label we do not toggle the label for all images
187 // but add the label to all unlabeled images first
188 if(!(before & labels))
189 {
190 action = DT_CA_ADD;
191 break;
192 }
193 }
194 }
195
196 for(GList *image = g_list_first(imgs); image; image = g_list_next((GList *)image))
197 {
198 const int32_t image_id = GPOINTER_TO_INT(image->data);
199
200 dt_image_t *img = dt_image_cache_get(image_id, 'w');
201 if(IS_NULL_PTR(img)) continue;
202
203 const int before = img->color_labels;
204 int after = 0;
205 switch(action)
206 {
207 case DT_CA_SET:
208 after = labels;
209 break;
210 case DT_CA_ADD:
211 after = before | labels;
212 break;
213 case DT_CA_TOGGLE:
214 after = (before & labels) ? before & (~labels) : before | labels;
215 break;
216 default:
217 after = before;
218 break;
219 }
220
221 img->color_labels = after;
223
224 if(undo_on)
225 {
226 dt_undo_colorlabels_t *undocolorlabels = (dt_undo_colorlabels_t *)malloc(sizeof(dt_undo_colorlabels_t));
227 undocolorlabels->imgid = image_id;
228 undocolorlabels->before = before;
229 undocolorlabels->after = after;
230 *undo = g_list_append(*undo, undocolorlabels);
231 }
232 }
233
234 return action;
235}
236
237void dt_colorlabels_toggle_label_on_list(GList *list, const int color, const gboolean undo_on)
238{
239 const int label = 1<<color;
240 GList *undo = NULL;
242
243 // The toggle resolves to an addition as soon as one image lacks the label, and to a removal
244 // only when every image already carries it: ask _colorlabels_execute() what it actually did
245 // instead of assuming, or the toast announces an addition on the way out too.
246 int done;
247 if(color == 5)
248 {
249 done = _colorlabels_execute(list, 0, &undo, undo_on, DT_CA_SET);
250 }
251 else
252 {
253 done = _colorlabels_execute(list, label, &undo, undo_on, DT_CA_TOGGLE);
254 }
255
256 if(undo_on)
257 {
260 }
262
263 const int count = (int)g_list_length(list);
264 if(color == 5)
265 dt_metadata_notify(DT_METADATA_NOTICE_TOAST, _("Color labels removed for %i image(s)"), count);
266 else if(done == DT_CA_ADD)
267 dt_metadata_notify(DT_METADATA_NOTICE_TOAST, _("Color label set to %s for %i image(s)"),
269 else
270 dt_metadata_notify(DT_METADATA_NOTICE_TOAST, _("Color label %s removed for %i image(s)"),
272}
273
274int dt_colorlabels_check_label(const int32_t imgid, const int color)
275{
276 return dt_colorlabel_repository_has(imgid, color) ? 1 : 0;
277}
278
279// FIXME: XMP uses Red, Green, ... while we use red, green, ... What should this function return?
280const char *dt_colorlabels_to_string(int label)
281{
282 if(label < 0 || label >= DT_COLORLABELS_LAST) return ""; // shouldn't happen
283 return dt_colorlabels_name[label];
284}
285
286// clang-format off
287// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
288// vim: shiftwidth=2 expandtab tabstop=2 cindent
289// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
290// clang-format on
dt_collection_t * dt_collection_get_global(void)
Definition collection.c:138
void dt_collection_hint_message(const dt_collection_t *collection)
Definition collection.c:912
gboolean dt_colorlabel_repository_has(const int32_t imgid, const int color)
TRUE when colour color is set on imgid.
void dt_colorlabel_repository_remove_all(const int32_t imgid)
Clear every colour on imgid.
void dt_colorlabel_repository_remove(const int32_t imgid, const int color)
Clear colour color on imgid. Clearing one that is not set does nothing.
void dt_colorlabel_repository_set(const int32_t imgid, const int color)
Set colour color on imgid. Setting one that is already set does nothing.
int dt_colorlabel_repository_get(const int32_t imgid)
The colours set on imgid, as a bitmask: bit c is set when colour c is.
void dt_colorlabel_repository_cleanup(void)
Finalise whatever this repository still caches – today, nothing.
main.color_labels: which of the five colour labels are set on an image.
dt_colorlabels_actions_t
@ DT_CA_TOGGLE
@ DT_CA_ADD
@ DT_CA_SET
static void _pop_undo(gpointer user_data, dt_undo_type_t type, dt_undo_data_t data, dt_undo_action_t action, GList **imgs)
void dt_colorlabels_remove_label(const int32_t imgid, const int color)
void dt_colorlabels_remove_labels(const int32_t imgid)
static void _colorlabels_undo_data_free(gpointer data)
void dt_colorlabels_cleanup(void)
int dt_colorlabels_get_labels(const int32_t imgid)
Definition colorlabels.c:79
int dt_colorlabels_check_label(const int32_t imgid, const int color)
static int _colorlabels_execute(GList *imgs, const int labels, GList **undo, const gboolean undo_on, int action)
static void _pop_undo_execute(const int32_t imgid, const int before, const int after)
Definition colorlabels.c:95
void dt_colorlabels_set_label(const int32_t imgid, const int color)
void dt_colorlabels_toggle_label_on_list(GList *list, const int color, const gboolean undo_on)
const char * dt_colorlabels_to_string(int label)
char * dt_colorlabels_get_name(const int label)
Definition colorlabels.c:51
const char * dt_colorlabels_name[]
Definition colorlabels.c:46
void dt_colorlabels_set_labels(const int32_t imgid, const int colors)
Definition colorlabels.c:84
@ DT_COLORLABELS_LAST
Definition colorlabels.h:47
const dt_collection_filter_flag_t colors[6]
Definition filter.c:302
GdkRGBA color[]
Definition geotagging.c:541
void dt_image_cache_write_release(dt_image_t *img, dt_image_cache_write_mode_t mode)
dt_image_t * dt_image_cache_get(const int32_t imgid, char mode)
void dt_image_cache_read_release(const dt_image_t *img)
@ DT_IMAGE_CACHE_SAFE
Definition image_cache.h:48
_lib_location_type_t type
Definition location.c:1
#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 macros.h:96
void dt_metadata_notify(const dt_metadata_notice_t kind, const char *format,...)
Everything this module says to the outside world: messages for the user, and the fact that the tag vo...
@ DT_METADATA_NOTICE_TOAST
int color_labels
Definition image.h:472
void dt_undo_end_group(dt_undo_t *self)
Definition undo.c:149
void dt_undo_start_group(dt_undo_t *self, dt_undo_type_t type)
Definition undo.c:134
void dt_undo_record(dt_undo_t *self, gpointer user_data, dt_undo_type_t type, dt_undo_data_t data, void(*undo)(gpointer user_data, dt_undo_type_t type, dt_undo_data_t item, dt_undo_action_t action, GList **imgs), void(*free_data)(gpointer data))
Definition undo.c:163
dt_undo_type_t
Definition undo.h:40
@ DT_UNDO_COLORLABELS
Definition undo.h:46
dt_undo_t * dt_undo_get_global(void)
Definition darktable.c:611
void * dt_undo_data_t
Definition undo.h:70
dt_undo_action_t
Definition undo.h:65
@ DT_ACTION_UNDO
Definition undo.h:66