Skip to content

Commit

Permalink
Change filmstrip UX to match what lighttable does.
Browse files Browse the repository at this point in the history
So for the selection:

- Click        : select a single image
- Ctrl+Click   : toggle image selection
- Shift+Click  : select range

And so now to change image in darkroom:

- Double-click : change edited image

Note that the tricky part is that a double-click does raise:

   GDK_BUTTON_PRESS
   GDK_BUTTON_PRESS
   GDK_2BUTTON_PRESS

So we do resort on a timeout action for single click (GDK_BUTTON_PRESS)
selection which gets remove if a double click is actually done.

Part of #16275.
  • Loading branch information
TurboGit committed Oct 2, 2024
1 parent 15f1760 commit e1006d0
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 92 deletions.
51 changes: 1 addition & 50 deletions src/dtgtk/thumbnail.c
Original file line number Diff line number Diff line change
Expand Up @@ -941,57 +941,13 @@ static gboolean _event_main_motion(GtkWidget *widget,
return FALSE;
}

static gboolean _event_main_press(GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
dt_thumbnail_t *thumb = (dt_thumbnail_t *)user_data;
if(event->button == 1
&& ((event->type == GDK_2BUTTON_PRESS && !thumb->single_click)
|| (event->type == GDK_BUTTON_PRESS
&& dt_modifier_is(event->state, 0) && thumb->single_click)))
{
dt_control_set_mouse_over_id(thumb->imgid);
// to ensure we haven't lost imgid during double-click
}
return FALSE;
}
static gboolean _event_main_release(GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
dt_thumbnail_t *thumb = (dt_thumbnail_t *)user_data;

if(event->button == 1
&& !thumb->moved
&& thumb->sel_mode != DT_THUMBNAIL_SEL_MODE_DISABLED)
{
if(dt_modifier_is(event->state, 0)
&& thumb->sel_mode != DT_THUMBNAIL_SEL_MODE_MOD_ONLY)
dt_selection_select_single(darktable.selection, thumb->imgid);
else if(dt_modifier_is(event->state, GDK_MOD1_MASK))
{
dt_selection_select_single(darktable.selection, thumb->imgid);
}
else if(dt_modifier_is(event->state, GDK_CONTROL_MASK)
|| dt_modifier_is(event->state, GDK_MOD2_MASK)) // CMD key on macOS
{
dt_selection_toggle(darktable.selection, thumb->imgid);
}
else if(dt_modifier_is(event->state, GDK_SHIFT_MASK))
{
dt_selection_select_range(darktable.selection, thumb->imgid);
}
}
return FALSE;
}

static gboolean _event_rating_press(GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
return TRUE;
}

static gboolean _event_rating_release(GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
Expand Down Expand Up @@ -1408,11 +1364,6 @@ GtkWidget *dt_thumbnail_create_widget(dt_thumbnail_t *thumb,
g_signal_connect(G_OBJECT(thumb->w_main), "drag-motion",
G_CALLBACK(_event_main_drag_motion), thumb);

g_signal_connect(G_OBJECT(thumb->w_main), "button-press-event",
G_CALLBACK(_event_main_press), thumb);
g_signal_connect(G_OBJECT(thumb->w_main), "button-release-event",
G_CALLBACK(_event_main_release), thumb);

g_object_set_data(G_OBJECT(thumb->w_main), "thumb", thumb);
DT_DEBUG_CONTROL_SIGNAL_CONNECT(darktable.signals, DT_SIGNAL_ACTIVE_IMAGES_CHANGE,
G_CALLBACK(_dt_active_images_callback), thumb);
Expand Down
160 changes: 118 additions & 42 deletions src/dtgtk/thumbtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -1386,6 +1386,23 @@ static gboolean _event_enter_notify(GtkWidget *widget,
return TRUE;
}

static gboolean _do_select_single(gpointer user_data)
{
dt_thumbtable_t *table = (dt_thumbtable_t *)user_data;
const dt_imgid_t id = table->to_selid;

// always keep the edited picture selected
GList *sel = g_list_append(NULL, GINT_TO_POINTER(id));
sel = g_list_append(sel, GINT_TO_POINTER(darktable.develop->image_storage.id));

dt_selection_clear(darktable.selection);
dt_selection_select_list(darktable.selection, sel);
table->sel_single_cb = 0;
g_list_free(sel);

return FALSE;
}

static gboolean _event_button_press(GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
Expand All @@ -1396,12 +1413,45 @@ static gboolean _event_button_press(GtkWidget *widget,
const dt_imgid_t id = dt_control_get_mouse_over_id();

if(dt_is_valid_imgid(id)
&& event->button == 1
&& (table->mode == DT_THUMBTABLE_MODE_FILEMANAGER
|| table->mode == DT_THUMBTABLE_MODE_ZOOM)
&& event->type == GDK_2BUTTON_PRESS)
&& event->button == 1)
{
dt_view_manager_switch(darktable.view_manager, "darkroom");
// double-click
if(event->type == GDK_2BUTTON_PRESS)
{
switch(table->mode)
{
case DT_THUMBTABLE_MODE_FILEMANAGER:
case DT_THUMBTABLE_MODE_ZOOM:
dt_view_manager_switch(darktable.view_manager, "darkroom");
break;

case DT_THUMBTABLE_MODE_FILMSTRIP:
if(dt_view_get_current() == DT_VIEW_DARKROOM)
{
if(table->sel_single_cb != 0)
{
g_source_remove(table->sel_single_cb);
table->sel_single_cb = 0;
}
// disable next BUTTON_RELEASE event (see _event_motion_release)
table->to_selid = -1;
// unselect currently edited picture, select new one
dt_selection_deselect(darktable.selection,
darktable.develop->image_storage.id);
dt_selection_select(darktable.selection, id);
DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals,
DT_SIGNAL_VIEWMANAGER_THUMBTABLE_ACTIVATE, id);
return FALSE;
}
default:
break;
}
}

if(event->button == 1
&& event->type == GDK_BUTTON_PRESS
&& table->mode == DT_THUMBTABLE_MODE_FILMSTRIP)
return FALSE;
}

if(event->button == 1 && event->type == GDK_BUTTON_PRESS)
Expand All @@ -1415,8 +1465,20 @@ static gboolean _event_button_press(GtkWidget *widget,
&& event->button == 1
&& event->type == GDK_BUTTON_PRESS)
{
const dt_view_type_flags_t cv = dt_view_get_current();

// we click in an empty area, let's deselect all images
dt_selection_clear(darktable.selection);

// but we still want the currently edited image to be selected when
// in darkroom.
if(table->mode == DT_THUMBTABLE_MODE_FILMSTRIP
&& cv == DT_VIEW_DARKROOM)
{
dt_selection_select(darktable.selection,
darktable.develop->image_storage.id);
}

PangoRectangle *button = &table->manual_button;
if(event->x < button->x && event->x > button->x - button->width
&& event->y < button->y && event->y > button->y - button->height)
Expand All @@ -1427,19 +1489,6 @@ static gboolean _event_button_press(GtkWidget *widget,
return TRUE;
}

if(table->mode != DT_THUMBTABLE_MODE_ZOOM)
return FALSE;

if(event->button == 1
&& event->type == GDK_BUTTON_PRESS)
{
table->dragging = TRUE;
table->drag_dx = table->drag_dy = 0;
table->drag_initial_imgid = id;
table->drag_thumb = _thumbtable_get_thumb(table, id);
if(table->drag_thumb)
table->drag_thumb->moved = FALSE;
}
return TRUE;
}

Expand Down Expand Up @@ -1479,39 +1528,64 @@ static gboolean _event_button_release(GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
// we select only in LIGHTTABLE, DARKROOM & MAP mode
const dt_view_type_flags_t cv = dt_view_get_current();

if(cv != DT_VIEW_DARKROOM
&& cv != DT_VIEW_LIGHTTABLE
&& cv != DT_VIEW_MAP)
return FALSE;

dt_set_backthumb_time(0.0);
const dt_imgid_t id = dt_control_get_mouse_over_id();

dt_thumbtable_t *table = (dt_thumbtable_t *)user_data;

if(table->dragging == FALSE)
{
// on map view consider click release instead of press
dt_view_manager_t *vm = darktable.view_manager;
dt_view_t *view = vm->current_view;
const dt_imgid_t id = dt_control_get_mouse_over_id();
if(dt_is_valid_imgid(id)
&& event->button == 1
&& table->mode == DT_THUMBTABLE_MODE_FILMSTRIP
&& event->type == GDK_BUTTON_RELEASE
&& !strcmp(view->module_name, "map")
&& dt_modifier_is(event->state, 0))
{
DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals,
DT_SIGNAL_VIEWMANAGER_THUMBTABLE_ACTIVATE, id);
return TRUE;
if(dt_is_valid_imgid(id)
&& event->button == 1
&& event->type == GDK_BUTTON_RELEASE)
{
if(dt_modifier_is(event->state, GDK_CONTROL_MASK)
|| dt_modifier_is(event->state, GDK_MOD2_MASK)) // CMD key on macOS
{
dt_selection_toggle(darktable.selection, id);
}
else if(dt_modifier_is(event->state, GDK_SHIFT_MASK))
{
dt_selection_select_range(darktable.selection, id);
}
else if(dt_is_valid_imgid(id)
&& event->button == 1
&& table->mode == DT_THUMBTABLE_MODE_FILMSTRIP
&& event->type == GDK_BUTTON_RELEASE
&& strcmp(view->module_name, "map")
&& dt_modifier_is(event->state, 0))
else
{
if(table->mode == DT_THUMBTABLE_MODE_FILMSTRIP
&& cv == DT_VIEW_DARKROOM)
{
DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals,
DT_SIGNAL_VIEWMANAGER_THUMBTABLE_ACTIVATE, id);
// if there is more than one selected image then we have at least
// one picture selected not counting the currently edited one.
// delay the single selection to ensure that if we double-click we
// do not unselect all the pictures.
if(table->sel_single_cb == 0)
{
// button released event must be skip
if(table->to_selid == -1)
{
table->to_selid = NO_IMGID;
}
else
{
table->to_selid = id;
table->sel_single_cb = g_timeout_add(300, _do_select_single, table);
}
}
}
else
{
dt_selection_select_single(darktable.selection, id);
}
}
}

// Left now if not in zoom mode

if(table->mode != DT_THUMBTABLE_MODE_ZOOM)
return FALSE;

Expand Down Expand Up @@ -2416,6 +2490,8 @@ dt_thumbtable_t *dt_thumbtable_new()
// we init key accels
_thumbtable_init_accels();

table->sel_single_cb = 0;
table->to_selid = NO_IMGID;
return table;
}

Expand Down
4 changes: 4 additions & 0 deletions src/dtgtk/thumbtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ typedef struct dt_thumbtable_t
// scroll timeout values
guint scroll_timeout_id;
float scroll_value;

// darkroom selection from filmstrip (support for single & double click)
guint sel_single_cb;
dt_imgid_t to_selid;
} dt_thumbtable_t;

dt_thumbtable_t *dt_thumbtable_new();
Expand Down

0 comments on commit e1006d0

Please sign in to comment.