1use crate::layout::{Align, FlexDir};
4
5#[derive(Debug, Clone)]
7pub struct Widget {
8 pub kind: WidgetKind,
9 pub id: Option<String>,
10 pub style: Style,
11 pub flex_dir: FlexDir,
12 pub children: Vec<Widget>,
13 pub on_click: Option<String>,
14 pub enabled: bool,
15 pub focused: bool,
16}
17
18#[derive(Debug, Clone)]
19pub enum WidgetKind {
20 Panel(FlexDir),
22 Label(String),
24 Button(String),
26 ItemSlot(String),
28 InvSlot(usize),
30 McImage { id: String, img_w: f32, img_h: f32 },
32 Spacer,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Default)]
45pub enum Dock { #[default] None, Fill, Left, Right, Top, Bottom }
46
47#[derive(Debug, Clone, Copy, PartialEq)]
49pub enum FocusStyle {
50 Outline,
52 Fill,
54 None,
56}
57
58impl Default for FocusStyle { fn default() -> Self { FocusStyle::Outline } }
59
60#[derive(Debug, Clone)]
62pub struct Style {
63 pub w: f32, pub h: f32, pub min_w: f32,
66 pub min_h: f32,
67 pub flex: f32, pub dock: Dock, pub gap: f32, pub pad: [f32; 4], pub margin: [f32; 4], pub bg: u32, pub color: u32, pub align: Align,
75 pub font_scale: f32,
76 pub text_shadow: bool, pub focus_style: FocusStyle,
78 pub focus_color: u32, pub no_wrap: bool,
84}
85
86impl Default for Style {
87 fn default() -> Self {
88 Self {
89 w: 0.0, h: 0.0, min_w: 4.0, min_h: 4.0, flex: 0.0, dock: Dock::None, gap: 2.0,
90 pad: [0.0; 4], margin: [0.0; 4], bg: 0, color: 0xFF_CCCCAA,
91 align: Align::Start, font_scale: 1.0, text_shadow: true,
92 focus_style: FocusStyle::default(), focus_color: 0, no_wrap: false,
93 }
94 }
95}
96
97impl Widget {
100 fn new(kind: WidgetKind) -> Self {
101 let flex_dir = if let WidgetKind::Panel(dir) = &kind { *dir } else { FlexDir::Column };
102 Self { kind, id: None, style: Style::default(), flex_dir,
103 children: Vec::new(), on_click: None, enabled: true, focused: false }
104 }
105
106 pub fn id(mut self, id: impl Into<String>) -> Self { self.id = Some(id.into()); self }
107 pub fn on_click(mut self, ev: impl Into<String>) -> Self { self.on_click = Some(ev.into()); self }
108 pub fn child(mut self, w: Widget) -> Self { self.children.push(w); self }
109
110 pub fn w(mut self, w: f32) -> Self { self.style.w = w; self }
111 pub fn h(mut self, h: f32) -> Self { self.style.h = h; self }
112 pub fn min_w(mut self, v: f32) -> Self { self.style.min_w = v; self }
113 pub fn min_h(mut self, v: f32) -> Self { self.style.min_h = v; self }
114 pub fn flex(mut self, v: f32) -> Self { self.style.flex = v; self }
115 pub fn flex_dir(mut self, v: FlexDir) -> Self { self.flex_dir = v; self }
116 pub fn gap(mut self, v: f32) -> Self { self.style.gap = v; self }
117 pub fn bg(mut self, v: u32) -> Self { self.style.bg = v; self }
118 pub fn color(mut self, v: u32) -> Self { self.style.color = v; self }
119 pub fn align(mut self, v: Align) -> Self { self.style.align = v; self }
120 pub fn font_scale(mut self, v: f32) -> Self { self.style.font_scale = v; self }
121 pub fn shadow(mut self, v: bool) -> Self { self.style.text_shadow = v; self }
122 pub fn no_wrap(mut self) -> Self { self.style.no_wrap = true; self }
123 pub fn focus_style(mut self, v: FocusStyle) -> Self { self.style.focus_style = v; self }
124 pub fn focus_color(mut self, v: u32) -> Self { self.style.focus_color = v; self }
125 pub fn dock(mut self, v: Dock) -> Self { self.style.dock = v; self }
126 pub fn enabled(mut self, v: bool) -> Self { self.enabled = v; self }
127 pub fn focused(mut self, v: bool) -> Self { self.focused = v; self }
128 pub fn padding(mut self, top: f32, right: f32, bottom: f32, left: f32) -> Self {
129 self.style.pad = [top, right, bottom, left]; self
130 }
131 pub fn margin(mut self, top: f32, right: f32, bottom: f32, left: f32) -> Self {
132 self.style.margin = [top, right, bottom, left]; self
133 }
134}
135
136pub fn panel(dir: FlexDir) -> Widget { Widget::new(WidgetKind::Panel(dir)) }
139pub fn label(text: impl Into<String>) -> Widget { Widget::new(WidgetKind::Label(text.into())) }
140pub fn button(text: impl Into<String>) -> Widget { Widget::new(WidgetKind::Button(text.into())) }
141pub fn item_slot(item_id: impl Into<String>) -> Widget { Widget::new(WidgetKind::ItemSlot(item_id.into())) }
142pub fn inv_slot(index: usize) -> Widget { Widget::new(WidgetKind::InvSlot(index)).w(18.0).h(18.0) }
143pub fn mc_image(id: impl Into<String>, img_w: f32, img_h: f32) -> Widget {
144 Widget::new(WidgetKind::McImage { id: id.into(), img_w, img_h })
145 .w(img_w).h(img_h)
146}
147pub fn spacer() -> Widget { Widget::new(WidgetKind::Spacer) }