void dt_styles_apply_to_selection(const char *name,gboolean duplicate) { gboolean selected = FALSE; /* write current history changes so nothing gets lost, do that only in the darkroom as there is nothing to be save when in the lighttable (and it would write over current history stack) */ const dt_view_t *cv = dt_view_manager_get_current_view(darktable.view_manager); if(cv->view((dt_view_t*)cv) == DT_VIEW_DARKROOM) dt_dev_write_history(darktable.develop); /* for each selected image apply style */ sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select * from selected_images", -1, &stmt, NULL); while(sqlite3_step(stmt) == SQLITE_ROW) { int imgid = sqlite3_column_int (stmt, 0); dt_styles_apply_to_image (name,duplicate,imgid); selected = TRUE; } sqlite3_finalize(stmt); if (!selected) dt_control_log(_("no image selected!")); }
void dt_ctl_switch_mode_to(const char *mode) { const dt_view_t *current_view = dt_view_manager_get_current_view(darktable.view_manager); if(current_view && !strcmp(mode, current_view->module_name)) return; g_main_context_invoke(NULL, _dt_ctl_switch_mode_to, (gpointer)mode); }
static gboolean _lib_plugin_header_button_press(GtkWidget *w, GdkEventButton *e, gpointer user_data) { if(e->type == GDK_2BUTTON_PRESS || e->type == GDK_3BUTTON_PRESS) return TRUE; dt_lib_module_t *module = (dt_lib_module_t *)user_data; if(e->button == 1) { /* bail out if module is static */ if(!module->expandable(module)) return FALSE; // make gtk scroll to the module once it updated its allocation size uint32_t container = module->container(module); if(dt_conf_get_bool("lighttable/ui/scroll_to_module")) { if(container == DT_UI_CONTAINER_PANEL_LEFT_CENTER) darktable.gui->scroll_to[0] = module->expander; else if(container == DT_UI_CONTAINER_PANEL_RIGHT_CENTER) darktable.gui->scroll_to[1] = module->expander; } /* handle shiftclick on expander, hide all except this */ if(!dt_conf_get_bool("lighttable/ui/single_module") != !(e->state & GDK_SHIFT_MASK)) { GList *it = g_list_first(darktable.lib->plugins); const dt_view_t *v = dt_view_manager_get_current_view(darktable.view_manager); gboolean all_other_closed = TRUE; while(it) { dt_lib_module_t *m = (dt_lib_module_t *)it->data; if(m != module && container == m->container(module) && m->expandable(module) && (m->views(module) & v->view(v))) { all_other_closed = all_other_closed && !dtgtk_expander_get_expanded(DTGTK_EXPANDER(m->expander)); dt_lib_gui_set_expanded(m, FALSE); } it = g_list_next(it); } if(all_other_closed) dt_lib_gui_set_expanded(module, !dtgtk_expander_get_expanded(DTGTK_EXPANDER(module->expander))); else dt_lib_gui_set_expanded(module, TRUE); } else { /* else just toggle */ dt_lib_gui_set_expanded(module, !dtgtk_expander_get_expanded(DTGTK_EXPANDER(module->expander))); } return TRUE; } else if(e->button == 2) { /* show preset popup if any preset for module */ return TRUE; } return FALSE; }
uint32_t container(dt_lib_module_t *self) { const dt_view_t *cv = dt_view_manager_get_current_view(darktable.view_manager); if(cv->view((dt_view_t *)cv) == DT_VIEW_DARKROOM) return DT_UI_CONTAINER_PANEL_LEFT_CENTER; else return DT_UI_CONTAINER_PANEL_RIGHT_CENTER; }
void dt_lib_gui_set_expanded(dt_lib_module_t *module, gboolean expanded) { if(!module->expander) return; dtgtk_expander_set_expanded(DTGTK_EXPANDER(module->expander), expanded); /* update expander arrow state */ GtkWidget *icon; GtkWidget *header = dtgtk_expander_get_header(DTGTK_EXPANDER(module->expander)); gint flags = CPF_DIRECTION_DOWN; int c = module->container(module); GList *header_childs = gtk_container_get_children(GTK_CONTAINER(header)); if((c == DT_UI_CONTAINER_PANEL_LEFT_TOP) || (c == DT_UI_CONTAINER_PANEL_LEFT_CENTER) || (c == DT_UI_CONTAINER_PANEL_LEFT_BOTTOM)) { icon = g_list_nth_data(header_childs, 0); if(!expanded) flags = CPF_DIRECTION_RIGHT; } else { icon = g_list_last(header_childs)->data; if(!expanded) flags = CPF_DIRECTION_LEFT; } g_list_free(header_childs); dtgtk_icon_set_paint(icon, dtgtk_cairo_paint_solid_arrow, flags); /* show / hide plugin widget */ if(expanded) { /* register to receive draw events */ darktable.lib->gui_module = module; /* focus the current module */ for(int k = 0; k < DT_UI_CONTAINER_SIZE; k++) dt_ui_container_focus_widget(darktable.gui->ui, k, GTK_WIDGET(module->expander)); } else { if(darktable.lib->gui_module == module) { darktable.lib->gui_module = NULL; dt_control_queue_redraw(); } } /* store expanded state of module */ char var[1024]; const dt_view_t *current_view = dt_view_manager_get_current_view(darktable.view_manager); snprintf(var, sizeof(var), "plugins/%s/%s/expanded", current_view->module_name, module->plugin_name); dt_conf_set_bool(var, expanded); }
gboolean dt_lib_gui_get_expanded(dt_lib_module_t *module) { if(!module->expandable(module)) return true; if(!module->expander) return true; if(!module->widget) { char var[1024]; const dt_view_t *current_view = dt_view_manager_get_current_view(darktable.view_manager); snprintf(var, sizeof(var), "plugins/%s/%s/expanded", current_view->module_name, module->plugin_name); return dt_conf_get_bool(var); } return dtgtk_expander_get_expanded(DTGTK_EXPANDER(module->expander)); }
static gboolean borders_button_pressed (GtkWidget *w, GdkEventButton *event, gpointer user_data) { dt_ui_t *ui = (dt_ui_t*)user_data; const dt_view_t *cv = dt_view_manager_get_current_view(darktable.view_manager); char key[512]; long which = (long)g_object_get_data(G_OBJECT(w),"border"); switch(which) { case 0: // left border { g_snprintf(key, 512, "%s/ui/%s_visible", cv->module_name, _ui_panel_config_names[DT_UI_PANEL_LEFT]); dt_ui_panel_show(ui, DT_UI_PANEL_LEFT, !dt_conf_get_bool(key)); } break; case 1: // right border { g_snprintf(key, 512, "%s/ui/%s_visible", cv->module_name, _ui_panel_config_names[DT_UI_PANEL_RIGHT]); dt_ui_panel_show(ui, DT_UI_PANEL_RIGHT, !dt_conf_get_bool(key)); } break; case 2: // top border { g_snprintf(key, 512, "%s/ui/%s_visible", cv->module_name, _ui_panel_config_names[DT_UI_PANEL_CENTER_TOP]); gboolean show = !dt_conf_get_bool(key); dt_ui_panel_show(ui, DT_UI_PANEL_CENTER_TOP, show); /* special case show header */ g_snprintf(key, 512, "%s/ui/show_header", cv->module_name); if (dt_conf_get_bool(key)) dt_ui_panel_show(ui, DT_UI_PANEL_TOP, show); } break; case 4: // bottom border default: { g_snprintf(key, 512, "%s/ui/%s_visible", cv->module_name, _ui_panel_config_names[DT_UI_PANEL_CENTER_BOTTOM]); gboolean show = !dt_conf_get_bool(key); dt_ui_panel_show(ui, DT_UI_PANEL_CENTER_BOTTOM, show); dt_ui_panel_show(ui, DT_UI_PANEL_BOTTOM, show); } break; } gtk_widget_queue_draw(w); return TRUE; }
static int current_view_cb(lua_State *L) { if(lua_gettop(L) > 0) { luaL_argcheck(L,dt_lua_isa(L,1,dt_view_t),1,"dt_view_t expected"); dt_view_t * module = *(dt_view_t**)lua_touserdata(L,1); int i = 0; while(i< darktable.view_manager->num_views && module != &darktable.view_manager->view[i]) i++; if(i == darktable.view_manager->num_views) return luaL_error(L,"should never happen : %s %d\n",__FILE__,__LINE__); dt_ctl_switch_mode_to(i); } const dt_view_t* current_view = dt_view_manager_get_current_view(darktable.view_manager); dt_lua_module_push_entry(L,"view",current_view->module_name); return 1; }
static int current_view_cb(lua_State *L) { if(lua_gettop(L) > 0) { dt_view_t *module; luaA_to(L,dt_lua_view_t,&module,1); int i = 0; while(i < darktable.view_manager->num_views && module != &darktable.view_manager->view[i]) i++; if(i == darktable.view_manager->num_views) return luaL_error(L, "should never happen : %s %d\n", __FILE__, __LINE__); dt_ctl_switch_mode_to(i); } const dt_view_t *current_view = dt_view_manager_get_current_view(darktable.view_manager); dt_lua_module_entry_push(L, "view", current_view->module_name); return 1; }
void dt_ui_toggle_panels_visibility(struct dt_ui_t *ui) { char key[512]; const dt_view_t *cv = dt_view_manager_get_current_view(darktable.view_manager); g_snprintf(key, 512, "%s/ui/panel_collaps_state",cv->module_name); uint32_t state = dt_conf_get_int(key); if (state) { /* restore previous panel view states */ for (int k=0;k<DT_UI_PANEL_SIZE;k++) dt_ui_panel_show(ui, k, (state>>k)&1); /* reset state */ state = 0; } else { /* store current panel view state */ for (int k=0;k<DT_UI_PANEL_SIZE;k++)
void dt_ctl_switch_mode() { const dt_view_t *view = dt_view_manager_get_current_view(darktable.view_manager); const char *mode = (view && !strcmp(view->module_name, "lighttable")) ? "darkroom" : "lighttable"; dt_ctl_switch_mode_to(mode); }
void dt_ctl_switch_mode_to_by_view(const dt_view_t *view) { if(view == dt_view_manager_get_current_view(darktable.view_manager)) return; g_main_context_invoke(NULL, _dt_ctl_switch_mode_to_by_view, (gpointer)view); }
/* update all values to reflect mouse over image id or no data at all */ static void _metadata_view_update_values(dt_lib_module_t *self) { dt_lib_metadata_view_t *d = (dt_lib_metadata_view_t *)self->data; int32_t mouse_over_id = dt_control_get_mouse_over_id(); if (mouse_over_id == -1) { const dt_view_t *cv = dt_view_manager_get_current_view(darktable.view_manager); if(cv->view((dt_view_t*)cv) == DT_VIEW_DARKROOM) { mouse_over_id = darktable.develop->image_storage.id; } else { sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select imgid from selected_images limit 1", -1, &stmt, NULL); if(sqlite3_step(stmt) == SQLITE_ROW) mouse_over_id = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); } } if(mouse_over_id >= 0) { char value[512]; char pathname[PATH_MAX]; const dt_image_t *img = dt_image_cache_read_get(darktable.image_cache, mouse_over_id); if(!img) goto fill_minuses; if(img->film_id == -1) { dt_image_cache_read_release(darktable.image_cache, img); goto fill_minuses; } /* update all metadata */ dt_image_film_roll(img, value, sizeof(value)); _metadata_update_value(d->metadata[md_internal_filmroll], value); const int tp = 512; char tooltip[tp]; snprintf(tooltip, tp, _("double click to jump to film roll\n%s"), value); g_object_set(G_OBJECT(d->metadata[md_internal_filmroll]), "tooltip-text", tooltip, (char *)NULL); snprintf(value,sizeof(value),"%d", img->id); _metadata_update_value(d->metadata[md_internal_imgid], value); snprintf(value,sizeof(value),"%d", img->group_id); _metadata_update_value(d->metadata[md_internal_groupid], value); _metadata_update_value(d->metadata[md_internal_filename], img->filename); snprintf(value,sizeof(value),"%d", img->version); _metadata_update_value(d->metadata[md_internal_version], value); gboolean from_cache = FALSE; dt_image_full_path(img->id, pathname, sizeof(pathname), &from_cache); _metadata_update_value(d->metadata[md_internal_fullpath], pathname); snprintf(value, sizeof(value), "%s", (img->flags & DT_IMAGE_LOCAL_COPY)?_("yes"):_("no")); _metadata_update_value(d->metadata[md_internal_local_copy], value); // TODO: decide if this should be removed for a release. maybe #ifdef'ing to only add it to git compiles? // the bits of the flags { #define EMPTY_FIELD '.' #define FALSE_FIELD '.' #define TRUE_FIELD '!' char *tooltip = NULL; char *flag_descriptions[] = { N_("unused"), N_("unused/deprecated"), N_("ldr"), N_("raw"), N_("hdr"), N_("marked for deletion"), N_("auto-applying presets applied"), N_("legacy flag. set for all new images"), N_("local copy"), N_("has .txt"), N_("has .wav") }; char *tooltip_parts[13] = { 0 }; int next_tooltip_part = 0; memset(value, EMPTY_FIELD, sizeof(value)); int stars = img->flags & 0x7; char *star_string = NULL; if(stars == 6) { value[0] = 'x'; tooltip_parts[next_tooltip_part++] = _("image rejected"); } else { value[0] = '0' + stars; tooltip_parts[next_tooltip_part++] = star_string = g_strdup_printf(ngettext("image has %d star", "image has %d stars", stars), stars); } if(img->flags & 8) { value[1] = TRUE_FIELD; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[0]); } else value[1] = FALSE_FIELD; if(img->flags & DT_IMAGE_THUMBNAIL_DEPRECATED) { value[2] = TRUE_FIELD; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[1]); } else value[2] = FALSE_FIELD; if(img->flags & DT_IMAGE_LDR) { value[3] = 'l'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[2]); } if(img->flags & DT_IMAGE_RAW) { value[4] = 'r'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[3]); } if(img->flags & DT_IMAGE_HDR) { value[5] = 'h'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[4]); } if(img->flags & DT_IMAGE_REMOVE) { value[6] = 'd'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[5]); } if(img->flags & DT_IMAGE_AUTO_PRESETS_APPLIED) { value[7] = 'a'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[6]); } if(img->flags & DT_IMAGE_NO_LEGACY_PRESETS) { value[8] = 'p'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[7]); } if(img->flags & DT_IMAGE_LOCAL_COPY) { value[9] = 'c'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[8]); } if(img->flags & DT_IMAGE_HAS_TXT) { value[10] = 't'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[9]); } if(img->flags & DT_IMAGE_HAS_WAV) { value[11] = 'w'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[10]); } value[12] = '\0'; tooltip = g_strjoinv("\n", tooltip_parts); _metadata_update_value(d->metadata[md_internal_flags], value); g_object_set(G_OBJECT(d->metadata[md_internal_flags]), "tooltip-text", tooltip, (char *)NULL); g_free(star_string); g_free(tooltip); #undef EMPTY_FIELD #undef FALSE_FIELD #undef TRUE_FIELD } /* EXIF */ _metadata_update_value_end(d->metadata[md_exif_model], img->exif_model); _metadata_update_value_end(d->metadata[md_exif_lens], img->exif_lens); _metadata_update_value_end(d->metadata[md_exif_maker], img->exif_maker); snprintf(value, sizeof(value), "F/%.1f", img->exif_aperture); _metadata_update_value(d->metadata[md_exif_aperture], value); if(img->exif_exposure <= 0.5) snprintf(value, sizeof(value), "1/%.0f", 1.0/img->exif_exposure); else snprintf(value, sizeof(value), "%.1f''", img->exif_exposure); _metadata_update_value(d->metadata[md_exif_exposure], value); snprintf(value, sizeof(value), "%.0f mm", img->exif_focal_length); _metadata_update_value(d->metadata[md_exif_focal_length], value); if (isnan(img->exif_focus_distance) || fpclassify(img->exif_focus_distance) == FP_ZERO) { _metadata_update_value(d->metadata[md_exif_focus_distance], NODATA_STRING); } else { snprintf(value, sizeof(value), "%.2f m", img->exif_focus_distance); _metadata_update_value(d->metadata[md_exif_focus_distance], value); } snprintf(value, sizeof(value), "%.0f", img->exif_iso); _metadata_update_value(d->metadata[md_exif_iso], value); _metadata_update_value(d->metadata[md_exif_datetime], img->exif_datetime_taken); snprintf(value, sizeof(value), "%d", img->height); _metadata_update_value(d->metadata[md_exif_height], value); snprintf(value, sizeof(value), "%d", img->width); _metadata_update_value(d->metadata[md_exif_width], value); /* XMP */ GList *res; if((res = dt_metadata_get(img->id, "Xmp.dc.title", NULL))!=NULL) { snprintf(value, sizeof(value), "%s", (char*)res->data); _filter_non_printable(value, sizeof(value)); g_list_free_full(res, &g_free); } else snprintf(value, sizeof(value), NODATA_STRING); _metadata_update_value(d->metadata[md_xmp_title], value); if((res = dt_metadata_get(img->id, "Xmp.dc.creator", NULL))!=NULL) { snprintf(value, sizeof(value), "%s", (char*)res->data); _filter_non_printable(value, sizeof(value)); g_list_free_full(res, &g_free); } else snprintf(value, sizeof(value), NODATA_STRING); _metadata_update_value(d->metadata[md_xmp_creator], value); if((res = dt_metadata_get(img->id, "Xmp.dc.rights", NULL))!=NULL) { snprintf(value, sizeof(value), "%s", (char*)res->data); _filter_non_printable(value, sizeof(value)); g_list_free_full(res, &g_free); } else snprintf(value, sizeof(value), NODATA_STRING); _metadata_update_value(d->metadata[md_xmp_rights], value); /* geotagging */ /* latitude */ if(isnan(img->latitude)) { _metadata_update_value(d->metadata[md_geotagging_lat], NODATA_STRING); } else { #ifdef HAVE_MAP if(dt_conf_get_bool("plugins/lighttable/metadata_view/pretty_location")) { gchar *latitude = osd_latitude_str(img->latitude); _metadata_update_value(d->metadata[md_geotagging_lat], latitude); g_free(latitude); } else { #endif gchar NS = img->latitude<0?'S':'N'; snprintf(value, sizeof(value), "%c %09.6f", NS, fabs(img->latitude)); _metadata_update_value(d->metadata[md_geotagging_lat], value); #ifdef HAVE_MAP } #endif } /* longitude */ if(isnan(img->longitude)) { _metadata_update_value(d->metadata[md_geotagging_lon], NODATA_STRING); } else { #ifdef HAVE_MAP if(dt_conf_get_bool("plugins/lighttable/metadata_view/pretty_location")) { gchar *longitude = osd_longitude_str(img->longitude); _metadata_update_value(d->metadata[md_geotagging_lon], longitude); g_free(longitude); } else { #endif gchar EW = img->longitude<0?'W':'E'; snprintf(value, sizeof(value), "%c %010.6f", EW, fabs(img->longitude)); _metadata_update_value(d->metadata[md_geotagging_lon], value); #ifdef HAVE_MAP } #endif } /* release img */ dt_image_cache_read_release(darktable.image_cache, img); } return; /* reset */ fill_minuses: for(int k=0; k<md_size; k++) _metadata_update_value(d->metadata[k],NODATA_STRING); }
int dt_history_copy_and_paste_on_image(int32_t imgid, int32_t dest_imgid, gboolean merge, GList *ops) { sqlite3_stmt *stmt; if(imgid == dest_imgid) return 1; if(imgid == -1) { dt_control_log(_("you need to copy history from an image before you paste it onto another")); return 1; } // be sure the current history is written before pasting some other history data const dt_view_t *cv = dt_view_manager_get_current_view(darktable.view_manager); if(cv->view((dt_view_t *)cv) == DT_VIEW_DARKROOM) dt_dev_write_history(darktable.develop); /* if merge onto history stack, lets find history offest in destination image */ int32_t offs = 0; if(merge) { /* apply on top of history stack */ // first trim the stack to get rid of whatever is above the selected entry DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.history WHERE imgid = ?1 AND num >= (SELECT history_end " "FROM main.images WHERE id = imgid)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT IFNULL(MAX(num), -1)+1 FROM main.history WHERE imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); if(sqlite3_step(stmt) == SQLITE_ROW) offs = sqlite3_column_int(stmt, 0); } else { /* replace history stack */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.history WHERE imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); sqlite3_step(stmt); } sqlite3_finalize(stmt); /* delete all items from the temp styles_items, this table is used only to get a ROWNUM of the results */ DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "DELETE FROM memory.style_items", NULL, NULL, NULL); /* copy history items from styles onto temp table */ // prepare SQL request char req[2048]; g_strlcpy(req, "INSERT INTO memory.style_items (num, module, operation, op_params, enabled, blendop_params, " "blendop_version, multi_name, multi_priority) SELECT num, module, operation, " "op_params, enabled, blendop_params, blendop_version, multi_name, multi_priority FROM " "main.history WHERE imgid = ?1", sizeof(req)); // Add ops selection if any format: ... and num in (val1, val2) if(ops) { GList *l = ops; int first = 1; g_strlcat(req, " AND num IN (", sizeof(req)); while(l) { unsigned int value = GPOINTER_TO_UINT(l->data); char v[30]; if(!first) g_strlcat(req, ",", sizeof(req)); snprintf(v, sizeof(v), "%u", value); g_strlcat(req, v, sizeof(req)); first = 0; l = g_list_next(l); } g_strlcat(req, ")", sizeof(req)); } DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), req, -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); /* copy the history items into the history of the dest image */ /* note: rowid starts at 1 while num has to start at 0! */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "INSERT INTO main.history " "(imgid,num,module,operation,op_params,enabled,blendop_params,blendop_" "version,multi_priority,multi_name) SELECT " "?1,?2+rowid-1,module,operation,op_params,enabled,blendop_params,blendop_" "version,multi_priority,multi_name FROM memory.style_items", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, offs); sqlite3_step(stmt); sqlite3_finalize(stmt); if(merge && ops) _dt_history_cleanup_multi_instance(dest_imgid, offs); // we have to copy masks too // what to do with existing masks ? if(merge) { // there's very little chance that we will have same shapes id. // but we may want to handle this case anyway // and it's not trivial at all ! } else { // let's remove all existing shapes DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.mask WHERE imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); } // let's copy now g_strlcpy(req, "INSERT INTO main.mask (imgid, formid, form, name, version, points, points_count, source) SELECT " "?1, formid, form, name, version, points, points_count, source FROM main.mask WHERE imgid = ?2", sizeof(req)); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), req, -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); // always make the whole stack active DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "UPDATE main.images SET history_end = (SELECT MAX(num) + 1 FROM main.history " "WHERE imgid = ?1) WHERE id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); /* if current image in develop reload history */ if(dt_dev_is_current_image(darktable.develop, dest_imgid)) { dt_dev_reload_history_items(darktable.develop); dt_dev_modulegroups_set(darktable.develop, dt_dev_modulegroups_get(darktable.develop)); } /* update xmp file */ dt_image_synch_xmp(dest_imgid); dt_mipmap_cache_remove(darktable.mipmap_cache, dest_imgid); return 0; }
/* update all values to reflect mouse over image id or no data at all */ static void _metadata_view_update_values(dt_lib_module_t *self) { dt_lib_metadata_view_t *d = (dt_lib_metadata_view_t *)self->data; int32_t mouse_over_id = dt_control_get_mouse_over_id(); if(mouse_over_id == -1) { const dt_view_t *cv = dt_view_manager_get_current_view(darktable.view_manager); if(cv->view((dt_view_t *)cv) == DT_VIEW_DARKROOM) { mouse_over_id = darktable.develop->image_storage.id; } else { sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select imgid from selected_images limit 1", -1, &stmt, NULL); if(sqlite3_step(stmt) == SQLITE_ROW) mouse_over_id = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); } } if(mouse_over_id >= 0) { char value[512]; char pathname[PATH_MAX] = { 0 }; const dt_image_t *img = dt_image_cache_get(darktable.image_cache, mouse_over_id, 'r'); if(!img) goto fill_minuses; if(img->film_id == -1) { dt_image_cache_read_release(darktable.image_cache, img); goto fill_minuses; } /* update all metadata */ dt_image_film_roll(img, value, sizeof(value)); _metadata_update_value(d->metadata[md_internal_filmroll], value); const int tp = 512; char tooltip[tp]; snprintf(tooltip, tp, _("double click to jump to film roll\n%s"), value); gtk_widget_set_tooltip_text(GTK_WIDGET(d->metadata[md_internal_filmroll]), tooltip); snprintf(value, sizeof(value), "%d", img->id); _metadata_update_value(d->metadata[md_internal_imgid], value); snprintf(value, sizeof(value), "%d", img->group_id); _metadata_update_value(d->metadata[md_internal_groupid], value); _metadata_update_value(d->metadata[md_internal_filename], img->filename); snprintf(value, sizeof(value), "%d", img->version); _metadata_update_value(d->metadata[md_internal_version], value); gboolean from_cache = FALSE; dt_image_full_path(img->id, pathname, sizeof(pathname), &from_cache); _metadata_update_value(d->metadata[md_internal_fullpath], pathname); snprintf(value, sizeof(value), "%s", (img->flags & DT_IMAGE_LOCAL_COPY) ? _("yes") : _("no")); _metadata_update_value(d->metadata[md_internal_local_copy], value); // TODO: decide if this should be removed for a release. maybe #ifdef'ing to only add it to git compiles? // the bits of the flags #if SHOW_FLAGS { #define EMPTY_FIELD '.' #define FALSE_FIELD '.' #define TRUE_FIELD '!' char *tooltip = NULL; char *flag_descriptions[] = { N_("unused"), N_("unused/deprecated"), N_("ldr"), N_("raw"), N_("hdr"), N_("marked for deletion"), N_("auto-applying presets applied"), N_("legacy flag. set for all new images"), N_("local copy"), N_("has .txt"), N_("has .wav") }; char *tooltip_parts[14] = { 0 }; int next_tooltip_part = 0; memset(value, EMPTY_FIELD, sizeof(value)); int stars = img->flags & 0x7; char *star_string = NULL; if(stars == 6) { value[0] = 'x'; tooltip_parts[next_tooltip_part++] = _("image rejected"); } else { value[0] = '0' + stars; tooltip_parts[next_tooltip_part++] = star_string = g_strdup_printf(ngettext("image has %d star", "image has %d stars", stars), stars); } if(img->flags & 8) { value[1] = TRUE_FIELD; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[0]); } else value[1] = FALSE_FIELD; if(img->flags & DT_IMAGE_THUMBNAIL_DEPRECATED) { value[2] = TRUE_FIELD; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[1]); } else value[2] = FALSE_FIELD; if(img->flags & DT_IMAGE_LDR) { value[3] = 'l'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[2]); } if(img->flags & DT_IMAGE_RAW) { value[4] = 'r'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[3]); } if(img->flags & DT_IMAGE_HDR) { value[5] = 'h'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[4]); } if(img->flags & DT_IMAGE_REMOVE) { value[6] = 'd'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[5]); } if(img->flags & DT_IMAGE_AUTO_PRESETS_APPLIED) { value[7] = 'a'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[6]); } if(img->flags & DT_IMAGE_NO_LEGACY_PRESETS) { value[8] = 'p'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[7]); } if(img->flags & DT_IMAGE_LOCAL_COPY) { value[9] = 'c'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[8]); } if(img->flags & DT_IMAGE_HAS_TXT) { value[10] = 't'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[9]); } if(img->flags & DT_IMAGE_HAS_WAV) { value[11] = 'w'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[10]); } static const struct { char *tooltip; char flag; } loaders[] = { { N_("unknown"), EMPTY_FIELD}, { N_("tiff"), 't'}, { N_("png"), 'p'}, { N_("j2k"), 'J'}, { N_("jpeg"), 'j'}, { N_("exr"), 'e'}, { N_("rgbe"), 'R'}, { N_("pfm"), 'P'}, { N_("GraphicsMagick"), 'g'}, { N_("rawspeed"), 'r'} }; int loader = (unsigned int)img->loader < sizeof(loaders) / sizeof(*loaders) ? img->loader : 0; value[12] = loaders[loader].flag; char *loader_tooltip = g_strdup_printf(_("loader: %s"), _(loaders[loader].tooltip)); tooltip_parts[next_tooltip_part++] = loader_tooltip; value[13] = '\0'; tooltip = g_strjoinv("\n", tooltip_parts); g_free(loader_tooltip); _metadata_update_value(d->metadata[md_internal_flags], value); gtk_widget_set_tooltip_text(GTK_WIDGET(d->metadata[md_internal_flags]), tooltip); g_free(star_string); g_free(tooltip); #undef EMPTY_FIELD #undef FALSE_FIELD #undef TRUE_FIELD } #endif // SHOW_FLAGS /* EXIF */ _metadata_update_value_end(d->metadata[md_exif_model], img->camera_alias); _metadata_update_value_end(d->metadata[md_exif_lens], img->exif_lens); _metadata_update_value_end(d->metadata[md_exif_maker], img->camera_maker); snprintf(value, sizeof(value), "F/%.1f", img->exif_aperture); _metadata_update_value(d->metadata[md_exif_aperture], value); if(img->exif_exposure <= 0.5) snprintf(value, sizeof(value), "1/%.0f", 1.0 / img->exif_exposure); else snprintf(value, sizeof(value), "%.1f''", img->exif_exposure); _metadata_update_value(d->metadata[md_exif_exposure], value); snprintf(value, sizeof(value), "%.0f mm", img->exif_focal_length); _metadata_update_value(d->metadata[md_exif_focal_length], value); if(isnan(img->exif_focus_distance) || fpclassify(img->exif_focus_distance) == FP_ZERO) { _metadata_update_value(d->metadata[md_exif_focus_distance], NODATA_STRING); } else { snprintf(value, sizeof(value), "%.2f m", img->exif_focus_distance); _metadata_update_value(d->metadata[md_exif_focus_distance], value); } snprintf(value, sizeof(value), "%.0f", img->exif_iso); _metadata_update_value(d->metadata[md_exif_iso], value); struct tm tt_exif = { 0 }; if(sscanf(img->exif_datetime_taken, "%d:%d:%d %d:%d:%d", &tt_exif.tm_year, &tt_exif.tm_mon, &tt_exif.tm_mday, &tt_exif.tm_hour, &tt_exif.tm_min, &tt_exif.tm_sec) == 6) { char datetime[200]; tt_exif.tm_year -= 1900; tt_exif.tm_mon--; tt_exif.tm_isdst = -1; mktime(&tt_exif); // just %c is too long and includes a time zone that we don't know from exif strftime(datetime, sizeof(datetime), "%a %x %X", &tt_exif); _metadata_update_value(d->metadata[md_exif_datetime], datetime); } else _metadata_update_value(d->metadata[md_exif_datetime], img->exif_datetime_taken); snprintf(value, sizeof(value), "%d", img->height); _metadata_update_value(d->metadata[md_exif_height], value); snprintf(value, sizeof(value), "%d", img->width); _metadata_update_value(d->metadata[md_exif_width], value); /* XMP */ GList *res; if((res = dt_metadata_get(img->id, "Xmp.dc.title", NULL)) != NULL) { snprintf(value, sizeof(value), "%s", (char *)res->data); _filter_non_printable(value, sizeof(value)); g_list_free_full(res, &g_free); } else snprintf(value, sizeof(value), NODATA_STRING); _metadata_update_value(d->metadata[md_xmp_title], value); if((res = dt_metadata_get(img->id, "Xmp.dc.creator", NULL)) != NULL) { snprintf(value, sizeof(value), "%s", (char *)res->data); _filter_non_printable(value, sizeof(value)); g_list_free_full(res, &g_free); } else snprintf(value, sizeof(value), NODATA_STRING); _metadata_update_value(d->metadata[md_xmp_creator], value); if((res = dt_metadata_get(img->id, "Xmp.dc.rights", NULL)) != NULL) { snprintf(value, sizeof(value), "%s", (char *)res->data); _filter_non_printable(value, sizeof(value)); g_list_free_full(res, &g_free); } else snprintf(value, sizeof(value), NODATA_STRING); _metadata_update_value(d->metadata[md_xmp_rights], value); /* geotagging */ /* latitude */ if(isnan(img->latitude)) { _metadata_update_value(d->metadata[md_geotagging_lat], NODATA_STRING); } else { if(dt_conf_get_bool("plugins/lighttable/metadata_view/pretty_location")) { gchar *latitude = dt_util_latitude_str(img->latitude); _metadata_update_value(d->metadata[md_geotagging_lat], latitude); g_free(latitude); } else { gchar NS = img->latitude < 0 ? 'S' : 'N'; snprintf(value, sizeof(value), "%c %09.6f", NS, fabs(img->latitude)); _metadata_update_value(d->metadata[md_geotagging_lat], value); } } /* longitude */ if(isnan(img->longitude)) { _metadata_update_value(d->metadata[md_geotagging_lon], NODATA_STRING); } else { if(dt_conf_get_bool("plugins/lighttable/metadata_view/pretty_location")) { gchar *longitude = dt_util_longitude_str(img->longitude); _metadata_update_value(d->metadata[md_geotagging_lon], longitude); g_free(longitude); } else { gchar EW = img->longitude < 0 ? 'W' : 'E'; snprintf(value, sizeof(value), "%c %010.6f", EW, fabs(img->longitude)); _metadata_update_value(d->metadata[md_geotagging_lon], value); } } /* elevation */ if(isnan(img->elevation)) { _metadata_update_value(d->metadata[md_geotagging_ele], NODATA_STRING); } else { if(dt_conf_get_bool("plugins/lighttable/metadata_view/pretty_location")) { gchar *elevation = dt_util_elevation_str(img->elevation); _metadata_update_value(d->metadata[md_geotagging_ele], elevation); g_free(elevation); } else { snprintf(value, sizeof(value), "%.2f %s", img->elevation, _("m")); _metadata_update_value(d->metadata[md_geotagging_ele], value); } } /* release img */ dt_image_cache_read_release(darktable.image_cache, img); #ifdef USE_LUA dt_lua_async_call_alien(lua_update_metadata, 0,NULL,NULL, LUA_ASYNC_TYPENAME,"void*",self, LUA_ASYNC_TYPENAME,"int32_t",mouse_over_id,LUA_ASYNC_DONE); #endif } return; /* reset */ fill_minuses: for(int k = 0; k < md_size; k++) _metadata_update_value(d->metadata[k], NODATA_STRING); #ifdef USE_LUA dt_lua_async_call_alien(lua_update_metadata, 0,NULL,NULL, LUA_ASYNC_TYPENAME,"void*",self, LUA_ASYNC_TYPENAME,"int32_t",-1,LUA_ASYNC_DONE); #endif }
int dt_control_key_pressed_override(guint key, guint state) { dt_control_accels_t *accels = &darktable.control->accels; // TODO: if darkroom mode // did a : vim-style command start? static GList *autocomplete = NULL; static char vimkey_input[256]; if(darktable.control->vimkey_cnt) { guchar unichar = gdk_keyval_to_unicode(key); if(key == GDK_KEY_Return) { if(!strcmp(darktable.control->vimkey, ":q")) { dt_control_quit(); } else { dt_bauhaus_vimkey_exec(darktable.control->vimkey); } darktable.control->vimkey[0] = 0; darktable.control->vimkey_cnt = 0; dt_control_log_ack_all(); g_list_free(autocomplete); autocomplete = NULL; } else if(key == GDK_KEY_Escape) { darktable.control->vimkey[0] = 0; darktable.control->vimkey_cnt = 0; dt_control_log_ack_all(); g_list_free(autocomplete); autocomplete = NULL; } else if(key == GDK_KEY_BackSpace) { darktable.control->vimkey_cnt -= (darktable.control->vimkey + darktable.control->vimkey_cnt) - g_utf8_prev_char(darktable.control->vimkey + darktable.control->vimkey_cnt); darktable.control->vimkey[darktable.control->vimkey_cnt] = 0; if(darktable.control->vimkey_cnt == 0) dt_control_log_ack_all(); else dt_control_log("%s", darktable.control->vimkey); g_list_free(autocomplete); autocomplete = NULL; } else if(key == GDK_KEY_Tab) { // TODO: also support :preset and :get? // auto complete: if(darktable.control->vimkey_cnt < 5) { snprintf(darktable.control->vimkey, sizeof(darktable.control->vimkey), ":set "); darktable.control->vimkey_cnt = 5; } else if(!autocomplete) { // TODO: handle '.'-separated things separately // this is a static list, and tab cycles through the list g_strlcpy(vimkey_input, darktable.control->vimkey + 5, sizeof(vimkey_input)); autocomplete = dt_bauhaus_vimkey_complete(darktable.control->vimkey + 5); autocomplete = g_list_append(autocomplete, vimkey_input); // remember input to cycle back } if(autocomplete) { // pop first. // the paths themselves are owned by bauhaus, // no free required. snprintf(darktable.control->vimkey, sizeof(darktable.control->vimkey), ":set %s", (char *)autocomplete->data); autocomplete = g_list_remove(autocomplete, autocomplete->data); darktable.control->vimkey_cnt = strlen(darktable.control->vimkey); } dt_control_log("%s", darktable.control->vimkey); } else if(g_unichar_isprint(unichar)) // printable unicode character { gchar utf8[6]; gint char_width = g_unichar_to_utf8(unichar, utf8); if(darktable.control->vimkey_cnt + 1 + char_width < 256) { g_utf8_strncpy(darktable.control->vimkey + darktable.control->vimkey_cnt, utf8, 1); darktable.control->vimkey_cnt += char_width; darktable.control->vimkey[darktable.control->vimkey_cnt] = 0; dt_control_log("%s", darktable.control->vimkey); g_list_free(autocomplete); autocomplete = NULL; } } else if(key == GDK_KEY_Up) { // TODO: step history up and copy to vimkey } else if(key == GDK_KEY_Down) { // TODO: step history down and copy to vimkey } return 1; } else if(key == ':' && darktable.control->key_accelerators_on) { darktable.control->vimkey[0] = ':'; darktable.control->vimkey[1] = 0; darktable.control->vimkey_cnt = 1; dt_control_log("%s", darktable.control->vimkey); return 1; } /* check if key accelerators are enabled*/ if(darktable.control->key_accelerators_on != 1) return 0; if(key == accels->global_sideborders.accel_key && state == accels->global_sideborders.accel_mods) { /* toggle panel viewstate */ dt_ui_toggle_panels_visibility(darktable.gui->ui); /* trigger invalidation of centerview to reprocess pipe */ dt_dev_invalidate(darktable.develop); gtk_widget_queue_draw(dt_ui_center(darktable.gui->ui)); return 1; } else if(key == accels->global_header.accel_key && state == accels->global_header.accel_mods) { char key[512]; const dt_view_t *cv = dt_view_manager_get_current_view(darktable.view_manager); /* do nothing if in collapse panel state TODO: reconsider adding this check to ui api */ g_snprintf(key, sizeof(key), "%s/ui/panel_collaps_state", cv->module_name); if(dt_conf_get_int(key)) return 0; /* toggle the header visibility state */ g_snprintf(key, sizeof(key), "%s/ui/show_header", cv->module_name); gboolean header = !dt_conf_get_bool(key); dt_conf_set_bool(key, header); /* show/hide the actual header panel */ dt_ui_panel_show(darktable.gui->ui, DT_UI_PANEL_TOP, header, TRUE); gtk_widget_queue_draw(dt_ui_center(darktable.gui->ui)); return 1; } return 0; }
/* update all values to reflect mouse over image id or no data at all */ static void _metadata_view_update_values(dt_lib_module_t *self) { dt_lib_metadata_view_t *d = (dt_lib_metadata_view_t *)self->data; int32_t mouse_over_id = dt_control_get_mouse_over_id(); if (mouse_over_id == -1) { const dt_view_t *cv = dt_view_manager_get_current_view(darktable.view_manager); if(cv->view((dt_view_t*)cv) == DT_VIEW_DARKROOM) { mouse_over_id = darktable.develop->image_storage.id; } else { sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select imgid from selected_images limit 1", -1, &stmt, NULL); if(sqlite3_step(stmt) == SQLITE_ROW) mouse_over_id = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); } } if(mouse_over_id >= 0) { char value[512]; char pathname[PATH_MAX]; const dt_image_t *img = dt_image_cache_read_get(darktable.image_cache, mouse_over_id); if(!img) goto fill_minuses; if(img->film_id == -1) { dt_image_cache_read_release(darktable.image_cache, img); goto fill_minuses; } /* update all metadata */ dt_image_film_roll(img, value, sizeof(value)); _metadata_update_value(d->metadata[md_internal_filmroll], value); const int tp = 512; char tooltip[tp]; snprintf(tooltip, tp, _("double click to jump to film roll\n%s"), value); g_object_set(G_OBJECT(d->metadata[md_internal_filmroll]), "tooltip-text", tooltip, (char *)NULL); snprintf(value,sizeof(value),"%d", img->id); _metadata_update_value(d->metadata[md_internal_imgid], value); _metadata_update_value(d->metadata[md_internal_filename], img->filename); snprintf(value,sizeof(value),"%d", img->version); _metadata_update_value(d->metadata[md_internal_version], value); gboolean from_cache = FALSE; dt_image_full_path(img->id, pathname, sizeof(pathname), &from_cache); _metadata_update_value(d->metadata[md_internal_fullpath], pathname); snprintf(value, sizeof(value), "%s", (img->flags & DT_IMAGE_LOCAL_COPY)?_("yes"):_("no")); _metadata_update_value(d->metadata[md_internal_local_copy], value); /* EXIF */ _metadata_update_value_end(d->metadata[md_exif_model], img->exif_model); _metadata_update_value_end(d->metadata[md_exif_lens], img->exif_lens); _metadata_update_value_end(d->metadata[md_exif_maker], img->exif_maker); snprintf(value, sizeof(value), "F/%.1f", img->exif_aperture); _metadata_update_value(d->metadata[md_exif_aperture], value); if(img->exif_exposure <= 0.5) snprintf(value, sizeof(value), "1/%.0f", 1.0/img->exif_exposure); else snprintf(value, sizeof(value), "%.1f''", img->exif_exposure); _metadata_update_value(d->metadata[md_exif_exposure], value); snprintf(value, sizeof(value), "%.0f mm", img->exif_focal_length); _metadata_update_value(d->metadata[md_exif_focal_length], value); if (isnan(img->exif_focus_distance) || fpclassify(img->exif_focus_distance) == FP_ZERO) { _metadata_update_value(d->metadata[md_exif_focus_distance], NODATA_STRING); } else { snprintf(value, sizeof(value), "%.2f m", img->exif_focus_distance); _metadata_update_value(d->metadata[md_exif_focus_distance], value); } snprintf(value, sizeof(value), "%.0f", img->exif_iso); _metadata_update_value(d->metadata[md_exif_iso], value); _metadata_update_value(d->metadata[md_exif_datetime], img->exif_datetime_taken); snprintf(value, sizeof(value), "%d", img->height); _metadata_update_value(d->metadata[md_exif_height], value); snprintf(value, sizeof(value), "%d", img->width); _metadata_update_value(d->metadata[md_exif_width], value); /* XMP */ GList *res; if((res = dt_metadata_get(img->id, "Xmp.dc.title", NULL))!=NULL) { snprintf(value, sizeof(value), "%s", (char*)res->data); _filter_non_printable(value, sizeof(value)); g_list_free_full(res, &g_free); } else snprintf(value, sizeof(value), NODATA_STRING); _metadata_update_value(d->metadata[md_xmp_title], value); if((res = dt_metadata_get(img->id, "Xmp.dc.creator", NULL))!=NULL) { snprintf(value, sizeof(value), "%s", (char*)res->data); _filter_non_printable(value, sizeof(value)); g_list_free_full(res, &g_free); } else snprintf(value, sizeof(value), NODATA_STRING); _metadata_update_value(d->metadata[md_xmp_creator], value); if((res = dt_metadata_get(img->id, "Xmp.dc.rights", NULL))!=NULL) { snprintf(value, sizeof(value), "%s", (char*)res->data); _filter_non_printable(value, sizeof(value)); g_list_free_full(res, &g_free); } else snprintf(value, sizeof(value), NODATA_STRING); _metadata_update_value(d->metadata[md_xmp_rights], value); /* geotagging */ /* latitude */ if(isnan(img->latitude)) { _metadata_update_value(d->metadata[md_geotagging_lat], NODATA_STRING); } else { #ifdef HAVE_MAP if(dt_conf_get_bool("plugins/lighttable/metadata_view/pretty_location")) { gchar *latitude = osd_latitude_str(img->latitude); _metadata_update_value(d->metadata[md_geotagging_lat], latitude); g_free(latitude); } else { #endif gchar NS = img->latitude<0?'S':'N'; snprintf(value, sizeof(value), "%c %09.6f", NS, fabs(img->latitude)); _metadata_update_value(d->metadata[md_geotagging_lat], value); #ifdef HAVE_MAP } #endif } /* longitude */ if(isnan(img->longitude)) { _metadata_update_value(d->metadata[md_geotagging_lon], NODATA_STRING); } else { #ifdef HAVE_MAP if(dt_conf_get_bool("plugins/lighttable/metadata_view/pretty_location")) { gchar *longitude = osd_longitude_str(img->longitude); _metadata_update_value(d->metadata[md_geotagging_lon], longitude); g_free(longitude); } else { #endif gchar EW = img->longitude<0?'W':'E'; snprintf(value, sizeof(value), "%c %010.6f", EW, fabs(img->longitude)); _metadata_update_value(d->metadata[md_geotagging_lon], value); #ifdef HAVE_MAP } #endif } /* release img */ dt_image_cache_read_release(darktable.image_cache, img); } return; /* reset */ fill_minuses: for(int k=0; k<md_size; k++) _metadata_update_value(d->metadata[k],NODATA_STRING); }