diff --git a/src/components/panel.rs b/src/components/panel.rs
index 19fbaddd9576c02051bae8fa92f87e2887c49add..c2b9de30c4689f9624ddd85b6dbd26dd27f6d17d 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 599a66307d06fc8a7c2e730a9c60d1723da78392..f4b6077c83a24b9fb780b1e75599112241a46daf 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 ae0653fc0b4712a92fdf5e774738c5d3be624f13..6b1afffa63f75c8b654bac65229e7b67300ff333 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()