Hi Jefferson, Thanks for your interest. You may find my patch attached.
If you have any questions, please let me know. Best regards, Mario 2018-04-15 20:46 GMT+02:00 Mario Lüder <monsieur.m...@gmail.com>: > Hi, > > I missed the possibility to order images by drag and drop in lighttable. I > needed this for my image selection process. I have to see the image in the > right order to decide which one shall be kept and to see the sequence is > "working". > > I have seen on several forums and the bug tracker that others are also > keen to see this freature. > > So I took the time and implemented a simple version of it. > > Please see the short screencast on youtube > https://youtu.be/Z2dwCXXzxbU > > The custom sequence is stored for each collection. So you can select an > other collection and come back later to continue your work. > > I would like to post my changes for review. May I submit it to an > development branch? > > Best, > Mario > ___________________________________________________________________________ darktable developer mailing list to unsubscribe send a mail to darktable-dev+unsubscr...@lists.darktable.org
From d129ade50deb51c93159aef53b5298682db04adc Mon Sep 17 00:00:00 2001 From: Mario Lueder <monsieur.m...@gmail.com> Date: Sun, 15 Apr 2018 20:20:43 +0200 Subject: [PATCH] Added custom image order by drag and drop in lighttable --- src/common/collection.c | 246 +++++++++++++++++++++++++++++++++++++++++++++++- src/common/collection.h | 6 +- src/common/database.c | 20 +++- src/gui/gtk.c | 4 +- src/libs/tools/filter.c | 1 + src/views/lighttable.c | 91 +++++++++++++++++- 6 files changed, 360 insertions(+), 8 deletions(-) diff --git a/src/common/collection.c b/src/common/collection.c index 8fb39e9..4dff27d 100644 --- a/src/common/collection.c +++ b/src/common/collection.c @@ -63,6 +63,32 @@ static void _dt_collection_recount_callback_2(gpointer instance, uint8_t id, gpo /* determine image offset of specified imgid for the given collection */ static int dt_collection_image_offset_with_collection(const dt_collection_t *collection, int imgid); +/* insert images from filtered collection into a respected custom sorted collection */ +static void dt_collection_insert_custom_order_images(const dt_collection_t *collection); + +gchar * dt_collection_get_current_id() +{ + char confname[200]; + gchar * const separator = g_strdup(":"); + gchar * collection_id = g_strdup(""); + + const int num_rules = dt_conf_get_int("plugins/lighttable/collect/num_rules"); + + for (int i = 0; i < num_rules; ++i) + { + snprintf(confname, sizeof(confname), "plugins/lighttable/collect/string%1d", i); + gchar * const ruleName = dt_conf_get_string(confname); + gchar * new_collection_id = g_strconcat(collection_id, separator, ruleName, NULL); + g_free(ruleName); + g_free(collection_id); + collection_id = new_collection_id; + } + + g_free(separator); + + return collection_id; +} + const dt_collection_t *dt_collection_new(const dt_collection_t *clone) { dt_collection_t *collection = g_malloc0(sizeof(dt_collection_t)); @@ -185,6 +211,14 @@ int dt_collection_update(const dt_collection_t *collection) wq); else if(collection->params.query_flags & COLLECTION_QUERY_USE_ONLY_WHERE_EXT) selq = dt_util_dstrcat(selq, "SELECT DISTINCT images.id FROM main.images %s", wq); + else if(collection->params.sort == DT_COLLECTION_SORT_CUSTOM_ORDER + && (collection->params.query_flags & COLLECTION_QUERY_USE_SORT)) + { + gchar * const collection_id = dt_collection_get_current_id(); + selq = dt_util_dstrcat(selq, "SELECT DISTINCT id FROM (SELECT * FROM main.images WHERE %s) LEFT JOIN custom_image_order ON (id = img_id AND collection_id = '%s')", + wq, collection_id); + g_free(collection_id); + } else selq = dt_util_dstrcat(selq, "SELECT DISTINCT id FROM main.images WHERE %s", wq); @@ -390,6 +424,10 @@ gchar *dt_collection_get_sort_query(const dt_collection_t *collection) sq = dt_util_dstrcat(sq, ORDER_BY_QUERY, "folder DESC, filename DESC, version"); break; + case DT_COLLECTION_SORT_CUSTOM_ORDER: + sq = dt_util_dstrcat(sq, ORDER_BY_QUERY, "position DESC, filename DESC, version"); + break; + case DT_COLLECTION_SORT_NONE: // shouldn't happen break; @@ -427,6 +465,10 @@ gchar *dt_collection_get_sort_query(const dt_collection_t *collection) sq = dt_util_dstrcat(sq, ORDER_BY_QUERY, "folder, filename, version"); break; + case DT_COLLECTION_SORT_CUSTOM_ORDER: + sq = dt_util_dstrcat(sq, ORDER_BY_QUERY, "position, filename, version"); + break; + case DT_COLLECTION_SORT_NONE: // shouldn't happen break; @@ -516,7 +558,6 @@ GList *dt_collection_get(const dt_collection_t *collection, int limit, gboolean if((collection->params.query_flags & COLLECTION_QUERY_USE_SORT)) sq = dt_collection_get_sort_query(collection); - sqlite3_stmt *stmt = NULL; /* build the query string */ @@ -529,6 +570,14 @@ GList *dt_collection_get(const dt_collection_t *collection, int limit, gboolean && (collection->params.query_flags & COLLECTION_QUERY_USE_SORT)) query = dt_util_dstrcat( query, "JOIN (SELECT id AS film_rolls_id, folder FROM main.film_rolls) ON film_id = film_rolls_id "); + else if(collection->params.sort == DT_COLLECTION_SORT_CUSTOM_ORDER + && (collection->params.query_flags & COLLECTION_QUERY_USE_SORT)) + { + gchar * const collection_id = dt_collection_get_current_id(); + query = dt_util_dstrcat( + query, "LEFT JOIN custom_image_order ON (id = img_id AND '%s') ", collection_id); + g_free(collection_id); + } if (selected) query = dt_util_dstrcat(query, "WHERE id IN (SELECT imgid FROM main.selected_images) %s LIMIT ?1", sq); @@ -1217,6 +1266,8 @@ void dt_collection_update_query(const dt_collection_t *collection) g_free(complete_query); } + /* update the custom sorted collection */ + dt_collection_insert_custom_order_images(collection); /* raise signal of collection change, only if this is an original */ if(!collection->clone) dt_control_signal_raise(darktable.signals, DT_SIGNAL_COLLECTION_CHANGED); @@ -1331,6 +1382,199 @@ static void _dt_collection_recount_callback_2(gpointer instance, uint8_t id, gpo } } +/* move images with drag and drop */ +void dt_collection_move_before(const int32_t image_id, GList * selected_images) +{ + if (!selected_images) + { + return; + } + + const guint selected_images_length = g_list_length(selected_images); + + if (selected_images_length == 0) + { + return; + } + + gchar * const collection_id = dt_collection_get_current_id(); + + // TODO: to forget to add images to the end of the list + + // getting the position of the target image + int target_image_pos = -1; + + if (image_id >= 0) + { + sqlite3_stmt *stmt = NULL; + gchar *image_pos_query = NULL; + image_pos_query = dt_util_dstrcat( + image_pos_query, + "SELECT position FROM main.custom_image_order WHERE img_id = %i AND collection_id='%s'", + image_id, collection_id); + + DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), image_pos_query, -1, &stmt, NULL); + + if(sqlite3_step(stmt) == SQLITE_ROW) + { + target_image_pos = sqlite3_column_int(stmt, 0); + } + + sqlite3_finalize(stmt); + g_free(image_pos_query); + } + + if (target_image_pos >= 0) + { + DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "BEGIN;", NULL, NULL, NULL); + sqlite3_stmt *stmt = NULL; + + // shift image positions to make some space + gchar *update_image_pos_query = NULL; + update_image_pos_query = dt_util_dstrcat( + update_image_pos_query, + "UPDATE main.custom_image_order SET position = position + %i WHERE collection_id='%s' AND position >= %i", + selected_images_length, collection_id, target_image_pos); + + DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), update_image_pos_query, -1, &stmt, NULL); + sqlite3_step(stmt); + sqlite3_finalize(stmt); + g_free(update_image_pos_query); + DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "COMMIT;", NULL, NULL, NULL); + + DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "BEGIN;", NULL, NULL, NULL); + + // move images to their intended positons + int new_image_pos = target_image_pos; + + gchar *insert_image_pos_query = NULL; + insert_image_pos_query = dt_util_dstrcat( + insert_image_pos_query, + "UPDATE main.custom_image_order SET position = ?1 WHERE img_id = ?2 AND collection_id='%s'", + collection_id); + + DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), insert_image_pos_query, -1, &stmt, NULL); + + for (const GList * selected_images_iter = selected_images; + selected_images_iter != NULL; + selected_images_iter = selected_images_iter->next) + { + const int moved_image_id = GPOINTER_TO_INT(selected_images_iter->data); + + DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, new_image_pos); + DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, moved_image_id); + sqlite3_step(stmt); + sqlite3_reset(stmt); + new_image_pos++; + } + sqlite3_finalize(stmt); + g_free(insert_image_pos_query); + DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "COMMIT;", NULL, NULL, NULL); + } + else + { + // move images to the end of the list + sqlite3_stmt *stmt = NULL; + + // get last position + int max_position = -1; + + gchar *max_position_query = NULL; + max_position_query = dt_util_dstrcat(max_position_query, "SELECT MAX(position) FROM custom_image_order WHERE collection_id = '%s'", collection_id); + DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), max_position_query, -1, &stmt, NULL); + + if (sqlite3_step(stmt) == SQLITE_ROW) + { + max_position = sqlite3_column_int(stmt, 0); + } + + sqlite3_finalize(stmt); + g_free(max_position_query); + + sqlite3_stmt *update_stmt = NULL; + gchar *update_query = NULL; + + DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "BEGIN;", NULL, NULL, NULL); + + // move images to last position in custom image order table + update_query = dt_util_dstrcat(update_query, + "UPDATE main.custom_image_order SET position = ?1 WHERE img_id = ?2 AND collection_id='%s'", + collection_id); + DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), update_query, -1, &update_stmt, NULL); + + for (const GList * selected_images_iter = selected_images; + selected_images_iter != NULL; + selected_images_iter = selected_images_iter->next) + { + max_position++; + const int moved_image_id = GPOINTER_TO_INT(selected_images_iter->data); + DT_DEBUG_SQLITE3_BIND_INT(update_stmt, 1, max_position); + DT_DEBUG_SQLITE3_BIND_INT(update_stmt, 2, moved_image_id); + sqlite3_step(update_stmt); + sqlite3_reset(update_stmt); + } + + sqlite3_finalize(update_stmt); + g_free(update_query); + DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "COMMIT;", NULL, NULL, NULL); + } + + g_free(collection_id); +} + +static void dt_collection_insert_custom_order_images(const dt_collection_t *collection) +{ + sqlite3_stmt *stmt = NULL; + gchar * const collection_id = dt_collection_get_current_id(); + int max_position = -1; + + // get max position + gchar *max_position_query = NULL; + max_position_query = dt_util_dstrcat(max_position_query, "SELECT MAX(position) FROM custom_image_order WHERE collection_id = '%s'", collection_id); + DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), max_position_query, -1, &stmt, NULL); + + if (sqlite3_step(stmt) == SQLITE_ROW) + { + max_position = sqlite3_column_int(stmt, 0); + } + + sqlite3_finalize(stmt); + + // get images of filtered collection + DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "BEGIN;", NULL, NULL, NULL); + const gchar * image_collection_query = dt_collection_get_query(collection); + + DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), image_collection_query, -1, &stmt, NULL); + DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, 0); + DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, -1); + + sqlite3_stmt *ins_stmt = NULL; + gchar *insert_query = NULL; + + // insert images into custom order table if they don't exist - image id and collection id is key + insert_query = dt_util_dstrcat(insert_query, "INSERT OR IGNORE INTO custom_image_order(img_id, collection_id, position) VALUES(?1, '%s', ?2)", collection_id); + DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), insert_query, -1, &ins_stmt, NULL); + + while(sqlite3_step(stmt) == SQLITE_ROW) + { + max_position++; + const int img_id = sqlite3_column_int(stmt, 0); + DT_DEBUG_SQLITE3_BIND_INT(ins_stmt, 1, img_id); + DT_DEBUG_SQLITE3_BIND_INT(ins_stmt, 2, max_position); + sqlite3_step(ins_stmt); + sqlite3_reset(ins_stmt); + } + + DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "COMMIT;", NULL, NULL, NULL); + + sqlite3_finalize(stmt); + sqlite3_finalize(ins_stmt); + + g_free(insert_query); + g_free(max_position_query); + g_free(collection_id); +} + // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh // vim: shiftwidth=2 expandtab tabstop=2 cindent // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified; diff --git a/src/common/collection.h b/src/common/collection.h index fcc6e00..5e06db6 100644 --- a/src/common/collection.h +++ b/src/common/collection.h @@ -65,7 +65,8 @@ typedef enum dt_collection_sort_t DT_COLLECTION_SORT_ID, DT_COLLECTION_SORT_COLOR, DT_COLLECTION_SORT_GROUP, - DT_COLLECTION_SORT_PATH + DT_COLLECTION_SORT_PATH, + DT_COLLECTION_SORT_CUSTOM_ORDER } dt_collection_sort_t; typedef enum dt_collection_properties_t @@ -218,6 +219,9 @@ void dt_collection_split_operator_number(const gchar *input, char **number1, cha void dt_collection_split_operator_datetime(const gchar *input, char **number1, char **number2, char **operator); +/* move images with drag and drop */ +void dt_collection_move_before(const int32_t image_id, GList * selected_images); + // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh // vim: shiftwidth=2 expandtab tabstop=2 cindent // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified; diff --git a/src/common/database.c b/src/common/database.c index 06b4d1a..b635570 100644 --- a/src/common/database.c +++ b/src/common/database.c @@ -37,7 +37,7 @@ // whenever _create_*_schema() gets changed you HAVE to bump this version and add an update path to // _upgrade_*_schema_step()! -#define CURRENT_DATABASE_VERSION_LIBRARY 15 +#define CURRENT_DATABASE_VERSION_LIBRARY 16 #define CURRENT_DATABASE_VERSION_DATA 1 typedef struct dt_database_t @@ -967,6 +967,18 @@ static int _upgrade_library_schema_step(dt_database_t *db, int version) sqlite3_exec(db->handle, "COMMIT", NULL, NULL, NULL); new_version = 15; + } + else if(version == 15) + { + sqlite3_exec(db->handle, "BEGIN TRANSACTION", NULL, NULL, NULL); + ////////////////////////////// custom image order + TRY_EXEC("CREATE TABLE main.custom_image_order (img_id, INTEGER, collection_id TEXT, position INTEGER," + "PRIMARY KEY(img_id,collection_id));", + "[init] can't create a table to store custom image order\n"); + TRY_EXEC("CREATE INDEX main.custom_image_order_index ON custom_image_order (collection_id, position)", + "[init] can't create index for custom image order table\n"); + sqlite3_exec(db->handle, "COMMIT", NULL, NULL, NULL); + new_version = 16; } // maybe in the future, see commented out code elsewhere // else if(version == XXX) // { @@ -1118,6 +1130,12 @@ static void _create_library_schema(dt_database_t *db) ////////////////////////////// meta_data sqlite3_exec(db->handle, "CREATE TABLE main.meta_data (id INTEGER, key INTEGER, value VARCHAR)", NULL, NULL, NULL); sqlite3_exec(db->handle, "CREATE INDEX main.metadata_index ON meta_data (id, key)", NULL, NULL, NULL); + + ////////////////////////////// custom image order + sqlite3_exec(db->handle, "CREATE TABLE main.custom_image_order (img_id, INTEGER, collection_id TEXT, position INTEGER," + "PRIMARY KEY(img_id,collection_id));", NULL, NULL, NULL); + sqlite3_exec(db->handle, "CREATE INDEX main.custom_image_order_index ON custom_image_order (collection_id, position)", + NULL, NULL, NULL); } /* create the current database schema and set the version in db_info accordingly */ diff --git a/src/gui/gtk.c b/src/gui/gtk.c index 05c4a44..e65eb09 100644 --- a/src/gui/gtk.c +++ b/src/gui/gtk.c @@ -56,7 +56,6 @@ #endif #include <pthread.h> - /* * NEW UI API */ @@ -838,7 +837,7 @@ static gboolean button_pressed(GtkWidget *w, GdkEventButton *event, gpointer use dt_control_button_pressed(event->x, event->y, pressure, event->button, event->type, event->state & 0xf); gtk_widget_grab_focus(w); gtk_widget_queue_draw(w); - return TRUE; + return FALSE; } static gboolean button_released(GtkWidget *w, GdkEventButton *event, gpointer user_data) @@ -1016,6 +1015,7 @@ int dt_gui_gtk_init(dt_gui_gtk_t *gui) g_signal_connect(G_OBJECT(widget), "button-press-event", G_CALLBACK(button_pressed), NULL); g_signal_connect(G_OBJECT(widget), "button-release-event", G_CALLBACK(button_released), NULL); g_signal_connect(G_OBJECT(widget), "scroll-event", G_CALLBACK(scrolled), NULL); + // TODO: left, right, top, bottom: // leave-notify-event diff --git a/src/libs/tools/filter.c b/src/libs/tools/filter.c index abe7156..a33cd86 100644 --- a/src/libs/tools/filter.c +++ b/src/libs/tools/filter.c @@ -143,6 +143,7 @@ void gui_init(dt_lib_module_t *self) gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(widget), _("color label")); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(widget), _("group")); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(widget), _("full path")); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(widget), _("custom sort")); /* select the last selected value */ gtk_combo_box_set_active(GTK_COMBO_BOX(widget), dt_collection_get_sort_field(darktable.collection)); diff --git a/src/views/lighttable.c b/src/views/lighttable.c index e2225b0..836fc17 100644 --- a/src/views/lighttable.c +++ b/src/views/lighttable.c @@ -33,6 +33,7 @@ #include "control/settings.h" #include "dtgtk/button.h" #include "gui/accelerators.h" +#include "gui/drag_and_drop.h" #include "gui/draw.h" #include "gui/gtk.h" #include "libs/lib.h" @@ -132,6 +133,15 @@ typedef struct dt_library_t static GtkTargetEntry target_list[] = { { "text/uri-list", GTK_TARGET_OTHER_APP, 0 } }; static guint n_targets = G_N_ELEMENTS(target_list); +/* drag and drop callbacks to reorder picture sequence (dnd)*/ + +static void _dnd_get_picture_reorder(GtkWidget *widget, GdkDragContext *context, gint x, gint y, + GtkSelectionData *selection_data, guint target_type, guint time, + gpointer data); +static void _dnd_begin_picture_reorder(GtkWidget *widget, GdkDragContext *context, gpointer user_data); + +static gboolean _dnd_drag_picture_motion(GtkWidget *dest_button, GdkDragContext *dc, gint x, gint y, guint time, gpointer user_data); + static void _stop_audio(dt_library_t *lib); const char *name(dt_view_t *self) @@ -750,7 +760,6 @@ end_query_cache: } escape_image_loop: cairo_restore(cr); - if(!lib->pan && (iir != 1 || mouse_over_id != -1)) dt_control_set_mouse_over_id(mouse_over_id); // and now the group borders @@ -1635,12 +1644,21 @@ static void drag_and_drop_received(GtkWidget *widget, GdkDragContext *context, g void enter(dt_view_t *self) { - // init drag&drop of files/folders + // init drag&drop of external files/folders into darktable gtk_drag_dest_set(dt_ui_center(darktable.gui->ui), GTK_DEST_DEFAULT_ALL, target_list, n_targets, GDK_ACTION_COPY); g_signal_connect(dt_ui_center(darktable.gui->ui), "drag-data-received", G_CALLBACK(drag_and_drop_received), self); + // drag and drop for custom order of picture sequence (dnd) + gtk_drag_source_set(dt_ui_center(darktable.gui->ui), GDK_BUTTON1_MASK, target_list_internal, n_targets_internal, GDK_ACTION_MOVE); + gtk_drag_dest_set(dt_ui_center(darktable.gui->ui), GTK_DEST_DEFAULT_ALL, target_list_internal, n_targets_internal, + GDK_ACTION_MOVE); + + g_signal_connect(dt_ui_center(darktable.gui->ui), "drag-begin", G_CALLBACK(_dnd_begin_picture_reorder), (gpointer)self); + g_signal_connect(dt_ui_center(darktable.gui->ui), "drag-data-get", G_CALLBACK(_dnd_get_picture_reorder), (gpointer)self); + g_signal_connect(dt_ui_center(darktable.gui->ui), "drag_motion", G_CALLBACK(_dnd_drag_picture_motion), (gpointer)self); + /* connect to signals */ dt_control_signal_connect(darktable.signals, DT_SIGNAL_DEVELOP_MIPMAP_UPDATED, G_CALLBACK(_lighttable_mipmaps_updated_signal_callback), (gpointer)self); @@ -1824,7 +1842,12 @@ int button_pressed(dt_view_t *self, double x, double y, double pressure, int whi lib->select_offset_y = lib->zoom_y; lib->select_offset_x += x; lib->select_offset_y += y; - lib->pan = 1; + + if (dt_control_get_mouse_over_id() < 0) + { + lib->pan = 1; + } + if(which == 1) dt_control_change_cursor(GDK_HAND1); if(which == 1 && type == GDK_2BUTTON_PRESS) return 0; // image button pressed? @@ -2439,6 +2462,68 @@ void gui_init(dt_view_t *self) g_signal_connect(G_OBJECT(display_profile), "value-changed", G_CALLBACK(display_profile_callback), NULL); } +static void _dnd_get_picture_reorder(GtkWidget *widget, GdkDragContext *context, gint x, gint y, + GtkSelectionData *selection_data, guint target_type, guint time, + gpointer data) +{ + GList *selected_images = dt_collection_get_selected(darktable.collection, -1); + const int32_t mouse_over_id = dt_control_get_mouse_over_id(); + dt_collection_move_before(mouse_over_id, selected_images); + + dt_control_button_released(x, y, GDK_BUTTON1_MASK, 0 & 0xf); + //gtk_widget_queue_draw(widget); + _update_collected_images(darktable.view_manager->proxy.lighttable.view); + g_list_free(selected_images); +} + +static void _dnd_begin_picture_reorder(GtkWidget *widget, GdkDragContext *context, gpointer user_data) +{ + const int ts = DT_PIXEL_APPLY_DPI(64); + + GList *selected_images = dt_collection_get_selected(darktable.collection, 1); + + // if we are dragging a single image -> use the thumbnail of that image + // otherwise use the generic d&d icon + // TODO: have something pretty in the 2nd case, too. + if(dt_collection_get_selected_count(NULL) == 1 && selected_images) + { + const int imgid = GPOINTER_TO_INT(selected_images->data); + + dt_mipmap_buffer_t buf; + dt_mipmap_size_t mip = dt_mipmap_cache_get_matching_size(darktable.mipmap_cache, ts, ts); + dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, mip, DT_MIPMAP_BLOCKING, 'r'); + + if(buf.buf) + { + for(size_t i = 3; i < (size_t)4 * buf.width * buf.height; i += 4) buf.buf[i] = UINT8_MAX; + + int w = ts, h = ts; + if(buf.width < buf.height) + w = (buf.width * ts) / buf.height; // portrait + else + h = (buf.height * ts) / buf.width; // landscape + + GdkPixbuf *source = gdk_pixbuf_new_from_data(buf.buf, GDK_COLORSPACE_RGB, TRUE, 8, buf.width, + buf.height, buf.width * 4, NULL, NULL); + GdkPixbuf *scaled = gdk_pixbuf_scale_simple(source, w, h, GDK_INTERP_HYPER); + gtk_drag_set_icon_pixbuf(context, scaled, 0, h); + + if(source) g_object_unref(source); + if(scaled) g_object_unref(scaled); + } + + dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + } + + g_list_free(selected_images); +} + +static gboolean _dnd_drag_picture_motion(GtkWidget *dest_button, GdkDragContext *dc, gint x, gint y, guint time, gpointer user_data) +{ + dt_control_queue_redraw_center(); + return FALSE; +} + // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh // vim: shiftwidth=2 expandtab tabstop=2 cindent // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified; -- 2.7.4