From b08d135339854fba5a88251d9ccd55122f04267e Mon Sep 17 00:00:00 2001 From: Louis Capitanchik <contact@louiscap.co> Date: Mon, 6 Feb 2023 13:28:10 +0000 Subject: [PATCH] Update panel widget --- src/components/panel.rs | 42 +++++++++++------- src/lib.rs | 4 +- src/utilities.rs | 95 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 119 insertions(+), 22 deletions(-) diff --git a/src/components/panel.rs b/src/components/panel.rs index 19fbadd..c2b9de3 100644 --- a/src/components/panel.rs +++ b/src/components/panel.rs @@ -14,9 +14,10 @@ pub enum PanelVariant { Simple, } -#[derive(Component, Default, Clone, PartialEq, Eq)] +#[derive(Component, Default, Clone, PartialEq)] pub struct PanelProps { pub background: Option<String>, + pub inner_layout: StyleProp<LayoutType>, } impl Widget for PanelProps {} @@ -41,38 +42,47 @@ pub fn render_panel_widget( .unwrap(); *computed = KStyle { - render_command: value(RenderCommand::Quad), + render_command: value(RenderCommand::NinePatch { + handle: patch.handle.clone_weak(), + border: patch.border, + }), min_height: px(patch.border.bottom + patch.border.top + 8.0), min_width: px(patch.border.left + patch.border.right + 8.0), - padding: value(Edge::all(Units::Stretch(0.0))), ..Default::default() } .with_style(style) + .with_style(KStyle { + padding: value(Edge::new( + Units::Pixels(patch.border.top), + Units::Pixels(patch.border.right), + Units::Pixels(patch.border.bottom), + Units::Pixels(patch.border.left), + )), + ..Default::default() + }) .into(); let inner_style = match &style.padding { StyleProp::Unset => KStyle { - padding: value(Edge::new( - Units::Pixels(patch.border.top), - Units::Pixels(patch.border.right), - Units::Pixels(patch.border.bottom), - Units::Pixels(patch.border.left), - )), + layout_type: props.inner_layout.clone(), ..Default::default() }, pad => KStyle { + layout_type: props.inner_layout.clone(), padding: pad.clone(), ..Default::default() }, }; - rsx! { - <NinePatchBundle - nine_patch={patch.clone()} - styles={inner_style} - children={children.clone()} - /> - }; + children.process(&widget_context, Some(entity)); + + // rsx! { + // <NinePatchBundle + // nine_patch={patch.clone()} + // styles={inner_style} + // children={children.clone()} + // /> + // }; } true } diff --git a/src/lib.rs b/src/lib.rs index 599a663..f4b6077 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,8 +37,8 @@ pub use styles::{edge_px, pct, px, stretch, val_auto, value}; pub use theme::{tokens, ThemeMapping, ThemeProvider}; pub use types::IconContent; pub use utilities::{ - context, remove_root_ui, remove_tagged_root, widget_update_with_resource, EmptyProps, - StateUIRoot, + button_logic, context, remove_root_ui, remove_tagged_root, widget_update_with_resource, + EmptyProps, HasDisabledState, HasHoveredState, HasPressedState, StateUIRoot, TextSizer, }; pub mod prelude { diff --git a/src/utilities.rs b/src/utilities.rs index ae0653f..6b1afff 100644 --- a/src/utilities.rs +++ b/src/utilities.rs @@ -3,15 +3,17 @@ use std::marker::PhantomData; use bevy::asset::Assets; use bevy::ecs::system::SystemParam; use bevy::prelude::{ - Commands, Component, DespawnRecursiveExt, Entity, In, Query, Res, Resource, With, + Commands, Component, DespawnRecursiveExt, Entity, In, ParamSet, Query, Res, Resource, With, }; use kayak_font::{Alignment, KayakFont, TextProperties}; use kayak_ui::prelude::{ - Event, EventDispatcherContext, FontMapping, KayakRootContext, KayakWidgetContext, WidgetParam, - WidgetState, + Event, EventDispatcherContext, EventType, FontMapping, KayakRootContext, KayakWidgetContext, + OnEvent, WidgetParam, WidgetState, }; +use micro_musicbox::prelude::MusicBox; use crate::theme::ThemeMapping; +use crate::tokens::{THEME_SOUND_BUTTON_CLICK, THEME_SOUND_BUTTON_OVER}; #[derive(bevy::prelude::Component, Clone, PartialEq, Default)] pub struct EmptyProps; @@ -293,6 +295,91 @@ macro_rules! on_button_click { }; } +pub trait HasDisabledState { + fn is_disabled(&self) -> bool; + fn set_disabled(&mut self, value: bool); +} + +pub trait HasPressedState { + fn is_pressed(&self) -> bool; + fn set_pressed(&mut self, value: bool); +} + +pub trait HasHoveredState { + fn is_hovered(&self) -> bool; + fn set_hovered(&mut self, value: bool); +} + +pub fn button_logic<Props, State>(entity: Entity, state_entity: Entity) -> OnEvent +where + Props: HasDisabledState + Component + Clone, + State: HasHoveredState + HasPressedState + Component, +{ + OnEvent::new( + move |In((event_dispatcher_context, _, mut event, _)): In<( + EventDispatcherContext, + WidgetState, + Event, + Entity, + )>, + mut params: ParamSet<(Query<&Props>, Query<&mut State>, MusicBox<ThemeMapping>)>| { + let widget_props = match params.p0().get(entity) { + Ok(p) => p.clone(), + Err(..) => return (event_dispatcher_context, event), + }; + + let mut should_click = false; + let mut should_proing = false; + + if let Ok(mut state) = params.p1().get_mut(state_entity) { + match &event.event_type { + EventType::Hover(..) => { + if !widget_props.is_disabled() { + state.set_hovered(true); + } + } + EventType::MouseIn(..) => { + if !widget_props.is_disabled() { + state.set_hovered(true); + should_click = true; + } + } + EventType::MouseOut(..) => { + state.set_hovered(false); + state.set_pressed(false); + } + EventType::MouseDown(..) => { + if !widget_props.is_disabled() { + state.set_pressed(true); + } + } + EventType::MouseUp(..) => { + state.set_pressed(false); + } + EventType::Click(..) => { + if widget_props.is_disabled() { + event.prevent_default(); + event.stop_propagation(); + } else { + should_proing = true; + } + } + _ => {} + } + } + + if should_click { + params.p2().play_ui_sfx(THEME_SOUND_BUTTON_CLICK); + } + if should_proing { + params.p2().play_ui_sfx(THEME_SOUND_BUTTON_OVER); + } + + (event_dispatcher_context, event) + }, + ) +} + #[derive(SystemParam)] pub struct TextSizer<'w, 's> { pub assets: Res<'w, ThemeMapping>, @@ -316,7 +403,7 @@ impl<'w, 's> TextSizer<'w, 's> { line_height: font_size + 2.0, alignment: Alignment::Start, tab_size: 4, - max_size: (100000.0, font_size + 2.0), + max_size: (100000.0, font_size + 8.0), }, ) .size() -- GitLab