1use freya_core::prelude::*;
2use torin::{
3 content::Content,
4 gaps::Gaps,
5 prelude::Alignment,
6 size::Size,
7};
8
9use crate::{
10 get_theme,
11 icons::arrow::ArrowIcon,
12 theming::component_themes::{
13 TableTheme,
14 TableThemePartial,
15 },
16};
17
18#[derive(Clone, Copy, PartialEq, Default)]
19pub enum OrderDirection {
20 Up,
21 #[default]
22 Down,
23}
24
25#[derive(PartialEq)]
26pub struct TableArrow {
27 pub order_direction: OrderDirection,
28 key: DiffKey,
29}
30
31impl TableArrow {
32 pub fn new(order_direction: OrderDirection) -> Self {
33 Self {
34 order_direction,
35 key: DiffKey::None,
36 }
37 }
38}
39
40impl KeyExt for TableArrow {
41 fn write_key(&mut self) -> &mut DiffKey {
42 &mut self.key
43 }
44}
45
46impl Component for TableArrow {
47 fn render(&self) -> impl IntoElement {
48 let TableTheme { arrow_fill, .. } = get_theme!(None::<TableThemePartial>, table);
49 let rotate = match self.order_direction {
50 OrderDirection::Down => 0.,
51 OrderDirection::Up => 180.,
52 };
53 ArrowIcon::new().rotate(rotate).fill(arrow_fill)
54 }
55
56 fn render_key(&self) -> DiffKey {
57 self.key.clone().or(self.default_key())
58 }
59}
60
61#[derive(PartialEq, Default)]
63pub struct TableHead {
64 pub children: Vec<Element>,
65 key: DiffKey,
66}
67
68impl TableHead {
69 pub fn new() -> Self {
70 Self::default()
71 }
72}
73
74impl ChildrenExt for TableHead {
75 fn get_children(&mut self) -> &mut Vec<Element> {
76 &mut self.children
77 }
78}
79
80impl KeyExt for TableHead {
81 fn write_key(&mut self) -> &mut DiffKey {
82 &mut self.key
83 }
84}
85
86impl Component for TableHead {
87 fn render(&self) -> impl IntoElement {
88 rect().width(Size::fill()).children(self.children.clone())
89 }
90
91 fn render_key(&self) -> DiffKey {
92 self.key.clone().or(self.default_key())
93 }
94}
95
96#[derive(PartialEq, Default)]
97pub struct TableBody {
98 pub children: Vec<Element>,
99 key: DiffKey,
100}
101
102impl TableBody {
103 pub fn new() -> Self {
104 Self::default()
105 }
106}
107impl ChildrenExt for TableBody {
108 fn get_children(&mut self) -> &mut Vec<Element> {
109 &mut self.children
110 }
111}
112
113impl KeyExt for TableBody {
114 fn write_key(&mut self) -> &mut DiffKey {
115 &mut self.key
116 }
117}
118
119impl Component for TableBody {
120 fn render(&self) -> impl IntoElement {
121 rect().width(Size::fill()).children(self.children.clone())
122 }
123
124 fn render_key(&self) -> DiffKey {
125 self.key.clone().or(self.default_key())
126 }
127}
128
129#[derive(PartialEq, Clone, Copy)]
130enum TableRowState {
131 Idle,
132 Hovering,
133}
134
135#[derive(PartialEq, Default)]
136pub struct TableRow {
137 pub theme: Option<TableThemePartial>,
138 pub children: Vec<Element>,
139 key: DiffKey,
140}
141
142impl TableRow {
143 pub fn new() -> Self {
144 Self::default()
145 }
146}
147
148impl ChildrenExt for TableRow {
149 fn get_children(&mut self) -> &mut Vec<Element> {
150 &mut self.children
151 }
152}
153
154impl KeyExt for TableRow {
155 fn write_key(&mut self) -> &mut DiffKey {
156 &mut self.key
157 }
158}
159
160impl Component for TableRow {
161 fn render(&self) -> impl IntoElement {
162 let theme = get_theme!(&self.theme, table);
163 let config = use_try_consume::<TableConfig>().unwrap_or_default();
164 let mut state = use_state(|| TableRowState::Idle);
165 let TableTheme {
166 divider_fill,
167 hover_row_background,
168 row_background,
169 ..
170 } = theme;
171 let background = if state() == TableRowState::Hovering {
172 hover_row_background
173 } else {
174 row_background
175 };
176
177 rect()
178 .on_pointer_enter(move |_| state.set(TableRowState::Hovering))
179 .on_pointer_leave(move |_| state.set(TableRowState::Idle))
180 .background(background)
181 .child(
182 rect()
183 .width(Size::fill())
184 .horizontal()
185 .content(Content::Flex)
186 .children(self.children.iter().enumerate().map(|(index, child)| {
187 let width = config
188 .column_widths
189 .as_ref()
190 .and_then(|widths| widths.get(index).cloned())
191 .unwrap_or_else(|| Size::flex(1.));
192
193 rect().width(width).child(child.clone()).into()
194 })),
195 )
196 .child(
197 rect()
198 .height(Size::px(1.))
199 .width(Size::fill())
200 .background(divider_fill),
201 )
202 }
203
204 fn render_key(&self) -> DiffKey {
205 self.key.clone().or(self.default_key())
206 }
207}
208
209#[derive(PartialEq)]
210pub struct TableCell {
211 pub children: Vec<Element>,
212 pub on_press: Option<EventHandler<Event<PressEventData>>>,
214 pub order_direction: Option<OrderDirection>,
216 pub padding: Gaps,
218 pub height: Size,
220 key: DiffKey,
221}
222
223impl ChildrenExt for TableCell {
224 fn get_children(&mut self) -> &mut Vec<Element> {
225 &mut self.children
226 }
227}
228
229impl Default for TableCell {
230 fn default() -> Self {
231 Self {
232 children: vec![],
233 on_press: None,
234 order_direction: None,
235 padding: Gaps::new_all(5.0),
236 height: Size::px(35.0),
237 key: DiffKey::None,
238 }
239 }
240}
241
242impl TableCell {
243 pub fn new() -> Self {
244 Self::default()
245 }
246
247 pub fn padding(mut self, padding: Gaps) -> Self {
248 self.padding = padding;
249 self
250 }
251
252 pub fn height(mut self, height: impl Into<Size>) -> Self {
253 self.height = height.into();
254 self
255 }
256
257 pub fn on_press(mut self, handler: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
258 self.on_press = Some(handler.into());
259 self
260 }
261
262 pub fn order_direction(mut self, dir: Option<OrderDirection>) -> Self {
263 self.order_direction = dir;
264 self
265 }
266}
267
268impl KeyExt for TableCell {
269 fn write_key(&mut self) -> &mut DiffKey {
270 &mut self.key
271 }
272}
273
274impl Component for TableCell {
275 fn render(&self) -> impl IntoElement {
276 let mut container = rect()
277 .overflow(Overflow::Clip)
278 .padding(self.padding)
279 .width(Size::fill())
280 .main_align(Alignment::End)
281 .cross_align(Alignment::Center)
282 .height(self.height.clone())
283 .horizontal();
284
285 if let Some(on_press) = &self.on_press {
286 let handler = on_press.clone();
287 container = container.on_press(move |e| handler.call(e));
288 }
289
290 if let Some(order_direction) = self.order_direction {
291 container = container.child(
292 rect()
293 .margin(Gaps::new_all(10.0))
294 .width(Size::px(10.0))
295 .height(Size::px(10.0))
296 .child(TableArrow::new(order_direction)),
297 );
298 }
299
300 container.children(self.children.clone())
301 }
302
303 fn render_key(&self) -> DiffKey {
304 self.key.clone().or(self.default_key())
305 }
306}
307
308#[cfg_attr(feature = "docs",
352 doc = embed_doc_image::embed_image!("table", "images/gallery_table.png"),
353)]
354#[derive(PartialEq)]
355pub struct Table {
356 pub height: Size,
357 pub theme: Option<TableThemePartial>,
358 pub column_widths: Option<Vec<Size>>,
359 pub children: Vec<Element>,
360 key: DiffKey,
361}
362
363impl Default for Table {
364 fn default() -> Self {
365 Self {
366 height: Size::Inner,
367 theme: None,
368 column_widths: None,
369 children: vec![],
370 key: DiffKey::None,
371 }
372 }
373}
374
375impl Table {
376 pub fn new() -> Self {
377 Self {
378 ..Default::default()
379 }
380 }
381
382 pub fn height(mut self, height: impl Into<Size>) -> Self {
383 self.height = height.into();
384 self
385 }
386
387 pub fn theme(mut self, theme: TableThemePartial) -> Self {
388 self.theme = Some(theme);
389 self
390 }
391
392 pub fn column_widths(mut self, widths: impl Into<Vec<Size>>) -> Self {
396 self.column_widths = Some(widths.into());
397 self
398 }
399}
400
401impl ChildrenExt for Table {
402 fn get_children(&mut self) -> &mut Vec<Element> {
403 &mut self.children
404 }
405}
406
407impl KeyExt for Table {
408 fn write_key(&mut self) -> &mut DiffKey {
409 &mut self.key
410 }
411}
412
413#[derive(Clone, Default)]
414pub struct TableConfig {
415 pub column_widths: Option<Vec<Size>>,
416}
417
418impl TableConfig {
419 pub fn new() -> Self {
420 Self::default()
421 }
422
423 pub fn with_column_widths(column_widths: Vec<Size>) -> Self {
424 Self {
425 column_widths: Some(column_widths),
426 }
427 }
428}
429
430impl Component for Table {
431 fn render(&self) -> impl IntoElement {
432 let TableTheme {
433 background,
434 corner_radius,
435 divider_fill,
436 color,
437 ..
438 } = get_theme!(&self.theme, table);
439
440 let config = match &self.column_widths {
441 Some(widths) => TableConfig::with_column_widths(widths.clone()),
442 None => TableConfig::default(),
443 };
444 provide_context(config);
445
446 rect()
447 .overflow(Overflow::Clip)
448 .color(color)
449 .background(background)
450 .corner_radius(corner_radius)
451 .height(self.height.clone())
452 .border(
453 Border::new()
454 .alignment(BorderAlignment::Outer)
455 .fill(divider_fill)
456 .width(1.0),
457 )
458 .children(self.children.clone())
459 }
460
461 fn render_key(&self) -> DiffKey {
462 self.key.clone().or(self.default_key())
463 }
464}