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 {
46 #[default]
47 None,
48 Fill,
49 Left,
50 Right,
51 Top,
52 Bottom,
53}
54
55#[derive(Debug, Clone, Copy, PartialEq)]
57pub enum FocusStyle {
58 Outline,
60 Fill,
62 None,
64}
65
66impl Default for FocusStyle {
67 fn default() -> Self {
68 FocusStyle::Outline
69 }
70}
71
72#[derive(Debug, Clone)]
74pub struct Style {
75 pub w: f32, pub h: f32, pub min_w: f32,
78 pub min_h: f32,
79 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,
87 pub font_scale: f32,
88 pub text_shadow: bool, pub focus_style: FocusStyle,
90 pub focus_color: u32, pub no_wrap: bool,
96}
97
98impl Default for Style {
99 fn default() -> Self {
100 Self {
101 w: 0.0,
102 h: 0.0,
103 min_w: 4.0,
104 min_h: 4.0,
105 flex: 0.0,
106 dock: Dock::None,
107 gap: 2.0,
108 pad: [0.0; 4],
109 margin: [0.0; 4],
110 bg: 0,
111 color: 0xFF_CCCCAA,
112 align: Align::Start,
113 font_scale: 1.0,
114 text_shadow: true,
115 focus_style: FocusStyle::default(),
116 focus_color: 0,
117 no_wrap: false,
118 }
119 }
120}
121
122impl Widget {
125 fn new(kind: WidgetKind) -> Self {
126 let flex_dir = if let WidgetKind::Panel(dir) = &kind {
127 *dir
128 } else {
129 FlexDir::Column
130 };
131 Self {
132 kind,
133 id: None,
134 style: Style::default(),
135 flex_dir,
136 children: Vec::new(),
137 on_click: None,
138 enabled: true,
139 focused: false,
140 }
141 }
142
143 pub fn id(mut self, id: impl Into<String>) -> Self {
144 self.id = Some(id.into());
145 self
146 }
147 pub fn on_click(mut self, ev: impl Into<String>) -> Self {
148 self.on_click = Some(ev.into());
149 self
150 }
151 pub fn child(mut self, w: Widget) -> Self {
152 self.children.push(w);
153 self
154 }
155
156 pub fn w(mut self, w: f32) -> Self {
157 self.style.w = w;
158 self
159 }
160 pub fn h(mut self, h: f32) -> Self {
161 self.style.h = h;
162 self
163 }
164 pub fn min_w(mut self, v: f32) -> Self {
165 self.style.min_w = v;
166 self
167 }
168 pub fn min_h(mut self, v: f32) -> Self {
169 self.style.min_h = v;
170 self
171 }
172 pub fn flex(mut self, v: f32) -> Self {
173 self.style.flex = v;
174 self
175 }
176 pub fn flex_dir(mut self, v: FlexDir) -> Self {
177 self.flex_dir = v;
178 self
179 }
180 pub fn gap(mut self, v: f32) -> Self {
181 self.style.gap = v;
182 self
183 }
184 pub fn bg(mut self, v: u32) -> Self {
185 self.style.bg = v;
186 self
187 }
188 pub fn color(mut self, v: u32) -> Self {
189 self.style.color = v;
190 self
191 }
192 pub fn align(mut self, v: Align) -> Self {
193 self.style.align = v;
194 self
195 }
196 pub fn font_scale(mut self, v: f32) -> Self {
197 self.style.font_scale = v;
198 self
199 }
200 pub fn shadow(mut self, v: bool) -> Self {
201 self.style.text_shadow = v;
202 self
203 }
204 pub fn no_wrap(mut self) -> Self {
205 self.style.no_wrap = true;
206 self
207 }
208 pub fn focus_style(mut self, v: FocusStyle) -> Self {
209 self.style.focus_style = v;
210 self
211 }
212 pub fn focus_color(mut self, v: u32) -> Self {
213 self.style.focus_color = v;
214 self
215 }
216 pub fn dock(mut self, v: Dock) -> Self {
217 self.style.dock = v;
218 self
219 }
220 pub fn enabled(mut self, v: bool) -> Self {
221 self.enabled = v;
222 self
223 }
224 pub fn focused(mut self, v: bool) -> Self {
225 self.focused = v;
226 self
227 }
228 pub fn padding(mut self, top: f32, right: f32, bottom: f32, left: f32) -> Self {
229 self.style.pad = [top, right, bottom, left];
230 self
231 }
232 pub fn margin(mut self, top: f32, right: f32, bottom: f32, left: f32) -> Self {
233 self.style.margin = [top, right, bottom, left];
234 self
235 }
236}
237
238pub fn panel(dir: FlexDir) -> Widget {
241 Widget::new(WidgetKind::Panel(dir))
242}
243pub fn label(text: impl Into<String>) -> Widget {
244 Widget::new(WidgetKind::Label(text.into()))
245}
246pub fn button(text: impl Into<String>) -> Widget {
247 Widget::new(WidgetKind::Button(text.into()))
248}
249pub fn item_slot(item_id: impl Into<String>) -> Widget {
250 Widget::new(WidgetKind::ItemSlot(item_id.into()))
251}
252pub fn inv_slot(index: usize) -> Widget {
253 Widget::new(WidgetKind::InvSlot(index)).w(18.0).h(18.0)
254}
255pub fn mc_image(id: impl Into<String>, img_w: f32, img_h: f32) -> Widget {
256 Widget::new(WidgetKind::McImage {
257 id: id.into(),
258 img_w,
259 img_h,
260 })
261 .w(img_w)
262 .h(img_h)
263}
264pub fn spacer() -> Widget {
265 Widget::new(WidgetKind::Spacer)
266}