check box hover

This commit is contained in:
galister 2026-07-13 01:56:39 +09:00
parent 28a9ed2c27
commit 0516270dcb
1 changed files with 97 additions and 39 deletions

View File

@ -81,8 +81,7 @@ impl TooltipTrait for State {
struct Data { struct Data {
#[allow(dead_code)] #[allow(dead_code)]
id_container: WidgetID, // Rectangle, transparent if not hovered id_container: WidgetID, // Rectangle, transparent if not hovered
id_outer_box: WidgetID, // Rectangle, has the border
//id_outer_box: WidgetID, // Rectangle, parent of container
id_inner_box: WidgetID, // Rectangle, parent of outer_box id_inner_box: WidgetID, // Rectangle, parent of outer_box
id_label: WidgetID, // Label, parent of container id_label: WidgetID, // Label, parent of container
value: Option<Rc<str>>, // arbitrary value assigned to the element value: Option<Rc<str>>, // arbitrary value assigned to the element
@ -97,7 +96,7 @@ pub struct ComponentCheckbox {
state: Rc<RefCell<State>>, state: Rc<RefCell<State>>,
} }
const COLOR_UNCHECKED: WguiColor = WguiColorName::Background.to_wgui_color(); const COLOR_UNCHECKED: WguiColor = WguiColor::Raw(drawing::Color::new(0., 0., 0., 0.));
const COLOR_HOVERED: WguiColor = WguiColorName::Tertiary.to_wgui_color(); const COLOR_HOVERED: WguiColor = WguiColorName::Tertiary.to_wgui_color();
impl ComponentTrait for ComponentCheckbox { impl ComponentTrait for ComponentCheckbox {
@ -114,10 +113,14 @@ impl ComponentTrait for ComponentCheckbox {
} }
} }
fn set_box_checked(widgets: &layout::WidgetMap, data: &Data, checked: bool) { fn set_box_checked(widgets: &layout::WidgetMap, data: &Data, checked: bool, hovered: bool) {
widgets.call(data.id_inner_box, |rect: &mut WidgetRectangle| { widgets.call(data.id_inner_box, |rect: &mut WidgetRectangle| {
rect.params.color = if checked { rect.params.color = if checked {
data.color_checked if hovered {
COLOR_HOVERED.into()
} else {
data.color_checked
}
} else { } else {
COLOR_UNCHECKED.into() COLOR_UNCHECKED.into()
} }
@ -134,14 +137,16 @@ impl ComponentCheckbox {
} }
pub fn set_checked(&self, common: &mut CallbackDataCommon, checked: bool) { pub fn set_checked(&self, common: &mut CallbackDataCommon, checked: bool) {
let hovered;
{ {
let mut state = self.state.borrow_mut(); let mut state = self.state.borrow_mut();
if state.checked == checked { if state.checked == checked {
return; return;
} }
state.checked = checked; state.checked = checked;
hovered = state.hovered;
} }
set_box_checked(&common.state.widgets, &self.data, checked); set_box_checked(&common.state.widgets, &self.data, checked, hovered);
common.alterables.mark_redraw(); common.alterables.mark_redraw();
} }
@ -164,37 +169,37 @@ impl ComponentCheckbox {
} }
} }
fn anim_hover(rect: &mut WidgetRectangle, pos: f32, pressed: bool) { fn anim_hover(anim_data: &mut crate::animation::CallbackData<'_>, pos: f32, _pressed: bool) {
let mut brightness = pos * if pressed { 0.6 } else { 0.4 }; let rect = anim_data.obj.as_any_mut().downcast_mut::<WidgetRectangle>().unwrap();
rect.params.border = 2.0; rect.params.border = 2.0;
rect.params.color = rect.params.color.with_alpha(brightness); rect.params.border_color = if pos > 0.0 {
if pressed { COLOR_HOVERED.into()
brightness += 0.4; } else {
} WguiColorName::OnBackground.into()
rect.params.border_color = rect.params.border_color.with_alpha(brightness); };
} }
fn anim_hover_in(state: Rc<RefCell<State>>, widget_id: WidgetID, anim_mult: f32) -> Animation { fn anim_hover_in(state: Rc<RefCell<State>>, data: Rc<Data>, anim_mult: f32) -> Animation {
let down = state.borrow().down;
Animation::new( Animation::new(
widget_id, data.id_outer_box,
(5. * anim_mult) as _, (5. * anim_mult) as _,
AnimationEasing::OutQuad, AnimationEasing::OutQuad,
Box::new(move |common, anim_data| { Box::new(move |common, anim_data| {
let rect = anim_data.obj.get_as_mut::<WidgetRectangle>().unwrap(); anim_hover(anim_data, anim_data.pos, down);
anim_hover(rect, anim_data.pos, state.borrow().down);
common.alterables.mark_redraw(); common.alterables.mark_redraw();
}), }),
) )
} }
fn anim_hover_out(state: Rc<RefCell<State>>, widget_id: WidgetID, anim_mult: f32) -> Animation { fn anim_hover_out(state: Rc<RefCell<State>>, data: Rc<Data>, anim_mult: f32) -> Animation {
let down = state.borrow().down;
Animation::new( Animation::new(
widget_id, data.id_outer_box,
(8. * anim_mult) as _, (8. * anim_mult) as _,
AnimationEasing::OutQuad, AnimationEasing::OutQuad,
Box::new(move |common, anim_data| { Box::new(move |common, anim_data| {
let rect = anim_data.obj.get_as_mut::<WidgetRectangle>().unwrap(); anim_hover(anim_data, 1.0 - anim_data.pos, down);
anim_hover(rect, 1.0 - anim_data.pos, state.borrow().down);
common.alterables.mark_redraw(); common.alterables.mark_redraw();
}), }),
) )
@ -202,6 +207,7 @@ fn anim_hover_out(state: Rc<RefCell<State>>, widget_id: WidgetID, anim_mult: f32
fn register_event_mouse_enter( fn register_event_mouse_enter(
state: Rc<RefCell<State>>, state: Rc<RefCell<State>>,
data: Rc<Data>,
listeners: &mut EventListenerCollection, listeners: &mut EventListenerCollection,
tooltip_info: Option<tooltip::TooltipInfo>, tooltip_info: Option<tooltip::TooltipInfo>,
anim_mult: f32, anim_mult: f32,
@ -212,11 +218,25 @@ fn register_event_mouse_enter(
common.alterables.trigger_haptics(); common.alterables.trigger_haptics();
common common
.alterables .alterables
.animate(anim_hover_in(state.clone(), event_data.widget_id, anim_mult)); .animate(anim_hover_in(state.clone(), data.clone(), anim_mult));
ComponentTooltip::register_hover_in(common, &tooltip_info, event_data.widget_id, state.clone()); ComponentTooltip::register_hover_in(common, &tooltip_info, event_data.widget_id, state.clone());
state.borrow_mut().hovered = true; let checked = {
let mut state = state.borrow_mut();
state.hovered = true;
state.checked
};
if checked {
common
.state
.widgets
.call(data.id_inner_box, |rect: &mut WidgetRectangle| {
rect.params.color = COLOR_HOVERED.into();
});
}
Ok(EventResult::Pass) Ok(EventResult::Pass)
}), }),
) )
@ -224,21 +244,32 @@ fn register_event_mouse_enter(
fn register_event_mouse_leave( fn register_event_mouse_leave(
state: Rc<RefCell<State>>, state: Rc<RefCell<State>>,
data: Rc<Data>,
listeners: &mut EventListenerCollection, listeners: &mut EventListenerCollection,
anim_mult: f32, anim_mult: f32,
) -> EventListenerID { ) -> EventListenerID {
listeners.register( listeners.register(
EventListenerKind::MouseLeave, EventListenerKind::MouseLeave,
Box::new(move |common, event_data, (), ()| { Box::new(move |common, _event_data, (), ()| {
common.alterables.trigger_haptics(); common.alterables.trigger_haptics();
common common
.alterables .alterables
.animate(anim_hover_out(state.clone(), event_data.widget_id, anim_mult)); .animate(anim_hover_out(state.clone(), data.clone(), anim_mult));
{ let checked = {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
state.hovered = false; state.hovered = false;
state.active_tooltip = None; state.active_tooltip = None;
state.checked
};
if checked {
common
.state
.widgets
.call(data.id_inner_box, |rect: &mut WidgetRectangle| {
rect.params.color = data.color_checked;
});
} }
Ok(EventResult::Pass) Ok(EventResult::Pass)
@ -257,14 +288,28 @@ fn register_event_mouse_cancel(state: Rc<RefCell<State>>, listeners: &mut EventL
) )
} }
fn register_event_mouse_press(state: Rc<RefCell<State>>, listeners: &mut EventListenerCollection) -> EventListenerID { fn register_event_mouse_press(
state: Rc<RefCell<State>>,
data: Rc<Data>,
listeners: &mut EventListenerCollection,
) -> EventListenerID {
listeners.register( listeners.register(
EventListenerKind::MousePress, EventListenerKind::MousePress,
Box::new(move |common, event_data, (), ()| { Box::new(move |common, _event_data, (), ()| {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let pressed_hovered = state.hovered;
let rect = event_data.obj.get_as_mut::<WidgetRectangle>().unwrap(); common
anim_hover(rect, 1.0, true); .state
.widgets
.call(data.id_outer_box, |rect: &mut WidgetRectangle| {
rect.params.border = 2.0;
rect.params.border_color = if pressed_hovered {
COLOR_HOVERED.into()
} else {
WguiColorName::OnBackground.into()
};
});
common.alterables.trigger_haptics(); common.alterables.trigger_haptics();
common.alterables.mark_redraw(); common.alterables.mark_redraw();
@ -287,15 +332,27 @@ fn register_event_mouse_release(
) -> EventListenerID { ) -> EventListenerID {
listeners.register( listeners.register(
EventListenerKind::MouseRelease, EventListenerKind::MouseRelease,
Box::new(move |common, event_data, (), ()| { Box::new(move |common, _event_data, (), ()| {
let rect = event_data.obj.get_as_mut::<WidgetRectangle>().unwrap(); let mut state = state.borrow_mut();
anim_hover(rect, 1.0, false); let released_hovered = state.hovered;
let was_down = state.down;
common
.state
.widgets
.call(data.id_outer_box, |rect: &mut WidgetRectangle| {
rect.params.border = 2.0;
rect.params.border_color = if released_hovered {
COLOR_HOVERED.into()
} else {
WguiColorName::OnBackground.into()
};
});
common.alterables.trigger_haptics(); common.alterables.trigger_haptics();
common.alterables.mark_redraw(); common.alterables.mark_redraw();
let mut state = state.borrow_mut(); if was_down {
if state.down {
state.down = false; state.down = false;
if let Some(self_ref) = state.self_ref.upgrade() if let Some(self_ref) = state.self_ref.upgrade()
@ -313,7 +370,7 @@ fn register_event_mouse_release(
}); });
} }
set_box_checked(&common.state.widgets, &data, state.checked); set_box_checked(&common.state.widgets, &data, state.checked, state.hovered);
if state.hovered if state.hovered
&& let Some(on_toggle) = &state.on_toggle && let Some(on_toggle) = &state.on_toggle
{ {
@ -435,6 +492,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
let data = Rc::new(Data { let data = Rc::new(Data {
id_container, id_container,
id_outer_box: outer_box.id,
id_inner_box: inner_box.id, id_inner_box: inner_box.id,
id_label: label.id, id_label: label.id,
value: params.value, value: params.value,
@ -457,10 +515,10 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
let listeners = &mut root.widget.state().event_listeners; let listeners = &mut root.widget.state().event_listeners;
let anim_mult = ess.layout.state.theme.animation_mult; let anim_mult = ess.layout.state.theme.animation_mult;
vec![ vec![
register_event_mouse_enter(state.clone(), listeners, params.tooltip, anim_mult), register_event_mouse_enter(state.clone(), data.clone(), listeners, params.tooltip, anim_mult),
register_event_mouse_leave(state.clone(), listeners, anim_mult), register_event_mouse_leave(state.clone(), data.clone(), listeners, anim_mult),
register_event_mouse_cancel(state.clone(), listeners), register_event_mouse_cancel(state.clone(), listeners),
register_event_mouse_press(state.clone(), listeners), register_event_mouse_press(state.clone(), data.clone(), listeners),
register_event_mouse_release(data.clone(), state.clone(), listeners), register_event_mouse_release(data.clone(), state.clone(), listeners),
] ]
}, },