segmented_button: add on_double_click callback
Fires in addition to on_activate when the same entity is left-clicked twice within 400 ms. Lets applications bind quick actions (e.g. rename a tab) without blocking the normal single-click activation path. - New Widget::on_double_click builder mirroring on_activate/on_close. - last_click field on LocalState for timestamp tracking. - Detection branch in the mouse handler after on_activate fires, so the target entity is already focused when the callback runs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1d98eee6de
commit
108441ef61
1 changed files with 47 additions and 0 deletions
|
|
@ -173,6 +173,10 @@ where
|
|||
pub(super) on_context: Option<Box<dyn Fn(Entity) -> Message + 'static>>,
|
||||
#[setters(skip)]
|
||||
pub(super) on_middle_press: Option<Box<dyn Fn(Entity) -> Message + 'static>>,
|
||||
/// Emits the ID of the item that was double-clicked with the left button.
|
||||
/// Fires in addition to `on_activate` (which keeps firing on each click).
|
||||
#[setters(skip)]
|
||||
pub(super) on_double_click: Option<Box<dyn Fn(Entity) -> Message + 'static>>,
|
||||
#[setters(skip)]
|
||||
pub(super) on_dnd_drop:
|
||||
Option<Box<dyn Fn(Entity, Vec<u8>, String, DndAction) -> Message + 'static>>,
|
||||
|
|
@ -232,6 +236,7 @@ where
|
|||
on_close: None,
|
||||
on_context: None,
|
||||
on_middle_press: None,
|
||||
on_double_click: None,
|
||||
on_dnd_drop: None,
|
||||
on_dnd_enter: None,
|
||||
on_dnd_leave: None,
|
||||
|
|
@ -354,6 +359,16 @@ where
|
|||
self
|
||||
}
|
||||
|
||||
/// Emitted when a tab is double-clicked with the left mouse button.
|
||||
/// Fires in addition to `on_activate`, which keeps firing on each click.
|
||||
pub fn on_double_click<T>(mut self, on_double_click: T) -> Self
|
||||
where
|
||||
T: Fn(Entity) -> Message + 'static,
|
||||
{
|
||||
self.on_double_click = Some(Box::new(on_double_click));
|
||||
self
|
||||
}
|
||||
|
||||
/// Enable drag-and-drop support for tabs using the provided payload builder.
|
||||
pub fn enable_tab_drag(mut self, mime: String) -> Self {
|
||||
self.tab_drag = Some(TabDragSource::new(mime));
|
||||
|
|
@ -912,6 +927,7 @@ where
|
|||
hovered: Default::default(),
|
||||
known_length: Default::default(),
|
||||
middle_clicked: Default::default(),
|
||||
last_click: None,
|
||||
internal_layout: Default::default(),
|
||||
context_cursor: Point::default(),
|
||||
show_context: Default::default(),
|
||||
|
|
@ -1383,6 +1399,33 @@ where
|
|||
state.set_focused();
|
||||
state.focused_item = Item::Tab(key);
|
||||
state.pressed_item = None;
|
||||
|
||||
// Double-click detection on the same entity
|
||||
// within 400 ms — fires after on_activate so
|
||||
// the tab is already focused when the handler
|
||||
// runs.
|
||||
if let Some(on_double_click) =
|
||||
self.on_double_click.as_ref()
|
||||
{
|
||||
let now = Instant::now();
|
||||
let is_double = match state.last_click {
|
||||
Some((prev, t)) => {
|
||||
prev == key
|
||||
&& now.duration_since(t)
|
||||
< Duration::from_millis(400)
|
||||
}
|
||||
None => false,
|
||||
};
|
||||
state.last_click = if is_double {
|
||||
None
|
||||
} else {
|
||||
Some((key, now))
|
||||
};
|
||||
if is_double {
|
||||
shell.publish(on_double_click(key));
|
||||
}
|
||||
}
|
||||
|
||||
shell.capture_event();
|
||||
return;
|
||||
}
|
||||
|
|
@ -2387,6 +2430,9 @@ pub struct LocalState {
|
|||
hovered: Item,
|
||||
/// The ID of the button that was middle-clicked, but not yet released.
|
||||
middle_clicked: Option<Item>,
|
||||
/// Entity and timestamp of the most recent left-click activation, used
|
||||
/// to detect double-clicks on the same tab.
|
||||
last_click: Option<(Entity, Instant)>,
|
||||
/// Last known length of the model.
|
||||
pub(super) known_length: usize,
|
||||
/// Dimensions of internal buttons when shrinking
|
||||
|
|
@ -2532,6 +2578,7 @@ mod tests {
|
|||
hovered: Item::default(),
|
||||
known_length: 0,
|
||||
middle_clicked: None,
|
||||
last_click: None,
|
||||
internal_layout: Vec::new(),
|
||||
context_cursor: Point::ORIGIN,
|
||||
show_context: None,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue