diff --git a/src/develop/imageop.c b/src/develop/imageop.c index 890f9bb17201..c636ba106c44 100644 --- a/src/develop/imageop.c +++ b/src/develop/imageop.c @@ -2888,7 +2888,7 @@ static gboolean _on_drag_motion(GtkWidget *widget, GdkDragContext *dc, gint x, g if(!src || !dest || dest == src) return FALSE; - if(x != -1) + if(x != DND_DROP) { if(!(src->iop_order < dest->iop_order ? dt_ioppr_check_can_move_after_iop(darktable.develop->iop, src, dest) @@ -2932,7 +2932,7 @@ static gboolean _on_drag_motion(GtkWidget *widget, GdkDragContext *dc, gint x, g static gboolean _on_drag_drop(GtkWidget *widget, GdkDragContext *dc, gint x, gint y, guint time, dt_iop_module_t *module) { - return _on_drag_motion(widget, dc, -1, y, time, module); + return _on_drag_motion(widget, dc, DND_DROP, y, time, module); } void dt_iop_gui_set_expander(dt_iop_module_t *module) diff --git a/src/dtgtk/range.c b/src/dtgtk/range.c index 833d011f1df5..b6c80e9348f0 100644 --- a/src/dtgtk/range.c +++ b/src/dtgtk/range.c @@ -1724,18 +1724,16 @@ GtkWidget *dtgtk_range_select_new(const gchar *property, const gboolean show_ent gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); // the entries - range->entry_min = gtk_entry_new(); + range->entry_min = dt_ui_entry_new(); gtk_widget_set_can_default(range->entry_min, TRUE); - gtk_entry_set_width_chars(GTK_ENTRY(range->entry_min), 0); _entry_set_tooltip(range->entry_min, BOUND_MIN, range->type); g_signal_connect(G_OBJECT(range->entry_min), "activate", G_CALLBACK(_event_entry_activated), range); g_signal_connect(G_OBJECT(range->entry_min), "focus-out-event", G_CALLBACK(_event_entry_focus_out), range); g_signal_connect(G_OBJECT(range->entry_min), "button-press-event", G_CALLBACK(_event_entry_press), range); gtk_box_pack_start(GTK_BOX(hbox), range->entry_min, TRUE, TRUE, 0); - range->entry_max = gtk_entry_new(); + range->entry_max = dt_ui_entry_new(); gtk_widget_set_can_default(range->entry_max, TRUE); - gtk_entry_set_width_chars(GTK_ENTRY(range->entry_max), 0); gtk_entry_set_alignment(GTK_ENTRY(range->entry_max), 1.0); _entry_set_tooltip(range->entry_max, BOUND_MAX, range->type); g_signal_connect(G_OBJECT(range->entry_max), "activate", G_CALLBACK(_event_entry_activated), range); diff --git a/src/gui/accelerators.c b/src/gui/accelerators.c index ec9f349cdcb8..96c37f47bc73 100644 --- a/src/gui/accelerators.c +++ b/src/gui/accelerators.c @@ -5160,7 +5160,7 @@ GtkWidget *dt_action_entry_new(dt_action_t *ac, const gchar *tooltip, const gchar *text) { - GtkWidget *entry = gtk_entry_new(); + GtkWidget *entry = dt_ui_entry_new(); gtk_entry_set_width_chars(GTK_ENTRY(entry), 5); if(text) gtk_entry_set_text (GTK_ENTRY(entry), text); diff --git a/src/gui/drag_and_drop.h b/src/gui/drag_and_drop.h index 146173da7be3..e3bcaff8f680 100644 --- a/src/gui/drag_and_drop.h +++ b/src/gui/drag_and_drop.h @@ -21,6 +21,7 @@ #define _BYTE 8 #define _WORD 16 #define _DWORD 32 +#define DND_DROP -1 /* common for all the drag&drop sources/destinations */ enum diff --git a/src/gui/gtk.c b/src/gui/gtk.c index 5238cb00d195..e4aba5ad8c8a 100644 --- a/src/gui/gtk.c +++ b/src/gui/gtk.c @@ -2240,6 +2240,36 @@ static gboolean _ui_init_panel_container_center_scroll_event(GtkWidget *widget, != dt_conf_get_bool("darkroom/ui/sidebar_scroll_default")); } +static gboolean _on_drag_motion_drop(GtkWidget *widget, GdkDragContext *dc, gint x, gint y, guint time, gboolean drop) +{ + if(drop) gtk_widget_set_opacity(gtk_drag_get_source_widget(dc), 1.0); + + gboolean ret = TRUE; + gpointer last = NULL; + for(GList *m = gtk_container_get_children(GTK_CONTAINER(widget)); m; m = g_list_delete_link(m, m)) + if(gtk_widget_get_visible(GTK_WIDGET(m->data))) last = m->data; + if(last) + g_signal_emit_by_name(last, "drag-motion", dc, drop ? -1 : x, y, time, &ret); + else if(drop) + { + // drop in empty panel; dragged expander handles its own move; pass destination panel in dc + GtkWidget *src_expander = gtk_widget_get_ancestor + (gtk_drag_get_source_widget(dc), DTGTK_TYPE_EXPANDER); + if(src_expander) + g_signal_emit_by_name(src_expander, "drag-motion", widget, x, y, time, &ret); + } + else + gdk_drag_status(dc, GDK_ACTION_COPY, time); + + return ret; +} + +static void _on_drag_leave(GtkDarktableExpander *widget, GdkDragContext *dc, guint time, gpointer user_data) +{ + for(GList *m = gtk_container_get_children(GTK_CONTAINER(widget)); m; m = g_list_delete_link(m, m)) + dtgtk_expander_set_drag_hover(m->data, FALSE, FALSE); +} + static GtkWidget *_ui_init_panel_container_center(GtkWidget *container, const gboolean left) { @@ -2286,6 +2316,10 @@ static GtkWidget *_ui_init_panel_container_center(GtkWidget *container, widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_widget_set_name(widget, "plugins_vbox_left"); gtk_container_add(GTK_CONTAINER(container), widget); + gtk_drag_dest_set(widget, 0, NULL, 0, GDK_ACTION_COPY); + g_signal_connect(widget, "drag-motion", G_CALLBACK(_on_drag_motion_drop), GINT_TO_POINTER(FALSE)); + g_signal_connect(widget, "drag-drop", G_CALLBACK(_on_drag_motion_drop), GINT_TO_POINTER(TRUE)); + g_signal_connect(widget, "drag-leave", G_CALLBACK(_on_drag_leave), NULL); return widget; } @@ -3491,6 +3525,7 @@ GtkNotebook *dt_ui_notebook_new(dt_action_def_t *def) def->process = _action_process_tabs; } + gtk_drag_dest_unset(GTK_WIDGET(_current_notebook)); return _current_notebook; } diff --git a/src/gui/gtk.h b/src/gui/gtk.h index 08b9179f5d4d..7c1e66188e04 100644 --- a/src/gui/gtk.h +++ b/src/gui/gtk.h @@ -410,6 +410,14 @@ static inline GtkWidget *dt_ui_label_new(const gchar *str) return label; }; +static inline GtkWidget *dt_ui_entry_new() +{ + GtkWidget *entry = gtk_entry_new(); + gtk_drag_dest_unset(entry); + gtk_entry_set_width_chars(GTK_ENTRY(entry), 0); + return entry; +}; + extern const struct dt_action_def_t dt_action_def_tabs_all_rgb; extern const struct dt_action_def_t dt_action_def_tabs_rgb; extern const struct dt_action_def_t dt_action_def_tabs_none; diff --git a/src/libs/camera.c b/src/libs/camera.c index d462466359e6..203223e0d889 100644 --- a/src/libs/camera.c +++ b/src/libs/camera.c @@ -496,8 +496,7 @@ void gui_init(dt_lib_module_t *self) label = gtk_label_new(_("label")); gtk_widget_set_halign(label, GTK_ALIGN_START); - lib->gui.plabel = gtk_entry_new(); - gtk_entry_set_width_chars(GTK_ENTRY(lib->gui.plabel), 0); + lib->gui.plabel = dt_ui_entry_new(); gtk_grid_attach(GTK_GRID(self->widget), GTK_WIDGET(label), 0, lib->gui.rows++, 1, 1); gtk_grid_attach_next_to(GTK_GRID(self->widget), GTK_WIDGET(lib->gui.plabel), GTK_WIDGET(label), GTK_POS_RIGHT, 1, 1); @@ -506,8 +505,7 @@ void gui_init(dt_lib_module_t *self) gtk_widget_set_halign(label, GTK_ALIGN_START); GtkWidget *widget = gtk_button_new_with_label("O"); g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(_show_property_popupmenu_clicked), lib); - lib->gui.pname = gtk_entry_new(); - gtk_entry_set_width_chars(GTK_ENTRY(lib->gui.pname), 0); + lib->gui.pname = dt_ui_entry_new(); gtk_box_pack_start(hbox, GTK_WIDGET(lib->gui.pname), TRUE, TRUE, 0); gtk_box_pack_start(hbox, GTK_WIDGET(widget), FALSE, FALSE, 0); gtk_grid_attach(GTK_GRID(self->widget), GTK_WIDGET(label), 0, lib->gui.rows++, 1, 1); diff --git a/src/libs/collect.c b/src/libs/collect.c index 73b1a37dfab8..8c3c52d42493 100644 --- a/src/libs/collect.c +++ b/src/libs/collect.c @@ -3666,7 +3666,7 @@ void gui_init(dt_lib_module_t *self) G_CALLBACK(combo_changed), d->rule + i); gtk_box_pack_start(box, d->rule[i].combo, FALSE, TRUE, 0); - w = gtk_entry_new(); + w = dt_ui_entry_new(); gtk_entry_set_max_width_chars(GTK_ENTRY(w), 10); d->rule[i].text = w; gtk_widget_add_events(w, GDK_FOCUS_CHANGE_MASK); diff --git a/src/libs/duplicate.c b/src/libs/duplicate.c index 2f1762299f59..6c17d680e67a 100644 --- a/src/libs/duplicate.c +++ b/src/libs/duplicate.c @@ -315,9 +315,8 @@ static void _lib_duplicate_init_callback(gpointer instance, dt_lib_module_t *sel gchar *path = (gchar *)sqlite3_column_text(stmt, 2); g_snprintf(chl, sizeof(chl), "%d", sqlite3_column_int(stmt, 0)); - GtkWidget *tb = gtk_entry_new(); + GtkWidget *tb = dt_ui_entry_new(); if(path) gtk_entry_set_text(GTK_ENTRY(tb), path); - gtk_entry_set_width_chars(GTK_ENTRY(tb), 0); gtk_widget_set_hexpand(tb, TRUE); g_object_set_data (G_OBJECT(tb), "imgid", GINT_TO_POINTER(imgid)); gtk_widget_add_events(tb, GDK_FOCUS_CHANGE_MASK); diff --git a/src/libs/filters/filename.c b/src/libs/filters/filename.c index 67f537430fa4..70b3b2bceacf 100644 --- a/src/libs/filters/filename.c +++ b/src/libs/filters/filename.c @@ -363,7 +363,7 @@ static void _filename_widget_init(dt_lib_filtering_rule_t *rule, const dt_collec gtk_box_pack_start(GTK_BOX(rule->w_special_box_top), hb, TRUE, TRUE, 0); else gtk_box_pack_start(GTK_BOX(rule->w_special_box), hb, TRUE, TRUE, 0); - filename->name = gtk_entry_new(); + filename->name = dt_ui_entry_new(); gtk_entry_set_width_chars(GTK_ENTRY(filename->name), (top) ? 10 : 0); gtk_widget_set_can_default(filename->name, TRUE); gtk_entry_set_placeholder_text(GTK_ENTRY(filename->name), _("filename")); @@ -375,7 +375,7 @@ static void _filename_widget_init(dt_lib_filtering_rule_t *rule, const dt_collec g_signal_connect(G_OBJECT(filename->name), "focus-out-event", G_CALLBACK(_filename_focus_out), filename); g_signal_connect(G_OBJECT(filename->name), "button-press-event", G_CALLBACK(_filename_press), filename); - filename->ext = gtk_entry_new(); + filename->ext = dt_ui_entry_new(); gtk_entry_set_width_chars(GTK_ENTRY(filename->ext), (top) ? 5 : 0); gtk_widget_set_can_default(filename->ext, TRUE); gtk_entry_set_placeholder_text(GTK_ENTRY(filename->ext), _("extension")); diff --git a/src/libs/filters/misc.c b/src/libs/filters/misc.c index e27c64f48c97..611eef9dcdff 100644 --- a/src/libs/filters/misc.c +++ b/src/libs/filters/misc.c @@ -398,7 +398,7 @@ static void _misc_widget_init(dt_lib_filtering_rule_t *rule, gtk_box_pack_start(GTK_BOX(rule->w_special_box_top), hb, TRUE, TRUE, 0); else gtk_box_pack_start(GTK_BOX(rule->w_special_box), hb, TRUE, TRUE, 0); - misc->name = gtk_entry_new(); + misc->name = dt_ui_entry_new(); gtk_entry_set_width_chars(GTK_ENTRY(misc->name), (top) ? 10 : 0); gtk_widget_set_can_default(misc->name, TRUE); diff --git a/src/libs/filters/search.c b/src/libs/filters/search.c index 1f3cafb88841..cad6532e7b27 100644 --- a/src/libs/filters/search.c +++ b/src/libs/filters/search.c @@ -169,6 +169,7 @@ static void _search_widget_init(dt_lib_filtering_rule_t *rule, const dt_collecti else gtk_box_pack_start(GTK_BOX(rule->w_special_box), hbox, TRUE, TRUE, 0); search->text = gtk_search_entry_new(); + gtk_drag_dest_unset(search->text); g_signal_connect(G_OBJECT(search->text), "search-changed", G_CALLBACK(_search_changed), search); g_signal_connect(G_OBJECT(search->text), "stop-search", G_CALLBACK(_search_reset_text_entry), rule); if(top) diff --git a/src/libs/geotagging.c b/src/libs/geotagging.c index 7eb842fc2a63..ba7b70204630 100644 --- a/src/libs/geotagging.c +++ b/src/libs/geotagging.c @@ -1496,7 +1496,7 @@ static GtkWidget *_gui_init_datetime(gchar *text, dt_lib_datetime_t *dt, const i } if(i >= 2 || type != 2) { - dt->widget[i] = gtk_entry_new(); + dt->widget[i] = dt_ui_entry_new(); gtk_entry_set_width_chars(GTK_ENTRY(dt->widget[i]), i == 0 ? 4 : i == 6 ? 3 : 2); gtk_entry_set_alignment(GTK_ENTRY(dt->widget[i]), 0.5); gtk_box_pack_start(box, dt->widget[i], FALSE, FALSE, 0); @@ -1772,10 +1772,9 @@ void gui_init(dt_lib_module_t *self) gtk_grid_attach(grid, label, 0, line, 2, 1); - d->timezone = gtk_entry_new(); + d->timezone = dt_ui_entry_new(); gtk_widget_set_tooltip_text(d->timezone, _("start typing to show a list of permitted values and select your timezone.\npress enter to confirm, so that the asterisk * disappears")); d->timezone_changed = dt_ui_label_new(""); - gtk_entry_set_width_chars(GTK_ENTRY(d->timezone), 0); GtkWidget *timezone_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start(GTK_BOX(timezone_box), d->timezone, TRUE, TRUE, 0); diff --git a/src/libs/lib.c b/src/libs/lib.c index bc6022429fca..fc037896f9b0 100644 --- a/src/libs/lib.c +++ b/src/libs/lib.c @@ -1075,80 +1075,98 @@ static gboolean _on_drag_motion(GtkWidget *widget, gint x, gint y, guint time, dt_lib_module_t *dest) { - GtkWidget *src_widget = gtk_widget_get_ancestor(gtk_drag_get_source_widget(dc), - DTGTK_TYPE_EXPANDER); - dt_lib_module_t *src = NULL; - for(GList *lib = darktable.lib->plugins; lib; lib = lib->next) - if(((dt_lib_module_t *)lib->data)->expander == src_widget) - src = lib->data; + GtkContainer *src_panel = NULL, *dest_panel = NULL; + gboolean below = TRUE; + int dest_pos = 0; - if(!src_widget || !src || dest == src ) return FALSE; + if(GTK_IS_BOX(dc)) + { + // propagated from empty panel handler in gtk.c + src = dest; + src_panel = GTK_CONTAINER(gtk_widget_get_parent(src->expander)); + dest_panel = GTK_CONTAINER(dc); + } + else + { + dtgtk_expander_set_drag_hover(DTGTK_EXPANDER(widget), FALSE, FALSE); + gdk_drag_status(dc, 0, time); - GtkContainer *src_panel = GTK_CONTAINER(gtk_widget_get_parent(src->expander)); - GtkContainer *dest_panel = GTK_CONTAINER(gtk_widget_get_parent(dest->expander)); + GtkWidget *src_widget = gtk_widget_get_ancestor(gtk_drag_get_source_widget(dc), + DTGTK_TYPE_EXPANDER); - int src_pos, dest_pos; - gtk_container_child_get(src_panel, src->expander, "position", &src_pos, NULL); - gtk_container_child_get(dest_panel, dest->expander, "position", &dest_pos, NULL); + for(GList *lib = darktable.lib->plugins; lib; lib = lib->next) + if(((dt_lib_module_t *)lib->data)->expander == src_widget) + src = lib->data; - GtkDarktableExpander *expander = DTGTK_EXPANDER(dest->expander); - gboolean below_is_last_and_collapsed = dest_pos == src_pos + 1 - && !dtgtk_expander_get_expanded(expander) - && dest_pos == dt_gui_container_num_children(dest_panel) - 1; - gboolean below = y > gtk_widget_get_allocated_height(dtgtk_expander_get_header(expander)) - / (below_is_last_and_collapsed ? 2 : 1); - if(below) dest_pos++; - if(dest_pos > src_pos) dest_pos--; + if(!src_widget || !src || dest == src ) return TRUE; - if(dest_panel == src_panel && dest_pos == src_pos) return FALSE; + src_panel = GTK_CONTAINER(gtk_widget_get_parent(src->expander)); + dest_panel = GTK_CONTAINER(gtk_widget_get_parent(dest->expander)); - if(x != -1) - { - dtgtk_expander_set_drag_hover(DTGTK_EXPANDER(widget), TRUE, below); + int src_pos = G_MAXINT; + if(dest_panel == src_panel) + gtk_container_child_get(src_panel, src->expander, "position", &src_pos, NULL); + gtk_container_child_get(dest_panel, dest->expander, "position", &dest_pos, NULL); - gdk_drag_status(dc, GDK_ACTION_COPY, time); - } - else - { - GtkBox *dest_box = GTK_BOX(dest_panel); - if(dest_panel != src_panel) + GtkDarktableExpander *exp = DTGTK_EXPANDER(dest->expander); + int header_height = gtk_widget_get_allocated_height(dtgtk_expander_get_header(exp)); + below = y > (abs(dest_pos - src_pos) == 1 && !dtgtk_expander_get_expanded(exp) + ? header_height / 2 + : dest_pos < src_pos + ? gtk_widget_get_allocated_height(widget) - header_height + : header_height); + + if(below) dest_pos++; + if(dest_pos > src_pos) dest_pos--; + if(dest_pos == src_pos) return TRUE; + + if(x != DND_DROP) { - g_object_ref(src->expander); - gtk_container_remove(src_panel, src->expander); - gtk_box_pack_start(dest_box, src->expander, FALSE, FALSE, 0); + dtgtk_expander_set_drag_hover(DTGTK_EXPANDER(widget), TRUE, below); + gdk_drag_status(dc, GDK_ACTION_COPY, time); + + return TRUE; } - gtk_box_reorder_child(dest_box, src->expander, dest_pos); + } - GList **list = &darktable.lib->plugins; - *list = g_list_remove(*list, src); + GtkBox *dest_box = GTK_BOX(dest_panel); + if(dest_panel != src_panel) + { + g_object_ref(src->expander); + gtk_container_remove(src_panel, src->expander); + gtk_box_pack_start(dest_box, src->expander, FALSE, FALSE, 0); + } + gtk_box_reorder_child(dest_box, src->expander, dest_pos); - GList *dest_list = g_list_find(*list, dest); - if(below) - dest = dest_list->prev ? dest_list->prev->data : NULL; - else - dest_list = dest_list->next; + GList **list = &darktable.lib->plugins; + *list = g_list_remove(*list, src); - int new_pos = dest ? ABS(_lib_position(dest)) + 1 : 1; - int old_pos = dest_box != dt_ui_get_container(darktable.gui->ui, src->container(src)) ? -1 : +1; - dt_lib_module_t *cur = src; - while(new_pos >= ABS(old_pos)) - { - gchar *key = _get_lib_view_path(cur, "_position"); - dt_conf_set_int(key, old_pos < 0 ? -new_pos : new_pos); - g_free(key); + GList *dest_list = g_list_find(*list, dest); + if(below) + dest = dest_list && dest_list->prev ? dest_list->prev->data : NULL; + else + dest_list = dest_list->next; - if(!dest_list) break; + int new_pos = dest ? ABS(_lib_position(dest)) + 1 : 1; + int old_pos = dest_box != dt_ui_get_container(darktable.gui->ui, src->container(src)) ? -1 : +1; + dt_lib_module_t *cur = src; + while(new_pos >= ABS(old_pos)) + { + gchar *key = _get_lib_view_path(cur, "_position"); + dt_conf_set_int(key, old_pos < 0 ? -new_pos : new_pos); + g_free(key); - new_pos++; - cur = dest_list->data; - old_pos = _lib_position(cur); - dest_list = dest_list->next; - } + if(!dest_list) break; - *list = g_list_insert_sorted(*list, src, dt_lib_sort_plugins); + new_pos++; + cur = dest_list->data; + old_pos = _lib_position(cur); + dest_list = dest_list->next; } + *list = g_list_insert_sorted(*list, src, dt_lib_sort_plugins); + return TRUE; } @@ -1157,7 +1175,7 @@ static gboolean _on_drag_drop(GtkWidget *widget, gint x, gint y, guint time, dt_lib_module_t *dest) { - return _on_drag_motion(widget, dc, -1, y, time, dest); + return _on_drag_motion(widget, dc, DND_DROP, y, time, dest); } GtkWidget *dt_lib_gui_get_expander(dt_lib_module_t *module) diff --git a/src/libs/location.c b/src/libs/location.c index 0e9a8a15b012..2600a69c5603 100644 --- a/src/libs/location.c +++ b/src/libs/location.c @@ -140,7 +140,7 @@ void gui_init(dt_lib_module_t *self) self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); /* add search box */ - lib->search = GTK_ENTRY(gtk_entry_new()); + lib->search = GTK_ENTRY(dt_ui_entry_new()); gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(lib->search), FALSE, FALSE, 0); g_signal_connect(G_OBJECT(lib->search), "activate", diff --git a/src/libs/metadata.c b/src/libs/metadata.c index 1b7579cac09d..035702bf0787 100644 --- a/src/libs/metadata.c +++ b/src/libs/metadata.c @@ -686,6 +686,7 @@ void gui_init(dt_lib_module_t *self) gtk_grid_attach(grid, labelev, 0, i, 1, 1); GtkWidget *textview = gtk_text_view_new(); + gtk_drag_dest_unset(textview); dt_action_define(DT_ACTION(self), NULL, name, textview, &dt_action_def_entry); gtk_widget_set_tooltip_text(textview, _("metadata text" diff --git a/src/libs/session.c b/src/libs/session.c index 91e963061b0f..8efc4704b5b1 100644 --- a/src/libs/session.c +++ b/src/libs/session.c @@ -99,8 +99,7 @@ void gui_init(dt_lib_module_t *self) gtk_widget_set_halign(GTK_WIDGET(lib->gui.label1), GTK_ALIGN_START); gtk_box_pack_start(vbox1, GTK_WIDGET(lib->gui.label1), TRUE, TRUE, 0); - lib->gui.entry1 = GTK_ENTRY(gtk_entry_new()); - gtk_entry_set_width_chars(GTK_ENTRY(lib->gui.entry1), 0); + lib->gui.entry1 = GTK_ENTRY(dt_ui_entry_new()); gtk_box_pack_start(vbox2, GTK_WIDGET(lib->gui.entry1), TRUE, TRUE, 0); lib->gui.button1 = GTK_BUTTON(gtk_button_new_with_label(_("create")));