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