diff --git a/src/gui/gtk.c b/src/gui/gtk.c index 110621ef3b1..f1a3044b5b9 100644 --- a/src/gui/gtk.c +++ b/src/gui/gtk.c @@ -34,6 +34,7 @@ #include "gui/splash.h" #include "bauhaus/bauhaus.h" #include "develop/blend.h" +#include "develop/blend_gui_internal.h" #include "develop/develop.h" #include "develop/imageop.h" // dt_masks_get_edit_mode: the flexi panel's edge halo stands down while @@ -168,7 +169,9 @@ typedef struct dt_ui_t gboolean flexi_mask_active; // TRUE when the hosted module's mask is actually in use gchar *flexi_mask_label; // human-readable current mask type, for the hint gboolean flexi_panel_right; // current side (FALSE = left, TRUE = right) - GtkWidget *flexi_centerrow; // the panel's home when docked as a real column + gboolean flexi_has_content; // the edge strips are live (there is a panel to reach) + gboolean flexi_in_view; // the darkroom is showing, so the strips may take room + GtkWidget *flexi_centerrow; // the panel's home when docked as a real column } dt_ui_t; /* initialize the whole left panel */ @@ -4248,6 +4251,15 @@ static double _flexi_halo_arrow_size(GtkWidget *halo) static gboolean _flexi_sliver_draw(GtkWidget *w, cairo_t *cr, gpointer user_data) { + // kept only for its room (see _flexi_slivers_update): the canvas' own margin + // color, as darkroom.c paints it, so it reads as part of the canvas + if(!darktable.gui->ui->flexi_has_content) + { + dt_gui_gtk_set_source_rgb(cr, DT_GUI_COLOR_DARKROOM_BG); + cairo_paint(cr); + return FALSE; + } + GtkStyleContext *ctx = gtk_widget_get_style_context(w); const int width = gtk_widget_get_allocated_width(w); const int height = gtk_widget_get_allocated_height(w); @@ -4381,6 +4393,7 @@ static void _flexi_sliver_enter(GtkEventControllerMotion *controller, GtkWidget *w) { dt_ui_t *ui = darktable.gui->ui; + if(!ui->flexi_has_content) return; _flexi_sliver_hint(ui, _flexi_sliver_is_right(ui, w)); } @@ -4396,8 +4409,9 @@ static void _flexi_sliver_pressed(GtkGestureSingle *gesture, GtkWidget *w) { if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) return; - dt_gui_claim(gesture); dt_ui_t *ui = darktable.gui->ui; + if(!ui->flexi_has_content) return; + dt_gui_claim(gesture); const gboolean right = _flexi_sliver_is_right(ui, w); // the strip stays put once the panel is docked, so it needs something to do @@ -4739,9 +4753,21 @@ static void _flexi_slivers_update(dt_ui_t *ui, const gboolean show) { _flexi_halo_sync_width(ui); + ui->flexi_has_content = show; + // the strips are columns of centerrow, so showing or hiding them re-lays out + // the canvas and moves the image by a pixel. Their room is kept for as long + // as the canvas position is in use, whatever is focused; with no panel to + // reach they pass for canvas (_flexi_sliver_draw) and take no input + const gboolean reserve = + show || (ui->flexi_in_view && dt_masks_gui_panel_position() == MASKS_PANEL_POS_CANVAS); + for(int i = 0; i < 2; i++) { - if(ui->flexi_sliver[i]) gtk_widget_set_visible(ui->flexi_sliver[i], show); + if(ui->flexi_sliver[i]) + { + gtk_widget_set_visible(ui->flexi_sliver[i], reserve); + gtk_widget_queue_draw(ui->flexi_sliver[i]); + } // whether a halo is up is the proximity poll's business, but with no panel // to reach for there must be none, and no poll looking for one either if(!show && ui->flexi_halo[i]) gtk_widget_set_visible(ui->flexi_halo[i], FALSE); @@ -4908,6 +4934,13 @@ void dt_ui_flexi_panel_set_icon(dt_ui_t *ui, const gboolean active, const char * if(ui->flexi_halo[i]) gtk_widget_queue_draw(ui->flexi_halo[i]); } +void dt_ui_flexi_panel_set_in_view(dt_ui_t *ui, const gboolean in_view) +{ + if(!ui) return; + ui->flexi_in_view = in_view; + _flexi_slivers_update(ui, in_view && ui->flexi_has_content); +} + gboolean dt_ui_flexi_panel_is_collapsed(dt_ui_t *ui) { if(!ui->flexi_panel_overlay) return TRUE; diff --git a/src/gui/gtk.h b/src/gui/gtk.h index 065a6836e9d..2b22f26b487 100644 --- a/src/gui/gtk.h +++ b/src/gui/gtk.h @@ -485,6 +485,10 @@ void dt_ui_flexi_panel_set_collapsed(struct dt_ui_t *ui, const gboolean collapsed, const gboolean has_content, const gboolean persist); +/** \brief whether the darkroom is the current view. While it is, and the + canvas position is chosen, the edge strips keep their room in the center + row even with nothing to show, so that focus changes do not move the image */ +void dt_ui_flexi_panel_set_in_view(struct dt_ui_t *ui, const gboolean in_view); gboolean dt_ui_flexi_panel_is_collapsed(struct dt_ui_t *ui); /** \brief which edge the panel is on now, which can differ from the stored preference: anything mirroring the panel's own chrome follows this */ diff --git a/src/views/darkroom.c b/src/views/darkroom.c index 008a1250f07..1d3d67bcfdf 100644 --- a/src/views/darkroom.c +++ b/src/views/darkroom.c @@ -4134,6 +4134,10 @@ void enter(dt_view_t *self) // clean the undo list dt_undo_clear(darktable.undo, DT_UNDO_DEVELOP); + // before any module takes focus, so the canvas is laid out with the edge + // strips' room from the start + dt_ui_flexi_panel_set_in_view(darktable.gui->ui, TRUE); + /* connect to ui pipe finished signal for redraw */ DT_CONTROL_SIGNAL_HANDLE(DT_SIGNAL_DEVELOP_IMAGE_CHANGED, _darkroom_ui_image_changed_callback); @@ -4333,6 +4337,7 @@ void leave(dt_view_t *self) // not per-view lib content -- hide it and its edge strips explicitly, since // nothing else does this when leaving the view dt_ui_flexi_panel_set_collapsed(darktable.gui->ui, TRUE, FALSE, FALSE); + dt_ui_flexi_panel_set_in_view(darktable.gui->ui, FALSE); dt_iop_color_picker_cleanup(); if(darktable.lib->proxy.colorpicker.picker_proxy)