fix(segmented_button): hover state handling
when hover state changes, paragraphs also need to be updated. I'll make a not to check this again after the rebase though.
This commit is contained in:
parent
f1c43f79ab
commit
9fcd449611
1 changed files with 106 additions and 76 deletions
|
|
@ -242,6 +242,49 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn update_entity_paragraph(&mut self, state: &mut LocalState, key: Entity) {
|
||||
if let Some(text) = self.model.text.get(key) {
|
||||
let font = if self.button_is_focused(state, key) {
|
||||
self.font_active
|
||||
} else if state.show_context.is_some() || self.button_is_hovered(state, key) {
|
||||
self.font_hovered
|
||||
} else if self.model.is_active(key) {
|
||||
self.font_active
|
||||
} else {
|
||||
self.font_inactive
|
||||
};
|
||||
|
||||
let mut hasher = DefaultHasher::new();
|
||||
text.hash(&mut hasher);
|
||||
font.hash(&mut hasher);
|
||||
let text_hash = hasher.finish();
|
||||
|
||||
if let Some(prev_hash) = state.text_hashes.insert(key, text_hash) {
|
||||
if prev_hash == text_hash {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let text = Text {
|
||||
content: text.as_ref(),
|
||||
size: iced::Pixels(self.font_size),
|
||||
bounds: Size::INFINITY,
|
||||
font,
|
||||
horizontal_alignment: alignment::Horizontal::Left,
|
||||
vertical_alignment: alignment::Vertical::Center,
|
||||
shaping: Shaping::Advanced,
|
||||
wrapping: Wrapping::None,
|
||||
line_height: self.line_height,
|
||||
};
|
||||
|
||||
if let Some(paragraph) = state.paragraphs.get_mut(key) {
|
||||
paragraph.update(text);
|
||||
} else {
|
||||
state.paragraphs.insert(key, crate::Plain::new(text));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn context_menu(mut self, context_menu: Option<Vec<menu::Tree<Message>>>) -> Self
|
||||
where
|
||||
Message: Clone + 'static,
|
||||
|
|
@ -761,6 +804,14 @@ where
|
|||
SelectionMode: Default,
|
||||
Message: 'static + Clone,
|
||||
{
|
||||
fn id(&self) -> Option<widget::Id> {
|
||||
Some(self.id.0.clone())
|
||||
}
|
||||
|
||||
fn set_id(&mut self, id: widget::Id) {
|
||||
self.id = Id(id);
|
||||
}
|
||||
|
||||
fn children(&self) -> Vec<Tree> {
|
||||
let mut children = Vec::new();
|
||||
|
||||
|
|
@ -812,46 +863,7 @@ where
|
|||
let state = tree.state.downcast_mut::<LocalState>();
|
||||
|
||||
for key in self.model.order.iter().copied() {
|
||||
if let Some(text) = self.model.text.get(key) {
|
||||
let font = if self.button_is_focused(state, key) {
|
||||
self.font_active
|
||||
} else if state.show_context.is_some() || self.button_is_hovered(state, key) {
|
||||
self.font_hovered
|
||||
} else if self.model.is_active(key) {
|
||||
self.font_active
|
||||
} else {
|
||||
self.font_inactive
|
||||
};
|
||||
|
||||
let mut hasher = DefaultHasher::new();
|
||||
text.hash(&mut hasher);
|
||||
font.hash(&mut hasher);
|
||||
let text_hash = hasher.finish();
|
||||
|
||||
if let Some(prev_hash) = state.text_hashes.insert(key, text_hash) {
|
||||
if prev_hash == text_hash {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let text = Text {
|
||||
content: text.as_ref(),
|
||||
size: iced::Pixels(self.font_size),
|
||||
bounds: Size::INFINITY,
|
||||
font,
|
||||
horizontal_alignment: alignment::Horizontal::Left,
|
||||
vertical_alignment: alignment::Vertical::Center,
|
||||
shaping: Shaping::Advanced,
|
||||
wrapping: Wrapping::None,
|
||||
line_height: self.line_height,
|
||||
};
|
||||
|
||||
if let Some(paragraph) = state.paragraphs.get_mut(key) {
|
||||
paragraph.update(text);
|
||||
} else {
|
||||
state.paragraphs.insert(key, crate::Plain::new(text));
|
||||
}
|
||||
}
|
||||
self.update_entity_paragraph(state, key);
|
||||
}
|
||||
|
||||
// Diff the context menu
|
||||
|
|
@ -899,9 +911,8 @@ where
|
|||
shell: &mut Shell<'_, Message>,
|
||||
_viewport: &iced::Rectangle,
|
||||
) -> event::Status {
|
||||
let bounds = layout.bounds();
|
||||
let my_bounds = layout.bounds();
|
||||
let state = tree.state.downcast_mut::<LocalState>();
|
||||
state.hovered = Item::None;
|
||||
|
||||
let my_id = self.get_drag_id();
|
||||
|
||||
|
|
@ -938,7 +949,7 @@ where
|
|||
},
|
||||
) if Some(my_id) == *id => {
|
||||
let entity = self
|
||||
.variant_bounds(state, bounds)
|
||||
.variant_bounds(state, my_bounds)
|
||||
.filter_map(|item| match item {
|
||||
ItemBounds::Button(entity, bounds) => Some((entity, bounds)),
|
||||
_ => None,
|
||||
|
|
@ -947,7 +958,7 @@ where
|
|||
.map(|(key, _)| key);
|
||||
state.drop_hint = self.drop_hint_for_position(
|
||||
state,
|
||||
bounds,
|
||||
my_bounds,
|
||||
Point::new(*x as f32, *y as f32),
|
||||
);
|
||||
self.emit_drop_hint(shell, state.drop_hint);
|
||||
|
|
@ -979,9 +990,6 @@ where
|
|||
if matches!(leave, OfferEvent::Leave | OfferEvent::LeaveDestination)
|
||||
&& Some(my_id) == *id =>
|
||||
{
|
||||
if matches!(leave, OfferEvent::Leave) {
|
||||
state.dragging_tab = None;
|
||||
}
|
||||
state.drop_hint = None;
|
||||
self.emit_drop_hint(shell, state.drop_hint);
|
||||
if let Some(Some(entity)) = entity {
|
||||
|
|
@ -1001,7 +1009,7 @@ where
|
|||
"offer motion id={my_id:?} cursor=({x},{y}) current_entity={entity:?}"
|
||||
);
|
||||
let new = self
|
||||
.variant_bounds(state, bounds)
|
||||
.variant_bounds(state, my_bounds)
|
||||
.filter_map(|item| match item {
|
||||
ItemBounds::Button(entity, bounds) => Some((entity, bounds)),
|
||||
_ => None,
|
||||
|
|
@ -1018,11 +1026,15 @@ where
|
|||
);
|
||||
state.drop_hint = self.drop_hint_for_position(
|
||||
state,
|
||||
bounds,
|
||||
my_bounds,
|
||||
Point::new(*x as f32, *y as f32),
|
||||
);
|
||||
self.emit_drop_hint(shell, state.drop_hint);
|
||||
if Some(Some(new_entity)) != entity {
|
||||
state.hovered = Item::Tab(new_entity);
|
||||
for key in self.model.order.iter().copied() {
|
||||
self.update_entity_paragraph(state, key);
|
||||
}
|
||||
let prev_action = state
|
||||
.dnd_state
|
||||
.drag_offer
|
||||
|
|
@ -1039,6 +1051,10 @@ where
|
|||
}
|
||||
}
|
||||
} else if entity.is_some() {
|
||||
state.hovered = Item::None;
|
||||
for key in self.model.order.iter().copied() {
|
||||
self.update_entity_paragraph(state, key);
|
||||
}
|
||||
log::trace!(
|
||||
target: TAB_REORDER_LOG_TARGET,
|
||||
"offer motion leaving id={my_id:?}"
|
||||
|
|
@ -1124,31 +1140,24 @@ where
|
|||
|
||||
self.emit_drop_hint(shell, state.drop_hint);
|
||||
if let Some(event) = pending_reorder {
|
||||
state.focused_item = Item::Tab(event.dragged);
|
||||
state.hovered = Item::None;
|
||||
for key in self.model.order.iter().copied() {
|
||||
self.update_entity_paragraph(state, key);
|
||||
}
|
||||
if let Some(on_reorder) = self.on_reorder.as_ref() {
|
||||
shell.publish(on_reorder(event));
|
||||
return event::Status::Captured;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
log::trace!(
|
||||
target: TAB_REORDER_LOG_TARGET,
|
||||
"data received without entity id={my_id:?}"
|
||||
);
|
||||
state.drop_hint = None;
|
||||
|
||||
self.emit_drop_hint(shell, state.drop_hint);
|
||||
if let Some(event) = pending_reorder {
|
||||
if let Some(on_reorder) = self.on_reorder.as_ref() {
|
||||
shell.publish(on_reorder(event));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if cursor_position.is_over(bounds) {
|
||||
if cursor_position.is_over(my_bounds) {
|
||||
let fingers_pressed = state.fingers_pressed.len();
|
||||
|
||||
match event {
|
||||
|
|
@ -1166,10 +1175,14 @@ where
|
|||
// Check for clicks on the previous and next tab buttons, when tabs are collapsed.
|
||||
if state.collapsed {
|
||||
// Check if the prev tab button was clicked.
|
||||
if cursor_position.is_over(prev_tab_bounds(&bounds, f32::from(self.button_height)))
|
||||
if cursor_position
|
||||
.is_over(prev_tab_bounds(&my_bounds, f32::from(self.button_height)))
|
||||
&& self.prev_tab_sensitive(state)
|
||||
{
|
||||
state.hovered = Item::PrevButton;
|
||||
for key in self.model.order.iter().copied() {
|
||||
self.update_entity_paragraph(state, key);
|
||||
}
|
||||
if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))
|
||||
| Event::Touch(touch::Event::FingerLifted { .. }) = event
|
||||
{
|
||||
|
|
@ -1178,11 +1191,13 @@ where
|
|||
} else {
|
||||
// Check if the next tab button was clicked.
|
||||
if cursor_position
|
||||
.is_over(next_tab_bounds(&bounds, f32::from(self.button_height)))
|
||||
.is_over(next_tab_bounds(&my_bounds, f32::from(self.button_height)))
|
||||
&& self.next_tab_sensitive(state)
|
||||
{
|
||||
state.hovered = Item::NextButton;
|
||||
|
||||
for key in self.model.order.iter().copied() {
|
||||
self.update_entity_paragraph(state, key);
|
||||
}
|
||||
if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))
|
||||
| Event::Touch(touch::Event::FingerLifted { .. }) = event
|
||||
{
|
||||
|
|
@ -1193,7 +1208,7 @@ where
|
|||
}
|
||||
|
||||
for (key, bounds) in self
|
||||
.variant_bounds(state, bounds)
|
||||
.variant_bounds(state, my_bounds)
|
||||
.filter_map(|item| match item {
|
||||
ItemBounds::Button(entity, bounds) => Some((entity, bounds)),
|
||||
_ => None,
|
||||
|
|
@ -1203,7 +1218,12 @@ where
|
|||
if cursor_position.is_over(bounds) {
|
||||
if self.model.items[key].enabled {
|
||||
// Record that the mouse is hovering over this button.
|
||||
state.hovered = Item::Tab(key);
|
||||
if state.hovered != Item::Tab(key) {
|
||||
state.hovered = Item::Tab(key);
|
||||
for key in self.model.order.iter().copied() {
|
||||
self.update_entity_paragraph(state, key);
|
||||
}
|
||||
}
|
||||
|
||||
let close_button_bounds =
|
||||
close_bounds(bounds, f32::from(self.close_icon.size));
|
||||
|
|
@ -1320,6 +1340,9 @@ where
|
|||
}
|
||||
|
||||
break;
|
||||
} else if state.hovered == Item::Tab(key) {
|
||||
state.hovered = Item::None;
|
||||
self.update_entity_paragraph(state, key);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1377,15 +1400,22 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if state.is_focused() {
|
||||
// Unfocus on clicks outside of the boundaries of the segmented button.
|
||||
if is_pressed(&event) {
|
||||
state.unfocus();
|
||||
state.pressed_item = None;
|
||||
return event::Status::Ignored;
|
||||
} else {
|
||||
if let Item::Tab(key) = std::mem::replace(&mut state.hovered, Item::None) {
|
||||
for key in self.model.order.iter().copied() {
|
||||
self.update_entity_paragraph(state, key);
|
||||
}
|
||||
}
|
||||
if state.is_focused() {
|
||||
// Unfocus on clicks outside of the boundaries of the segmented button.
|
||||
if is_pressed(&event) {
|
||||
state.unfocus();
|
||||
state.pressed_item = None;
|
||||
return event::Status::Ignored;
|
||||
}
|
||||
} else if is_lifted(&event) {
|
||||
state.pressed_item = None;
|
||||
}
|
||||
} else if is_lifted(&event) {
|
||||
state.pressed_item = None;
|
||||
}
|
||||
|
||||
if let (Some(tab_drag), Some(candidate)) =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue