Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
metadata_view.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2011-2012 Henrik Andersson.
4 Copyright (C) 2011, 2013-2014 johannes hanika.
5 Copyright (C) 2011 Robert Bieber.
6 Copyright (C) 2012 James C. McPherson.
7 Copyright (C) 2012 Richard Wonka.
8 Copyright (C) 2012-2018 Tobias Ellinghaus.
9 Copyright (C) 2012-2014 Ulrich Pegelow.
10 Copyright (C) 2013 Jan Kundrát.
11 Copyright (C) 2013 José Carlos García Sogo.
12 Copyright (C) 2013, 2019-2021 Pascal Obry.
13 Copyright (C) 2013-2016 Roman Lebedev.
14 Copyright (C) 2013 Simon Spannagel.
15 Copyright (C) 2013 Thomas Pryds.
16 Copyright (C) 2015 Jean-Sébastien Pédron.
17 Copyright (C) 2015-2016 Jérémy Rosen.
18 Copyright (C) 2015 Pedro Côrte-Real.
19 Copyright (C) 2015 Steven Fosdick.
20 Copyright (C) 2018 Maurizio Paglia.
21 Copyright (C) 2018 rawfiner.
22 Copyright (C) 2019 Andreas Schneider.
23 Copyright (C) 2019 luzpaz.
24 Copyright (C) 2019-2022 Philippe Weyland.
25 Copyright (C) 2020 a.
26 Copyright (C) 2020-2022 Diederik Ter Rahe.
27 Copyright (C) 2020 Hanno Schwalm.
28 Copyright (C) 2020 hatsunearu.
29 Copyright (C) 2020-2021 Hubert Kowalski.
30 Copyright (C) 2020 JP Verrue.
31 Copyright (C) 2021-2022 Aldric Renaudin.
32 Copyright (C) 2021 Bill Ferguson.
33 Copyright (C) 2021 Daniel Vogelbacher.
34 Copyright (C) 2021 Ralf Brown.
35 Copyright (C) 2021 Vincent THOMAS.
36 Copyright (C) 2021 Wolfgang Goetz.
37 Copyright (C) 2022-2023, 2025-2026 Aurélien PIERRE.
38 Copyright (C) 2022 Martin Bařinka.
39 Copyright (C) 2023 Ricky Moon.
40
41 darktable is free software: you can redistribute it and/or modify
42 it under the terms of the GNU General Public License as published by
43 the Free Software Foundation, either version 3 of the License, or
44 (at your option) any later version.
45
46 darktable is distributed in the hope that it will be useful,
47 but WITHOUT ANY WARRANTY; without even the implied warranty of
48 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49 GNU General Public License for more details.
50
51 You should have received a copy of the GNU General Public License
52 along with darktable. If not, see <http://www.gnu.org/licenses/>.
53*/
54
55#include "common/collection.h"
56#include "common/darktable.h"
57#include "common/debug.h"
58#include "common/image_cache.h"
59#include "common/metadata.h"
60#include "common/tags.h"
61#include "common/datetime.h"
62#include "common/selection.h"
63#include "control/conf.h"
64#include "control/control.h"
65#include "develop/develop.h"
66
67#include "gui/gtk.h"
68#include "libs/lib.h"
69#include "libs/lib_api.h"
70
71#include <gdk/gdkkeysyms.h>
72#include <sys/param.h>
73#ifdef GDK_WINDOWING_QUARTZ
74#include "osx/osx.h"
75#endif
76
77DT_MODULE(1)
78
86
88{
90 GList *metadata;
92
93 // currently-displayed imgid
94 int32_t imgid;
96
98{
99 int index; // md_xx value or index inserted by lua
100 int order; // display order
101 char *name; // metadata name
102 char *value; // metadata value
103 char *tooltip; // tooltip
104 gboolean visible;
106
107enum
108{
109 /* internal */
123
124 /* exif */
137
138 /* size of final image */
141
142 /* xmp */
144
145 /* geotagging */
149
150 /* tags */
153
154 /* entries, do not touch! */
155 md_size
157
158static const char *_labels[] = {
159 /* internal */
160 N_("filmroll"),
161 N_("filmroll id"),
162 N_("image id"),
163 N_("group id"),
164 N_("filename"),
165 N_("version"),
166 N_("full path"),
167 N_("local copy"),
168 N_("import timestamp"),
169 N_("change timestamp"),
170 N_("export timestamp"),
171 N_("print timestamp"),
172 N_("flags"),
173
174 /* exif */
175 N_("model"),
176 N_("maker"),
177 N_("lens"),
178 N_("aperture"),
179 N_("exposure"),
180 N_("exposure bias"),
181 N_("focal length"),
182 N_("focus distance"),
183 N_("ISO"),
184 N_("datetime"),
185 N_("width"),
186 N_("height"),
187 N_("export width"),
188 N_("export height"),
189
190 /* xmp */
191 //FIXME: reserve DT_METADATA_NUMBER places
192 "","","","","","","","",
193
194 /* geotagging */
195 N_("latitude"),
196 N_("longitude"),
197 N_("elevation"),
198
199 /* tags */
200 N_("tags"),
201 N_("categories"),
202};
203
204static gboolean _dndactive = FALSE;
205
206const char *name(struct dt_lib_module_t *self)
207{
208 return _("EXIF and IPTC");
209}
210
211const char **views(dt_lib_module_t *self)
212{
213 static const char *v[] = {"darkroom", "lighttable", "map", "print", "slideshow", NULL};
214 return v;
215}
216
218{
220}
221
223{
224 return 1;
225}
226
227static gboolean _is_metadata_ui(const int i)
228{
229 // internal metadata are not to be shown on the ui
231 {
234 }
235 else return TRUE;
236}
237
238static const char *_get_label(const int i)
239{
241 {
243 return(dt_metadata_get_name(keyid));
244 }
245 else return _labels[i];
246}
247
248#define NODATA_STRING "-"
249
250// initialize the metadata queue
252{
254 d->metadata = NULL;
255 for(int i = md_size - 1; i >= 0; i--)
256 {
257 dt_lib_metadata_info_t *m = g_malloc0(sizeof(dt_lib_metadata_info_t));
258 m->name = (char *)_get_label(i);
259 m->value = g_strdup(NODATA_STRING);
260 m->index = m->order = i;
261 m->visible = _is_metadata_ui(i);
262 d->metadata = g_list_prepend(d->metadata, m);
263 }
264}
265
266// helper which eliminates non-printable characters from a string
267// strings which are already in valid UTF-8 are retained.
268static void _filter_non_printable(char *string, size_t length)
269{
270 /* explicitly tell the validator to ignore the trailing nulls, otherwise this fails */
271 if(g_utf8_validate(string, -1, 0)) return;
272
273 unsigned char *str = (unsigned char *)string;
274 int n = 0;
275
276 while(*str != '\000' && n < length)
277 {
278 if((*str < 0x20) || (*str >= 0x7f)) *str = '.';
279
280 str++;
281 n++;
282 }
283}
284
286{
288 for(GList *meta = d->metadata; meta; meta = g_list_next(meta))
289 {
291 if(m->index == index)
292 {
293 return m;
294 }
295 }
296 return NULL;
297}
298
299static void _metadata_update_markup(const gint32 i, const char *const format, dt_lib_module_t *self)
300{
303
304 GtkLabel *label = GTK_LABEL(gtk_grid_get_child_at(GTK_GRID(d->grid), 1, m->order));
305 char *markup = g_markup_printf_escaped(format, gtk_label_get_text(label));
306 gtk_label_set_markup(label, markup);
307 dt_free(markup);
308}
309
310/* helper function for updating a metadata value */
311static void _metadata_update_value(const int i, const char *value, dt_lib_module_t *self)
312{
314 gboolean validated = g_utf8_validate(value, -1, NULL);
315 const gchar *str = validated ? value : NODATA_STRING;
317 if(m)
318 {
319 if(m->value)
320 {
321 dt_free(m->value);
322 }
323 m->value = g_strdup(str);
324 GtkWidget *w_value = gtk_grid_get_child_at(GTK_GRID(d->grid), 1, m->order);
325 gtk_label_set_text(GTK_LABEL(w_value), str);
326 const char *tooltip = m->tooltip ? m->tooltip : m->value;
327 gtk_widget_set_tooltip_text(GTK_WIDGET(w_value), tooltip);
328 }
329}
330
331static void _metadata_update_tooltip(const int i, const char *tooltip, dt_lib_module_t *self)
332{
334 if(m)
335 {
336 if(m->tooltip)
337 {
338 dt_free(m->tooltip);
339 }
340 m->tooltip = g_strdup(tooltip);
341 }
342}
343
344static void _metadata_update_timestamp(const int i, const GTimeSpan gts, dt_lib_module_t *self)
345{
346 char datetime[200];
347 const gboolean valid = gts ? dt_datetime_gtimespan_to_local(datetime, sizeof(datetime), gts, FALSE, TRUE) : FALSE;
348 _metadata_update_value(i, valid ? datetime : NODATA_STRING, self);
349}
350
351static gint _lib_metadata_sort_order(gconstpointer a, gconstpointer b)
352{
355 return ma->order - mb->order;
356}
357
358static gint _lib_metadata_sort_index(gconstpointer a, gconstpointer b)
359{
362 return ma->index - mb->index;
363}
364
365static void _metadata_get_flags(const dt_image_t *const img, char *const text, char *const tooltip, const size_t tooltip_size)
366{
367#define EMPTY_FIELD '.'
368#define FALSE_FIELD '.'
369#define TRUE_FIELD '!'
370
371#define FLAG_NB 15
372
373 char *flags_tooltip = NULL;
374 char *flag_descriptions[] = { N_("unused"),
375 N_("unused/deprecated"),
376 N_("ldr"),
377 N_("raw"),
378 N_("hdr"),
379 N_("marked for deletion"),
380 N_("auto-applying presets applied"),
381 N_("legacy flag. set for all new images"),
382 N_("local copy"),
383 N_("has .txt"),
384 N_("has .wav"),
385 N_("monochrome")
386 };
387 char *tooltip_parts[FLAG_NB] = { 0 };
388 int next_tooltip_part = 0;
389
390 gchar *value = g_strnfill(FLAG_NB, EMPTY_FIELD);
391
392 int stars = img->flags & 0x7;
393 char *star_string = NULL;
394 if(stars == 6)
395 {
396 value[0] = 'x';
397 tooltip_parts[next_tooltip_part++] = _("image rejected");
398 }
399 else
400 {
401 value[0] = '0' + stars;
402 tooltip_parts[next_tooltip_part++] = star_string = g_strdup_printf(ngettext("image has %d star", "image has %d stars", stars), stars);
403 }
404
405
406 if(img->flags & 8)
407 {
408 value[1] = TRUE_FIELD;
409 tooltip_parts[next_tooltip_part++] = _(flag_descriptions[0]);
410 }
411 else
412 value[1] = FALSE_FIELD;
413
415 {
416 value[2] = TRUE_FIELD;
417 tooltip_parts[next_tooltip_part++] = _(flag_descriptions[1]);
418 }
419 else
420 value[2] = FALSE_FIELD;
421
422 if(dt_image_is_ldr(img))
423 {
424 value[3] = 'l';
425 tooltip_parts[next_tooltip_part++] = _(flag_descriptions[2]);
426 }
427
428 if(dt_image_is_raw(img))
429 {
430 value[4] = 'r';
431 tooltip_parts[next_tooltip_part++] = _(flag_descriptions[3]);
432 }
433
434 if(dt_image_is_hdr(img))
435 {
436 value[5] = 'h';
437 tooltip_parts[next_tooltip_part++] = _(flag_descriptions[4]);
438 }
439
440 if(img->flags & DT_IMAGE_REMOVE)
441 {
442 value[6] = 'd';
443 tooltip_parts[next_tooltip_part++] = _(flag_descriptions[5]);
444 }
445
447 {
448 value[7] = 'a';
449 tooltip_parts[next_tooltip_part++] = _(flag_descriptions[6]);
450 }
451
453 {
454 value[8] = 'p';
455 tooltip_parts[next_tooltip_part++] = _(flag_descriptions[7]);
456 }
457
458 if(img->flags & DT_IMAGE_LOCAL_COPY)
459 {
460 value[9] = 'c';
461 tooltip_parts[next_tooltip_part++] = _(flag_descriptions[8]);
462 }
463
464 if(img->flags & DT_IMAGE_HAS_TXT)
465 {
466 value[10] = 't';
467 tooltip_parts[next_tooltip_part++] = _(flag_descriptions[9]);
468 }
469
470 if(img->flags & DT_IMAGE_HAS_WAV)
471 {
472 value[11] = 'w';
473 tooltip_parts[next_tooltip_part++] = _(flag_descriptions[10]);
474 }
475
477 {
478 value[12] = 'm';
479 tooltip_parts[next_tooltip_part++] = _(flag_descriptions[11]);
480 }
481
482 const int loader = (unsigned int)img->loader < LOADER_COUNT ? img->loader : 0;
483 value[13] = loaders_info[loader].flag;
484 char *loader_tooltip = g_strdup_printf(_("loader: %s"), _(loaders_info[loader].tooltip));
485 tooltip_parts[next_tooltip_part++] = loader_tooltip;
486
487 value[14] = '\0';
488
489 flags_tooltip = g_strjoinv("\n", tooltip_parts);
490 dt_free(loader_tooltip);
491
492 (void)g_strlcpy(text, value, FLAG_NB);
493 (void)g_strlcpy(tooltip, flags_tooltip, tooltip_size);
494
495 dt_free(value);
496 dt_free(star_string);
497 dt_free(flags_tooltip);
498
499#undef EMPTY_FIELD
500#undef FALSE_FIELD
501#undef TRUE_FIELD
502#undef FLAG_NB
503}
504
505static gboolean _metadata_view_get_thumb_info(const int32_t imgid, dt_image_t *info)
506{
507 if(imgid <= 0 || IS_NULL_PTR(info) || IS_NULL_PTR(darktable.gui) || IS_NULL_PTR(darktable.gui->ui)) return FALSE;
508
510 return TRUE;
512 return TRUE;
513
514 return FALSE;
515}
516
517static void _concatenate_multiple_images(gboolean skip[md_size], int count)
518{
520 sqlite3_stmt *stmt = NULL;
521 // clang-format off
522 gchar *query = g_strdup_printf("SELECT COUNT(DISTINCT film_id), "
523 "COUNT(DISTINCT film_id), "
524 "2, " // imgid always different
525 "COUNT(DISTINCT group_id), "
526 "COUNT(DISTINCT filename), "
527 "COUNT(DISTINCT version), "
528 "COUNT(DISTINCT film_id || '/' || filename), " //path
529 "COUNT(DISTINCT flags & 2048), " //local copy
530 "COUNT(DISTINCT import_timestamp), "
531 "COUNT(DISTINCT change_timestamp), "
532 "COUNT(DISTINCT export_timestamp), "
533 "COUNT(DISTINCT print_timestamp), "
534 "COUNT(DISTINCT flags), "
535 "COUNT(DISTINCT model), "
536 "COUNT(DISTINCT maker), "
537 "COUNT(DISTINCT lens), "
538 "COUNT(DISTINCT aperture), "
539 "COUNT(DISTINCT exposure), "
540 "COUNT(DISTINCT IFNULL(exposure_bias, '')), "
541 "COUNT(DISTINCT focal_length), "
542 "COUNT(DISTINCT focus_distance), "
543 "COUNT(DISTINCT iso), "
544 "COUNT(DISTINCT datetime_taken), "
545 "COUNT(DISTINCT width), "
546 "COUNT(DISTINCT height), "
547 "COUNT(DISTINCT IFNULL(output_width, '')), " //exported width
548 "COUNT(DISTINCT IFNULL(output_height, '')), " //exported height
549 "(SELECT COUNT(DISTINCT IFNULL(value,'')) FROM images LEFT JOIN meta_data ON meta_data.id = images.id AND key = 2 WHERE images.id in (%s)), " //title
550 "(SELECT COUNT(DISTINCT IFNULL(value,'')) FROM images LEFT JOIN meta_data ON meta_data.id = images.id AND key = 3 WHERE images.id in (%s)), " //description
551 "(SELECT COUNT(DISTINCT IFNULL(value,'')) FROM images LEFT JOIN meta_data ON meta_data.id = images.id AND key = 0 WHERE images.id in (%s)), " //creator
552 "(SELECT COUNT(DISTINCT IFNULL(value,'')) FROM images LEFT JOIN meta_data ON meta_data.id = images.id AND key = 1 WHERE images.id in (%s)), " //publisher
553 "(SELECT COUNT(DISTINCT IFNULL(value,'')) FROM images LEFT JOIN meta_data ON meta_data.id = images.id AND key = 4 WHERE images.id in (%s)), " //rights
554 "(SELECT COUNT(DISTINCT IFNULL(value,'')) FROM images LEFT JOIN meta_data ON meta_data.id = images.id AND key = 5 WHERE images.id in (%s)), " //notes
555 "(SELECT COUNT(DISTINCT IFNULL(value,'')) FROM images LEFT JOIN meta_data ON meta_data.id = images.id AND key = 6 WHERE images.id in (%s)), " //version name
556 "(SELECT COUNT(DISTINCT IFNULL(value,'')) FROM images LEFT JOIN meta_data ON meta_data.id = images.id AND key = 7 WHERE images.id in (%s)), " //image id
557 "COUNT(DISTINCT IFNULL(latitude, '')), "
558 "COUNT(DISTINCT IFNULL(longitude, '')), "
559 "COUNT(DISTINCT IFNULL(altitude, '')) "
560 "FROM main.images "
561 "WHERE id IN (%s)",
562 images, images, images, images, images, images, images, images, images);
563 // clang-format on
564
566
567 sqlite3_stmt *stmt_tags = NULL;
568 // clang-format off
569 gchar *tag_query = g_strdup_printf("SELECT flags, COUNT(DISTINCT imgid) "
570 "FROM main.tagged_images "
571 "JOIN data.tags "
572 "ON data.tags.id = main.tagged_images.tagid AND name NOT LIKE 'darktable|%%' "
573 "WHERE imgid in (%s) GROUP BY tagid", images);
574 // clang-format on
575 DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), tag_query, -1, &stmt_tags, NULL);
576 dt_free(tag_query);
577 dt_free(query);
578
579 if(sqlite3_step(stmt) == SQLITE_ROW)
580 {
581 const int col_count = sqlite3_column_count(stmt);
582 for(int32_t md = 0; md < md_tag_names && md < col_count; md++)
583 skip[md] = (sqlite3_column_int(stmt, md) > 1);
584 }
585
586 sqlite3_finalize(stmt);
587
588 // Tags and categories management
589 gboolean same_tags = TRUE;
590 gboolean same_categories = TRUE;
591
592 while(sqlite3_step(stmt_tags) == SQLITE_ROW)
593 {
594 if(sqlite3_column_int(stmt_tags, 0) & DT_TF_CATEGORY)
595 same_categories &= (sqlite3_column_int(stmt_tags, 1) == count);
596 else
597 same_tags &= (sqlite3_column_int(stmt_tags, 1) == count);
598 }
599
600 skip[md_tag_names] = !same_tags;
601 skip[md_categories] = !same_categories;
602
603 sqlite3_finalize(stmt_tags);
604 dt_free(images);
605}
606
607
608/* update all values to reflect mouse over image id or no data at all */
610{
612
613 int32_t count = 0;
614 gboolean skip[md_size] = {FALSE};
615
616 int32_t img_id = dt_control_get_mouse_over_id();
617 if(img_id > -1)
618 {
619 count = 1;
620 }
622 {
625 }
626 else if(dt_act_on_get_first_image() > -1)
627 {
628 count = 1;
629 img_id = dt_act_on_get_first_image();
630 }
631
632 if(count > 1) _concatenate_multiple_images(skip, count);
633
634 dt_image_t tinfo = {0};
635 const gboolean have_thumb_info = _metadata_view_get_thumb_info(img_id, &tinfo);
636 if(!have_thumb_info) return;
637
638 if(img_id == d->imgid) return; // nothing to update, spare the SQL queries
639 d->imgid = img_id;
640
641 if(tinfo.film_id == -1)
642 {
643 goto fill_minuses;
644 }
645
646 // Update the metadata values
647 for(int32_t md = 0; md < md_size; md++)
648 {
649 if(skip[md] == TRUE)
650 {
651 if(md == md_internal_flags)
652 _metadata_update_tooltip(md, NULL, self);
653
654 if(md == md_internal_filmroll)
655 _metadata_update_tooltip(md, NULL, self);
656
657 _metadata_update_value(md, _("<various values>"), self);
658 _metadata_update_markup(md, "<span style=\"italic\">%s</span>", self);
659 continue;
660 }
661
662 char text[PATH_MAX] = {0};
663
664 switch(md)
665 {
667 {
668 char tooltip_filmroll[300] = {0};
669 g_strlcpy(text, tinfo.filmroll, sizeof(text));
670 snprintf(tooltip_filmroll, sizeof(tooltip_filmroll), _("double-click to jump to film roll\n%s"), text);
671 _metadata_update_tooltip(md_internal_filmroll, tooltip_filmroll, self);
673 }
674 break;
675
677 (void)g_snprintf(text, sizeof(text), "%d", tinfo.film_id);
679 break;
680
682 (void)g_snprintf(text, sizeof(text), "%d", tinfo.id);
684 break;
685
687 (void)g_snprintf(text, sizeof(text), "%d", tinfo.group_id);
689 break;
690
693 break;
694
696 (void)g_snprintf(text, sizeof(text), "%d", tinfo.version);
698 break;
699
701 {
702 g_strlcpy(text, tinfo.fullpath, sizeof(text));
704 }
705 break;
706
708 (void)g_strlcpy(text, (tinfo.flags & DT_IMAGE_LOCAL_COPY) ? _("yes") : _("no"),
709 sizeof(text));
711 break;
712
715 break;
716
719 break;
720
723 break;
724
727 break;
728
730 {
731 char tooltip_flags[300] = {0};
732 dt_image_t tmp = {0};
733 tmp.flags = tinfo.flags;
734 tmp.loader = tinfo.loader;
735 _metadata_get_flags(&tmp, text, tooltip_flags, sizeof(tooltip_flags));
736 _metadata_update_tooltip(md_internal_flags, tooltip_flags, self);
738 }
739 break;
740
741 case md_exif_model:
743 break;
744
745 case md_exif_maker:
747 break;
748
749 case md_exif_lens:
751 break;
752
753 case md_exif_aperture:
754 (void)g_snprintf(text, sizeof(text), "f/%.1f", (double)tinfo.exif_aperture);
756 break;
757
758 case md_exif_exposure:
759 {
760 gchar *const str = dt_util_format_exposure(tinfo.exif_exposure);
762 dt_free(str);
763 }
764 break;
765
767 {
768 g_strlcpy(text, NODATA_STRING, sizeof(text));
769 if(!(isnan(tinfo.exif_exposure_bias)))
770 {
771 (void)g_snprintf(text, sizeof(text), _("%+.2f EV"), tinfo.exif_exposure_bias);
772 }
774 break;
775 }
776
778 (void)g_snprintf(text, sizeof(text), "%.0f mm", (double)tinfo.exif_focal_length);
780 break;
781
783 {
784 (void)g_strlcpy(text, NODATA_STRING, sizeof(text));
785 if(!(isnan(tinfo.exif_focus_distance) || (fpclassify(tinfo.exif_focus_distance) == FP_ZERO) ))
786 {
787 (void)g_snprintf(text, sizeof(text), _("%.2f m"), tinfo.exif_focus_distance);
788 }
790 break;
791 }
792
793 case md_exif_iso:
794 (void)g_snprintf(text, sizeof(text), "%.0f", (double)tinfo.exif_iso);
796 break;
797
798 case md_exif_datetime:
799 {
800 char datetime[200];
801 const gboolean milliseconds = dt_conf_get_bool("lighttable/ui/milliseconds");
802 const gboolean valid = dt_datetime_gtimespan_to_local(datetime, sizeof(datetime),
803 tinfo.exif_datetime_taken, milliseconds, FALSE);
804 _metadata_update_value(md_exif_datetime, valid ? datetime : NODATA_STRING, self);
805 }
806 break;
807
808 case md_exif_width:
809 if(tinfo.p_width && (tinfo.p_width != tinfo.width))
810 {
811 (void)g_snprintf(text, sizeof(text), "%d (%d)", tinfo.p_width, tinfo.width);
813 }
814 else
815 {
816 (void)g_snprintf(text, sizeof(text), "%d", tinfo.width);
818 }
819 break;
820
821 case md_exif_height:
822 if(tinfo.p_height && (tinfo.p_height != tinfo.height))
823 {
824 (void)g_snprintf(text, sizeof(text), "%d (%d)", tinfo.p_height, tinfo.height);
826 }
827 else
828 {
829 (void)g_snprintf(text, sizeof(text), "%d", tinfo.height);
831 }
832 break;
833
834// case md_xmp_metadata: //managed below the switch()
835// break;
836
838 if(isnan(tinfo.geoloc.latitude))
839 {
841 }
842 else
843 {
844 if(dt_conf_get_bool("plugins/lighttable/metadata_view/pretty_location"))
845 {
846 gchar *latitude = dt_util_latitude_str((float)tinfo.geoloc.latitude);
848 dt_free(latitude);
849 }
850 else
851 {
852 const gchar NS = tinfo.geoloc.latitude < 0 ? 'S' : 'N';
853 (void)g_snprintf(text, sizeof(text), "%c %09.6f", NS, fabs(tinfo.geoloc.latitude));
855 }
856 }
857 break;
858
860 if(isnan(tinfo.geoloc.longitude))
861 {
863 }
864 else
865 {
866 if(dt_conf_get_bool("plugins/lighttable/metadata_view/pretty_location"))
867 {
868 gchar *longitude = dt_util_longitude_str((float)tinfo.geoloc.longitude);
870 dt_free(longitude);
871 }
872 else
873 {
874 const gchar EW = tinfo.geoloc.longitude < 0 ? 'W' : 'E';
875 (void)g_snprintf(text, sizeof(text), "%c %010.6f", EW, fabs(tinfo.geoloc.longitude));
877 }
878 }
879 break;
880
882 if(isnan(tinfo.geoloc.elevation))
883 {
885 }
886 else
887 {
888 if(dt_conf_get_bool("plugins/lighttable/metadata_view/pretty_location"))
889 {
890 gchar *elevation = dt_util_elevation_str((float)tinfo.geoloc.elevation);
892 dt_free(elevation);
893 }
894 else
895 {
896 (void)g_snprintf(text, sizeof(text), "%.2f %s", tinfo.geoloc.elevation, _("m"));
898 }
899 }
900 break;
901
902 case md_tag_names:
903 case md_categories:
904 {
905 GList *tags = NULL;
906 char *tagstring = NULL;
907 char *categoriesstring = NULL;
908 if(dt_tag_get_attached(img_id, &tags, TRUE))
909 {
910 uint64_t length = 0u;
911 for(GList *taglist = tags; taglist; taglist = g_list_next(taglist))
912 {
913 const char *tagname = ((dt_tag_t *)taglist->data)->leave;
914 if(!(((dt_tag_t *)taglist->data)->flags & DT_TF_CATEGORY))
915 {
916 // tags - just keywords
917 length = length + strlen(tagname) + 2u;
918 if(length < 45u)
919 tagstring = dt_util_dstrcat(tagstring, "%s, ", tagname);
920 else
921 {
922 tagstring = dt_util_dstrcat(tagstring, "\n%s, ", tagname);
923 length = strlen(tagname) + 2u;
924 }
925 }
926 else
927 {
928 // categories - needs parent category to make sense
929 char *category = g_strdup(((dt_tag_t *)taglist->data)->tag);
930 char *catend = g_strrstr(category, "|");
931 if(catend)
932 {
933 catend[0] = '\0';
934 char *catstart = g_strrstr(category, "|");
935 catstart = catstart ? catstart + 1 : category;
936 categoriesstring = dt_util_dstrcat(categoriesstring, categoriesstring ? "\n%s: %s " : "%s: %s ",
937 catstart, ((dt_tag_t *)taglist->data)->leave);
938 }
939 else
940 categoriesstring = dt_util_dstrcat(categoriesstring, categoriesstring ? "\n%s" : "%s",
941 ((dt_tag_t *)taglist->data)->leave);
942 dt_free(category);
943 }
944 }
945 if(tagstring) tagstring[strlen(tagstring)-2] = '\0';
946 }
947
948 if (md == md_tag_names)
949 _metadata_update_value(md_tag_names, tagstring ? tagstring : NODATA_STRING, self);
950 else
951 _metadata_update_value(md_categories, categoriesstring ? categoriesstring : NODATA_STRING, self);
952
953 dt_free(tagstring);
954 dt_free(categoriesstring);
955 dt_tag_free_result(&tags);
956 }
957 break;
958
959 default:
960 break;
961 }
962
963 //cases not handled by switch
965 {
966 g_strlcpy(text, NODATA_STRING, sizeof(text));
967
968 const uint32_t keyid = dt_metadata_get_keyid_by_display_order((uint32_t)(md - md_xmp_metadata));
969 const gboolean hidden = dt_metadata_get_type(keyid) == DT_METADATA_TYPE_INTERNAL;
970 if(! hidden)
971 {
972 const gchar *const key = dt_metadata_get_key(keyid);
973 GList *res = dt_metadata_get(img_id, key, NULL);
974 if(res)
975 {
976 g_strlcpy(text, (char *)res->data, sizeof(text));
977 _filter_non_printable(text, sizeof(text));
978 g_list_free_full(res, dt_free_gpointer);
979 res = NULL;
980 }
981 _metadata_update_value(md, text, self);
982 }
983 }
984 }
985
986 return;
987
988/* reset */
989fill_minuses:
990 for(int k = 0; k < md_size; k++) _metadata_update_value(k, NODATA_STRING, self);
991}
992
993static void _jump_to()
994{
995 int32_t imgid = dt_control_get_mouse_over_id();
996 if(imgid == UNKNOWN_IMAGE)
997 {
998 sqlite3_stmt *stmt;
999
1000 DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT imgid FROM main.selected_images", -1, &stmt,
1001 NULL);
1002
1003 if(sqlite3_step(stmt) == SQLITE_ROW) imgid = sqlite3_column_int(stmt, 0);
1004 sqlite3_finalize(stmt);
1005 }
1006 if(imgid != UNKNOWN_IMAGE)
1007 {
1008 char path[512];
1009 const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r');
1010 dt_image_film_roll_directory(img, path, sizeof(path));
1012 char collect[1024];
1013 snprintf(collect, sizeof(collect), "1:0:0:%s$", path);
1015 }
1016}
1017
1018static gboolean _filmroll_clicked(GtkWidget *widget, GdkEventButton *event, gpointer null)
1019{
1020 if(event->type != GDK_2BUTTON_PRESS) return FALSE;
1021 _jump_to();
1022 return TRUE;
1023}
1024
1025/* callback for the mouse over image change signal */
1026static void _mouse_over_image_callback(gpointer instance, gpointer user_data)
1027{
1028 dt_lib_module_t *self = (dt_lib_module_t *)user_data;
1029 //if(dt_lib_gui_get_expanded(self))
1031}
1032
1034{
1036 char *pref = NULL;
1037
1038 d->metadata = g_list_sort(d->metadata, _lib_metadata_sort_order);
1039 for(GList *meta = d->metadata; meta; meta= g_list_next(meta))
1040 {
1042 if(_is_metadata_ui(m->index))
1043 pref = dt_util_dstrcat(pref, "%s%s,", m->visible ? "" : "|", m->name);
1044 }
1045 if(pref)
1046 {
1047 pref[strlen(pref) - 1] = '\0';
1048 }
1049 return pref;
1050}
1051
1053{
1055 d->metadata = g_list_sort(d->metadata, _lib_metadata_sort_order);
1056
1057 int j = 0;
1058 // initialize the grid with metadata queue content
1059 for(GList *meta = d->metadata; meta; meta = g_list_next(meta))
1060 {
1062 m->order = j;
1063 GtkWidget *w_name = gtk_grid_get_child_at(GTK_GRID(d->grid), 0, j);
1064 gtk_label_set_text(GTK_LABEL(w_name), _(m->name));
1065 gtk_widget_set_tooltip_text(w_name, _(m->name));
1066 GtkWidget *w_value = gtk_grid_get_child_at(GTK_GRID(d->grid), 1, j);
1067 gtk_label_set_text(GTK_LABEL(w_value), m->value);
1068 const char *tooltip = m->tooltip ? m->tooltip : m->value;
1069 gtk_widget_set_tooltip_text(w_value, tooltip);
1070
1071 const int i = m->index;
1072 gtk_label_set_ellipsize(GTK_LABEL(w_value),
1074 ? PANGO_ELLIPSIZE_END : PANGO_ELLIPSIZE_MIDDLE);
1075 if(i == md_internal_filmroll)
1076 {
1077 // film roll jump to:
1078 if(d->filmroll_event && GTK_IS_WIDGET(d->filmroll_event))
1079 g_signal_handlers_disconnect_by_func(d->filmroll_event, G_CALLBACK(_filmroll_clicked), NULL);
1080 g_signal_connect(G_OBJECT(w_value), "button-press-event", G_CALLBACK(_filmroll_clicked), NULL);
1081 d->filmroll_event = G_OBJECT(w_value);
1082 }
1083
1084 gtk_widget_set_visible(w_name, m->visible);
1085 gtk_widget_set_visible(w_value, m->visible);
1086 j++;
1087 }
1088}
1089
1091{
1093
1094 int j = 0;
1095 // initialize the grid with metadata queue content
1096 for(GList *meta = d->metadata; meta; meta = g_list_next(meta))
1097 {
1099 GtkWidget *w_name = gtk_label_new(_(m->name));
1100 gtk_widget_set_halign(w_name, GTK_ALIGN_START);
1101 gtk_label_set_xalign(GTK_LABEL(w_name), 0.0f);
1102 gtk_label_set_ellipsize(GTK_LABEL(w_name), PANGO_ELLIPSIZE_END);
1103 gtk_widget_set_tooltip_text(w_name, _(m->name));
1104
1105 GtkWidget *w_value= gtk_label_new(m->value);
1106 gtk_widget_set_name(w_value, "brightbg");
1107 gtk_label_set_selectable(GTK_LABEL(w_value), TRUE);
1108 gtk_widget_set_halign(w_value, GTK_ALIGN_FILL);
1109 gtk_label_set_xalign(GTK_LABEL(w_value), 0.0f);
1110
1111 gtk_grid_attach(GTK_GRID(d->grid), w_name, 0, j, 1, 1);
1112 gtk_grid_attach(GTK_GRID(d->grid), w_value, 1, j, 1, 1);
1113 j++;
1114 }
1115}
1116
1117static void _apply_preferences(const char *prefs_list, dt_lib_module_t *self)
1118{
1119 if(!prefs_list || !prefs_list[0]) return;
1121
1122 GList *prefs = dt_util_str_to_glist(",", prefs_list);
1123 int k = 0;
1124 for(GList *pref = prefs; pref; pref = g_list_next(pref))
1125 {
1126 const char *name = (char *)pref->data;
1127 gboolean visible = TRUE;
1128 if(name)
1129 {
1130 if(name[0] == '|')
1131 {
1132 name++;
1133 visible = FALSE;
1134 }
1135 for(GList *meta = d->metadata; meta; meta= g_list_next(meta))
1136 {
1138 if(name && !g_strcmp0(name, m->name))
1139 {
1140 m->order = k;
1141 m->visible = visible;
1142 break;
1143 }
1144 }
1145 }
1146 else continue;
1147 k++;
1148 }
1149 g_list_free_full(prefs, dt_free_gpointer);
1150 prefs = NULL;
1151
1153}
1154
1156{
1157 char *pref = _get_current_configuration(self);
1158 dt_conf_set_string("plugins/lighttable/metadata_view/visible", pref);
1159 dt_free(pref);
1160}
1161
1162static void _select_toggled_callback(GtkCellRendererToggle *cell_renderer, gchar *path_str, gpointer user_data)
1163{
1164 GtkListStore *store = (GtkListStore *)user_data;
1165 GtkTreeIter iter;
1166 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1167 gboolean selected;
1168
1169 gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path);
1170 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, DT_METADATA_PREF_COL_VISIBLE, &selected, -1);
1171 gtk_list_store_set(store, &iter, DT_METADATA_PREF_COL_VISIBLE, !selected, -1);
1172
1173 gtk_tree_path_free(path);
1174}
1175
1176static void _drag_data_inserted(GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
1177{
1178 _dndactive = TRUE;
1179}
1180
1181void _menuitem_preferences(GtkMenuItem *menuitem, dt_lib_module_t *self)
1182{
1184
1186 GtkWidget *dialog = gtk_dialog_new_with_buttons(_("metadata settings"), GTK_WINDOW(win),
1187 GTK_DIALOG_DESTROY_WITH_PARENT, _("default"), GTK_RESPONSE_YES,
1188 _("cancel"), GTK_RESPONSE_NONE, _("save"), GTK_RESPONSE_ACCEPT, NULL);
1189 g_signal_connect(dialog, "key-press-event", G_CALLBACK(dt_handle_dialog_enter), NULL);
1190 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1191
1192 GtkWidget *w = gtk_scrolled_window_new(NULL, NULL);
1193 gtk_widget_set_size_request(w, -1, DT_PIXEL_APPLY_DPI(600));
1194 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1195 gtk_scrolled_window_set_overlay_scrolling(GTK_SCROLLED_WINDOW(w), FALSE);
1196 dt_gui_add_class(w, "dt_recessed_scroll");
1197 gtk_box_pack_start(GTK_BOX(area), w, TRUE, TRUE, 0);
1198
1199 GtkListStore *store = gtk_list_store_new(DT_METADATA_PREF_NUM_COLS,
1200 G_TYPE_INT, G_TYPE_STRING, G_TYPE_BOOLEAN);
1201 GtkTreeModel *model = GTK_TREE_MODEL(store);
1202
1203 GtkTreeIter iter;
1204 d->metadata = g_list_sort(d->metadata, _lib_metadata_sort_order);
1205 for(GList *meta = d->metadata; meta; meta = g_list_next(meta))
1206 {
1208 if(!_is_metadata_ui(m->index))
1209 continue;
1210 gtk_list_store_append(store, &iter);
1211 gtk_list_store_set(store, &iter,
1215 -1);
1216 }
1217
1218 GtkWidget *view = gtk_tree_view_new_with_model(model);
1219 g_object_unref(model);
1220 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
1221 GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(_("metadata"), renderer,
1222 "text", DT_METADATA_PREF_COL_NAME_L, NULL);
1223 gtk_tree_view_column_set_expand(column, TRUE);
1224 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
1225 GtkWidget *header = gtk_tree_view_column_get_button(column);
1226 gtk_widget_set_tooltip_text(header,
1227 _("drag and drop one row at a time until you get the desired order"
1228 "\nuntick to hide metadata which are not of interest for you"
1229 "\nif different settings are needed, use presets"));
1230 renderer = gtk_cell_renderer_toggle_new();
1231 g_signal_connect(renderer, "toggled", G_CALLBACK(_select_toggled_callback), store);
1232 column = gtk_tree_view_column_new_with_attributes(_("visible"), renderer,
1233 "active", DT_METADATA_PREF_COL_VISIBLE, NULL);
1234 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
1235
1236 // drag & drop
1237 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(view), TRUE);
1238 g_signal_connect(G_OBJECT(model), "row-inserted", G_CALLBACK(_drag_data_inserted), NULL);
1239
1240 gtk_container_add(GTK_CONTAINER(w), view);
1241
1242#ifdef GDK_WINDOWING_QUARTZ
1244#endif
1245 gtk_widget_show_all(dialog);
1246
1247 int res = gtk_dialog_run(GTK_DIALOG(dialog));
1248 while(res == GTK_RESPONSE_YES)
1249 {
1250 gtk_tree_model_get_iter_first(model, &iter);
1251 d->metadata = g_list_sort(d->metadata, _lib_metadata_sort_index);
1252 for(GList *meta = d->metadata; meta; meta= g_list_next(meta))
1253 {
1255 if(!_is_metadata_ui(m->index))
1256 continue;
1257 gtk_list_store_set(store, &iter,
1261 -1);
1262 gtk_tree_model_iter_next(model, &iter);
1263 }
1264 res = gtk_dialog_run(GTK_DIALOG(dialog));
1265 }
1266
1267 int i = 0;
1268 if(res == GTK_RESPONSE_ACCEPT)
1269 {
1270 gboolean valid = gtk_tree_model_get_iter_first(model, &iter);
1271 while(valid)
1272 {
1273 gboolean visible;
1274 uint32_t index;
1275 gtk_tree_model_get(model, &iter,
1278 -1);
1279 for(GList *meta = d->metadata; meta; meta= g_list_next(meta))
1280 {
1282 if(m->index == index)
1283 {
1284 m->order = i;
1285 m->visible = visible;
1286 break;
1287 }
1288 }
1289 i++;
1290 valid = gtk_tree_model_iter_next(model, &iter);
1291 }
1292
1294 _save_preferences(self);
1295 }
1296 gtk_widget_destroy(dialog);
1297}
1298
1299void set_preferences(void *menu, dt_lib_module_t *self)
1300{
1301 GtkWidget *mi = gtk_menu_item_new_with_label(_("preferences..."));
1302 g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(_menuitem_preferences), self);
1303 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
1304}
1305
1307{
1308 *size = 0;
1309 char *params = _get_current_configuration(self);
1310 if(params)
1311 *size =strlen(params) + 1;
1312 return params;
1313}
1314
1315int set_params(dt_lib_module_t *self, const void *params, int size)
1316{
1317 if(IS_NULL_PTR(params)) return 1;
1318
1319 _apply_preferences(params, self);
1320 _save_preferences(self);
1321 return 0;
1322}
1323
1325{
1327
1328 for(GList *meta = d->metadata; meta; meta= g_list_next(meta))
1329 {
1331 m->order = m->index;
1332 m->visible = _is_metadata_ui(m->index);
1333 }
1335}
1336
1338{
1339 /* initialize ui */
1341 self->data = (void *)d;
1342 d->imgid = -1;
1343
1345
1346 GtkWidget *child_grid_window = gtk_grid_new();
1347 d->grid = child_grid_window;
1348 gtk_grid_set_column_spacing(GTK_GRID(child_grid_window), DT_GUI_BOX_SPACING);
1349
1350 // Static: the metadata grid refreshes for the hovered/selected image, so keep a fixed height.
1351 self->widget = dt_ui_scroll_wrap(child_grid_window, 200, "plugins/lighttable/metadata_view/windowheight",
1353
1354 gtk_widget_show_all(d->grid);
1355 gtk_widget_set_no_show_all(d->grid, TRUE);
1357 const char *pref = dt_conf_get_string_const("plugins/lighttable/metadata_view/visible");
1358 if(!strlen(pref))
1359 _display_default(self);
1360 _apply_preferences(pref, self);
1361
1362 /* lets signup for mouse over image change signals */
1364 G_CALLBACK(_mouse_over_image_callback), self);
1365
1367 G_CALLBACK(_mouse_over_image_callback), self);
1368}
1369
1371{
1372 if(m->value)
1373 {
1374 dt_free(m->value);
1375 }
1376 if(m->tooltip)
1377 {
1378 dt_free(m->tooltip);
1379 }
1380 dt_free(m);
1381}
1382
1384{
1386 if(IS_NULL_PTR(self->data)) return;
1388 g_list_free_full(d->metadata, (GDestroyNotify)_free_metadata_queue);
1389 d->metadata = NULL;
1390 dt_free(self->data);
1391}
1392
1394{
1396
1397 for(GList *meta = d->metadata; meta; meta= g_list_next(meta))
1398 {
1400 m->order = m->index;
1401 m->visible = _is_metadata_ui(m->index);
1402 }
1404 _save_preferences(self);
1405}
1406
1407// clang-format off
1408// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1409// vim: shiftwidth=2 expandtab tabstop=2 cindent
1410// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1411// clang-format on
int32_t dt_act_on_get_first_image()
Definition act_on.c:68
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
#define m
Definition basecurve.c:278
void dt_collection_deserialize(const char *buf)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
gboolean dt_image_is_raw(const dt_image_t *img)
int dt_image_monochrome_flags(const dt_image_t *img)
gboolean dt_image_is_hdr(const dt_image_t *img)
gboolean dt_image_is_ldr(const dt_image_t *img)
void dt_image_film_roll_directory(const dt_image_t *img, char *pathname, size_t pathname_len)
char * key
const char * dt_metadata_get_key(const uint32_t keyid)
const char * dt_metadata_get_name(const uint32_t keyid)
GList * dt_metadata_get(const int id, const char *key, uint32_t *count)
int dt_metadata_get_type(const uint32_t keyid)
dt_metadata_t dt_metadata_get_keyid_by_display_order(const uint32_t order)
char * name
int dt_conf_get_bool(const char *name)
void dt_conf_set_string(const char *name, const char *val)
const char * dt_conf_get_string_const(const char *name)
int32_t dt_control_get_mouse_over_id()
Definition control.c:923
uint32_t view(const dt_view_t *self)
Definition darkroom.c:227
darktable_t darktable
Definition darktable.c:181
#define UNKNOWN_IMAGE
Definition darktable.h:182
#define DT_MODULE(MODVER)
Definition darktable.h:140
static void dt_free_gpointer(gpointer ptr)
Definition darktable.h:463
#define dt_free(ptr)
Definition darktable.h:456
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
#define PATH_MAX
Definition darktable.h:1062
#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
gboolean dt_datetime_gtimespan_to_local(char *local, const size_t local_size, const GTimeSpan gts, const gboolean msec, const gboolean tz)
Definition datetime.c:157
#define DT_DEBUG_SQLITE3_PREPARE_V2(a, b, c, d, e)
Definition debug.h:107
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)
Definition disk.c:252
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.
Definition gtk.c:2713
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
Definition gtk.c:133
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
@ DT_UI_RESIZE_STATIC
Definition gtk.h:264
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
#define DT_PIXEL_APPLY_DPI(value)
Definition gtk.h:90
const char * tooltip
Definition image.h:251
@ DT_IMAGE_NO_LEGACY_PRESETS
Definition image.h:119
@ DT_IMAGE_HAS_WAV
Definition image.h:125
@ DT_IMAGE_AUTO_PRESETS_APPLIED
Definition image.h:117
@ DT_IMAGE_REMOVE
Definition image.h:115
@ DT_IMAGE_LOCAL_COPY
Definition image.h:121
@ DT_IMAGE_THUMBNAIL_DEPRECATED
Definition image.h:106
@ DT_IMAGE_HAS_TXT
Definition image.h:123
static const struct @7 loaders_info[LOADER_COUNT]
@ LOADER_COUNT
Definition image.h:238
void dt_image_cache_read_release(dt_image_cache_t *cache, const dt_image_t *img)
dt_image_t * dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
static CameraMetaData * meta
const char * model
const float v
gboolean dt_handle_dialog_enter(GtkWidget *widget, GdkEventKey *event, gpointer data)
Definition lib.c:1551
dt_metadata_pref_cols_t
float *const restrict const size_t k
@ DT_METADATA_NUMBER
Definition metadata.h:52
@ DT_METADATA_TYPE_INTERNAL
Definition metadata.h:60
static void _concatenate_multiple_images(gboolean skip[md_size], int count)
void gui_reset(dt_lib_module_t *self)
void _menuitem_preferences(GtkMenuItem *menuitem, dt_lib_module_t *self)
int set_params(dt_lib_module_t *self, const void *params, int size)
static void _save_preferences(dt_lib_module_t *self)
void * get_params(dt_lib_module_t *self, int *size)
#define FLAG_NB
void set_preferences(void *menu, dt_lib_module_t *self)
#define EMPTY_FIELD
static gboolean _metadata_view_get_thumb_info(const int32_t imgid, dt_image_t *info)
static void _free_metadata_queue(dt_lib_metadata_info_t *m)
#define NODATA_STRING
static void _metadata_view_update_values(dt_lib_module_t *self)
static void _jump_to()
static char * _get_current_configuration(dt_lib_module_t *self)
@ md_exif_width
@ md_geotagging_ele
@ md_internal_fullpath
@ md_exif_exposure
@ md_internal_flags
@ md_height
@ md_xmp_metadata
@ md_categories
@ md_geotagging_lon
@ md_internal_filmroll_id
@ md_exif_model
@ md_exif_exposure_bias
@ md_internal_version
@ md_exif_lens
@ md_exif_focus_distance
@ md_tag_names
@ md_internal_imgid
@ md_internal_import_timestamp
@ md_exif_datetime
@ md_internal_groupid
@ md_internal_export_timestamp
@ md_size
@ md_exif_aperture
@ md_exif_iso
@ md_internal_print_timestamp
@ md_exif_height
@ md_exif_focal_length
@ md_internal_local_copy
@ md_internal_change_timestamp
@ md_internal_filmroll
@ md_internal_filename
@ md_width
@ md_exif_maker
@ md_geotagging_lat
static void _metadata_get_flags(const dt_image_t *const img, char *const text, char *const tooltip, const size_t tooltip_size)
static gboolean _filmroll_clicked(GtkWidget *widget, GdkEventButton *event, gpointer null)
void gui_cleanup(dt_lib_module_t *self)
static const char * _labels[]
dt_metadata_pref_cols_t
@ DT_METADATA_PREF_COL_INDEX
@ DT_METADATA_PREF_NUM_COLS
@ DT_METADATA_PREF_COL_NAME_L
@ DT_METADATA_PREF_COL_VISIBLE
static void _lib_metadata_setup_grid(dt_lib_module_t *self)
static gboolean _dndactive
static gboolean _is_metadata_ui(const int i)
static dt_lib_metadata_info_t * _get_metadata_per_index(const int index, dt_lib_module_t *self)
static void _lib_metadata_refill_grid(dt_lib_module_t *self)
static void _lib_metadata_init_queue(dt_lib_module_t *self)
static void _filter_non_printable(char *string, size_t length)
static void _metadata_update_markup(const gint32 i, const char *const format, dt_lib_module_t *self)
static void _apply_preferences(const char *prefs_list, dt_lib_module_t *self)
static void _select_toggled_callback(GtkCellRendererToggle *cell_renderer, gchar *path_str, gpointer user_data)
static void _mouse_over_image_callback(gpointer instance, gpointer user_data)
static gint _lib_metadata_sort_order(gconstpointer a, gconstpointer b)
uint32_t container(dt_lib_module_t *self)
static void _metadata_update_value(const int i, const char *value, dt_lib_module_t *self)
static void _drag_data_inserted(GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
void gui_init(dt_lib_module_t *self)
int position()
const char ** views(dt_lib_module_t *self)
static void _metadata_update_timestamp(const int i, const GTimeSpan gts, dt_lib_module_t *self)
static void _display_default(dt_lib_module_t *self)
static gint _lib_metadata_sort_index(gconstpointer a, gconstpointer b)
static void _metadata_update_tooltip(const int i, const char *tooltip, dt_lib_module_t *self)
static const char * _get_label(const int i)
#define TRUE_FIELD
#define FALSE_FIELD
size_t size
Definition mipmap_cache.c:3
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
void dt_osx_disallow_fullscreen(GtkWidget *widget)
Definition osx.mm:104
int32_t dt_selection_get_first_id(struct dt_selection_t *selection)
Definition selection.c:69
gchar * dt_selection_ids_to_string(struct dt_selection_t *selection)
Definition selection.c:367
int dt_selection_get_length(struct dt_selection_t *selection)
Definition selection.c:179
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
Definition signal.h:368
@ DT_SIGNAL_MOUSE_OVER_IMAGE_CHANGE
This signal is raised when mouse hovers over image thumbs both on lighttable and in the filmstrip....
Definition signal.h:59
@ 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
unsigned __int64 uint64_t
Definition strptime.c:75
struct dt_gui_gtk_t * gui
Definition darktable.h:775
struct dt_selection_t * selection
Definition darktable.h:782
const struct dt_database_t * db
Definition darktable.h:779
struct dt_control_signal_t * signals
Definition darktable.h:774
struct dt_image_cache_t * image_cache
Definition darktable.h:777
dt_ui_t * ui
Definition gtk.h:164
double latitude
Definition image.h:275
double elevation
Definition image.h:275
double longitude
Definition image.h:275
float exif_exposure
Definition image.h:285
int32_t height
Definition image.h:315
GTimeSpan export_timestamp
Definition image.h:333
float exif_focus_distance
Definition image.h:290
GTimeSpan import_timestamp
Definition image.h:333
int32_t group_id
Definition image.h:319
float exif_exposure_bias
Definition image.h:286
float exif_iso
Definition image.h:288
dt_image_loader_t loader
Definition image.h:335
float exif_aperture
Definition image.h:287
int32_t version
Definition image.h:319
char fullpath[PATH_MAX]
Definition image.h:305
dt_image_geoloc_t geoloc
Definition image.h:347
int32_t flags
Definition image.h:319
int32_t width
Definition image.h:315
float exif_focal_length
Definition image.h:289
char exif_maker[64]
Definition image.h:292
GTimeSpan change_timestamp
Definition image.h:333
char exif_lens[128]
Definition image.h:294
GTimeSpan print_timestamp
Definition image.h:333
int32_t film_id
Definition image.h:319
GTimeSpan exif_datetime_taken
Definition image.h:295
int32_t p_height
Definition image.h:315
int32_t p_width
Definition image.h:315
char exif_model[64]
Definition image.h:293
char filename[DT_MAX_FILENAME_LEN]
Definition image.h:304
int32_t id
Definition image.h:319
char filmroll[PATH_MAX]
Definition image.h:309
GModule *void * data
Definition lib.h:80
GtkWidget * widget
Definition lib.h:84
dt_thumbtable_t * thumbtable_lighttable
dt_thumbtable_t * thumbtable_filmstrip
uint32_t dt_tag_get_attached(const int32_t imgid, GList **result, const gboolean ignore_dt_tags)
Definition tags.c:635
void dt_tag_free_result(GList **result)
Definition tags.c:1592
@ DT_TF_CATEGORY
Definition tags.h:63
typedef double((*spd)(unsigned long int wavelength, double TempK))
gboolean dt_thumbtable_get_thumbnail_info(dt_thumbtable_t *table, int32_t imgid, dt_image_t *out)
Definition thumbtable.c:874
gchar * dt_util_longitude_str(float longitude)
Definition utility.c:569
gchar * dt_util_elevation_str(float elevation)
Definition utility.c:587
GList * dt_util_str_to_glist(const gchar *separator, const gchar *text)
Definition utility.c:830
char * dt_util_format_exposure(const float exposuretime)
Definition utility.c:865
gchar * dt_util_latitude_str(float latitude)
Definition utility.c:551
gchar * dt_util_dstrcat(gchar *str, const gchar *format,...)
Definition utility.c:95
@ DT_UI_CONTAINER_PANEL_LEFT_CENTER