implement listeners for Button component back

This commit is contained in:
Aleksander
2025-06-28 18:30:38 +02:00
parent 2420e8007c
commit 28d58fef59
6 changed files with 65 additions and 26 deletions

View File

@@ -62,7 +62,7 @@ fn load_testbed(
let name = std::env::var("TESTBED").unwrap_or_default(); let name = std::env::var("TESTBED").unwrap_or_default();
Ok(match name.as_str() { Ok(match name.as_str() {
"" => Box::new(TestbedGeneric::new(listeners)?), "" => Box::new(TestbedGeneric::new(listeners)?),
_ => Box::new(TestbedAny::new(&name)?), _ => Box::new(TestbedAny::new(&name, listeners)?),
}) })
} }

View File

@@ -1,16 +1,19 @@
use crate::{assets, testbed::Testbed}; use crate::{assets, testbed::Testbed};
use glam::Vec2; use glam::Vec2;
use wgui::layout::Layout; use wgui::{event::EventListenerCollection, layout::Layout};
pub struct TestbedAny { pub struct TestbedAny {
pub layout: Layout, pub layout: Layout,
} }
impl TestbedAny { impl TestbedAny {
pub fn new(name: &str) -> anyhow::Result<Self> { pub fn new(
name: &str,
listeners: &mut EventListenerCollection<(), ()>,
) -> anyhow::Result<Self> {
let path = format!("gui/{name}.xml"); let path = format!("gui/{name}.xml");
let (layout, _state) = let (layout, _state) =
wgui::parser::new_layout_from_assets(Box::new(assets::Asset {}), &path)?; wgui::parser::new_layout_from_assets(Box::new(assets::Asset {}), listeners, &path)?;
Ok(Self { layout }) Ok(Self { layout })
} }
} }

View File

@@ -11,7 +11,7 @@ impl TestbedGeneric {
const XML_PATH: &str = "gui/testbed.xml"; const XML_PATH: &str = "gui/testbed.xml";
let (layout, _res) = let (layout, _res) =
wgui::parser::new_layout_from_assets(Box::new(assets::Asset {}), XML_PATH)?; wgui::parser::new_layout_from_assets(Box::new(assets::Asset {}), listeners, XML_PATH)?;
Ok(Self { layout }) Ok(Self { layout })
} }

View File

@@ -2,10 +2,10 @@ use std::sync::Arc;
use taffy::{AlignItems, JustifyContent, prelude::length}; use taffy::{AlignItems, JustifyContent, prelude::length};
use crate::{ use crate::{
animation::{Animation, AnimationEasing}, animation::{self, Animation, AnimationEasing},
components::Component, components::Component,
drawing::{self, Color}, drawing::{self, Color},
event::WidgetCallback, event::{EventListenerCollection, EventListenerKind, WidgetCallback},
layout::{Layout, WidgetID}, layout::{Layout, WidgetID},
renderer_vk::text::{FontWeight, TextStyle}, renderer_vk::text::{FontWeight, TextStyle},
widget::{ widget::{
@@ -38,7 +38,8 @@ impl Default for Params<'_> {
} }
pub struct Button { pub struct Button {
pub color: drawing::Color, initial_color: drawing::Color,
initial_border_color: drawing::Color,
pub body: WidgetID, // Rectangle pub body: WidgetID, // Rectangle
pub text_id: WidgetID, // Text pub text_id: WidgetID, // Text
text_node: taffy::NodeId, text_node: taffy::NodeId,
@@ -59,6 +60,18 @@ impl Button {
} }
} }
fn anim_hover(rect: &mut Rectangle, button: &Button, pos: f32) {
let brightness = pos * 0.5;
let border_brightness = pos;
rect.params.color.r = button.initial_color.r + brightness;
rect.params.color.g = button.initial_color.g + brightness;
rect.params.color.b = button.initial_color.b + brightness;
rect.params.border_color.r = button.initial_border_color.r + border_brightness;
rect.params.border_color.g = button.initial_border_color.g + border_brightness;
rect.params.border_color.b = button.initial_border_color.b + border_brightness;
rect.params.border = 3.0;
}
fn anim_hover_in(button: Arc<Button>, widget_id: WidgetID) -> Animation { fn anim_hover_in(button: Arc<Button>, widget_id: WidgetID) -> Animation {
Animation::new( Animation::new(
widget_id, widget_id,
@@ -66,12 +79,7 @@ fn anim_hover_in(button: Arc<Button>, widget_id: WidgetID) -> Animation {
AnimationEasing::OutQuad, AnimationEasing::OutQuad,
Box::new(move |data| { Box::new(move |data| {
let rect = data.obj.get_as_mut::<Rectangle>(); let rect = data.obj.get_as_mut::<Rectangle>();
let brightness = data.pos * 0.5; anim_hover(rect, &button, data.pos);
rect.params.color.r = button.color.r + brightness;
rect.params.color.g = button.color.g + brightness;
rect.params.color.b = button.color.b + brightness;
rect.params.border_color = Color::new(1.0, 1.0, 1.0, 1.0);
rect.params.border = 1.0 + data.pos;
data.needs_redraw = true; data.needs_redraw = true;
}), }),
) )
@@ -84,12 +92,7 @@ fn anim_hover_out(button: Arc<Button>, widget_id: WidgetID) -> Animation {
AnimationEasing::OutQuad, AnimationEasing::OutQuad,
Box::new(move |data| { Box::new(move |data| {
let rect = data.obj.get_as_mut::<Rectangle>(); let rect = data.obj.get_as_mut::<Rectangle>();
let brightness = (1.0 - data.pos) * 0.5; anim_hover(rect, &button, 1.0 - data.pos);
rect.params.color.r = button.color.r + brightness;
rect.params.color.g = button.color.g + brightness;
rect.params.color.b = button.color.b + brightness;
rect.params.border_color = Color::new(1.0, 1.0, 1.0, 1.0);
rect.params.border = 1.0 + (1.0 - data.pos) * 2.0;
data.needs_redraw = true; data.needs_redraw = true;
}), }),
) )
@@ -97,6 +100,7 @@ fn anim_hover_out(button: Arc<Button>, widget_id: WidgetID) -> Animation {
pub fn construct( pub fn construct(
layout: &mut Layout, layout: &mut Layout,
listeners: &mut EventListenerCollection<(), ()>,
parent: WidgetID, parent: WidgetID,
params: Params, params: Params,
) -> anyhow::Result<Arc<Button>> { ) -> anyhow::Result<Arc<Button>> {
@@ -142,14 +146,35 @@ pub fn construct(
let button = Arc::new(Button { let button = Arc::new(Button {
body: rect_id, body: rect_id,
color: params.color,
text_id, text_id,
text_node, text_node,
initial_color: params.color,
initial_border_color: params.border_color,
}); });
//TODO: Highlight background on mouse enter //let mut widget = layout.widget_map.get(rect_id).unwrap().lock().unwrap();
//TODO: Bring back old color on mouse leave let _button = button.clone();
listeners.add(
rect_id,
EventListenerKind::MouseEnter,
Box::new(move |data, _, _| {
data
.animations
.push(anim_hover_in(_button.clone(), data.widget_id));
}),
);
let _button = button.clone();
listeners.add(
rect_id,
EventListenerKind::MouseLeave,
Box::new(move |data, _, _| {
data
.animations
.push(anim_hover_out(_button.clone(), data.widget_id));
}),
);
Ok(button) Ok(button)
} }

View File

@@ -45,6 +45,7 @@ pub fn parse_component_button<'a>(
let button = button::construct( let button = button::construct(
ctx.layout, ctx.layout,
ctx.listeners,
parent_id, parent_id,
button::Params { button::Params {
color, color,

View File

@@ -8,6 +8,7 @@ mod widget_sprite;
use crate::{ use crate::{
assets::AssetProvider, assets::AssetProvider,
drawing::{self}, drawing::{self},
event::EventListenerCollection,
layout::{Layout, WidgetID}, layout::{Layout, WidgetID},
parser::{ parser::{
component_button::parse_component_button, widget_div::parse_widget_div, component_button::parse_component_button, widget_div::parse_widget_div,
@@ -62,6 +63,7 @@ impl ParserResult {
&mut self, &mut self,
template_name: &str, template_name: &str,
layout: &mut Layout, layout: &mut Layout,
listeners: &mut EventListenerCollection<(), ()>,
widget_id: WidgetID, widget_id: WidgetID,
template_parameters: HashMap<Rc<str>, Rc<str>>, template_parameters: HashMap<Rc<str>, Rc<str>>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
@@ -71,6 +73,7 @@ impl ParserResult {
let mut ctx = ParserContext { let mut ctx = ParserContext {
layout, layout,
listeners,
ids: Default::default(), ids: Default::default(),
macro_attribs: self.macro_attribs.clone(), // FIXME: prevent copying macro_attribs: self.macro_attribs.clone(), // FIXME: prevent copying
var_map: self.var_map.clone(), // FIXME: prevent copying var_map: self.var_map.clone(), // FIXME: prevent copying
@@ -107,6 +110,7 @@ struct MacroAttribs {
struct ParserContext<'a> { struct ParserContext<'a> {
layout: &'a mut Layout, layout: &'a mut Layout,
listeners: &'a mut EventListenerCollection<(), ()>,
var_map: HashMap<Rc<str>, Rc<str>>, var_map: HashMap<Rc<str>, Rc<str>>,
macro_attribs: HashMap<Rc<str>, MacroAttribs>, macro_attribs: HashMap<Rc<str>, MacroAttribs>,
ids: HashMap<Rc<str>, WidgetID>, ids: HashMap<Rc<str>, WidgetID>,
@@ -557,9 +561,13 @@ fn parse_children<'a>(
Ok(()) Ok(())
} }
fn create_default_context(layout: &mut Layout) -> ParserContext<'_> { fn create_default_context<'a>(
layout: &'a mut Layout,
listeners: &'a mut EventListenerCollection<(), ()>,
) -> ParserContext<'a> {
ParserContext { ParserContext {
layout, layout,
listeners,
ids: Default::default(), ids: Default::default(),
var_map: Default::default(), var_map: Default::default(),
templates: Default::default(), templates: Default::default(),
@@ -569,12 +577,13 @@ fn create_default_context(layout: &mut Layout) -> ParserContext<'_> {
pub fn parse_from_assets( pub fn parse_from_assets(
layout: &mut Layout, layout: &mut Layout,
listeners: &mut EventListenerCollection<(), ()>,
parent_id: WidgetID, parent_id: WidgetID,
path: &str, path: &str,
) -> anyhow::Result<ParserResult> { ) -> anyhow::Result<ParserResult> {
let path = PathBuf::from(path); let path = PathBuf::from(path);
let mut ctx = create_default_context(layout); let mut ctx = create_default_context(layout, listeners);
let (file, node_layout) = get_doc_from_path(&mut ctx, &path)?; let (file, node_layout) = get_doc_from_path(&mut ctx, &path)?;
parse_document_root(file, &mut ctx, parent_id, node_layout)?; parse_document_root(file, &mut ctx, parent_id, node_layout)?;
@@ -595,11 +604,12 @@ pub fn parse_from_assets(
pub fn new_layout_from_assets( pub fn new_layout_from_assets(
assets: Box<dyn AssetProvider>, assets: Box<dyn AssetProvider>,
listeners: &mut EventListenerCollection<(), ()>,
path: &str, path: &str,
) -> anyhow::Result<(Layout, ParserResult)> { ) -> anyhow::Result<(Layout, ParserResult)> {
let mut layout = Layout::new(assets)?; let mut layout = Layout::new(assets)?;
let widget = layout.root_widget; let widget = layout.root_widget;
let state = parse_from_assets(&mut layout, widget, path)?; let state = parse_from_assets(&mut layout, listeners, widget, path)?;
Ok((layout, state)) Ok((layout, state))
} }