1use core::marker::PhantomData;
2
3use alloc::vec::Vec;
4
5use crate::{
6 align::{Alignment, Axis},
7 el::{El, ElId},
8 event::{Capture, CommonEvent, Event, EventResponse, Propagate},
9 layout::{Layout, Viewport},
10 padding::Padding,
11 render::Renderer,
12 size::{Length, Size},
13 state::StateNode,
14 ui::UiCtx,
15 widget::Widget,
16};
17
18pub trait LinearDirection {
19 const AXIS: Axis;
20}
21
22pub struct DirectionColumn;
23impl LinearDirection for DirectionColumn {
24 const AXIS: Axis = Axis::Y;
25}
26
27pub struct DirectionRow;
28impl LinearDirection for DirectionRow {
29 const AXIS: Axis = Axis::X;
30}
31
32pub type Column<'a, Message, R, E, S> = Linear<'a, Message, R, E, S, DirectionColumn>;
33pub type Row<'a, Message, R, E, S> = Linear<'a, Message, R, E, S, DirectionRow>;
34
35pub struct Linear<'a, Message, R: Renderer, E: Event, S, D: LinearDirection> {
36 spacing: u32,
37 size: Size<Length>,
38 padding: Padding,
39 gap: u32,
40 align: Alignment,
41 children: Vec<El<'a, Message, R, E, S>>,
42
43 dir: PhantomData<D>,
44}
45
46impl<'a, Message, R: Renderer, E: Event, S, D: LinearDirection> Linear<'a, Message, R, E, S, D> {
47 pub fn new(children: impl IntoIterator<Item = El<'a, Message, R, E, S>>) -> Self {
48 Self {
49 spacing: 0,
50 size: Size::fill(),
51 padding: Padding::default(),
52 gap: 0,
53 align: Alignment::Start,
54 children: children.into_iter().collect(),
55 dir: PhantomData,
56 }
57 }
58
59 pub fn spacing(mut self, spacing: u32) -> Self {
60 self.spacing = spacing;
61 self
62 }
63
64 pub fn width(mut self, width: impl Into<Length>) -> Self {
65 self.size.width = width.into();
66 self
67 }
68
69 pub fn height(mut self, height: impl Into<Length>) -> Self {
70 self.size.height = height.into();
71 self
72 }
73
74 pub fn padding(mut self, padding: impl Into<Padding>) -> Self {
75 self.padding = padding.into();
76 self
77 }
78
79 pub fn gap(mut self, gap: u32) -> Self {
80 self.gap = gap;
81 self
82 }
83
84 pub fn align(mut self, align: Alignment) -> Self {
85 self.align = align;
86 self
87 }
88
89 pub fn add(mut self, child: impl Into<El<'a, Message, R, E, S>>) -> Self {
90 self.children.push(child.into());
91 self
92 }
93
94 }
111
112impl<'a, Message, R: Renderer, E: Event, S, D: LinearDirection> Widget<Message, R, E, S>
113 for Linear<'a, Message, R, E, S, D>
114{
115 fn id(&self) -> Option<crate::el::ElId> {
116 None
117 }
118
119 fn tree_ids(&self) -> Vec<ElId> {
120 self.children.iter().map(|child| child.tree_ids()).flatten().collect()
121 }
122
123 fn size(&self) -> crate::size::Size<Length> {
124 self.size
125 }
126
127 fn state_children(&self) -> Vec<StateNode> {
128 self.children.iter().map(|child| StateNode::new(child)).collect()
129 }
130
131 fn on_event(
132 &mut self,
133 ctx: &mut UiCtx<Message>,
134 event: E,
135 state: &mut crate::state::StateNode,
136 ) -> EventResponse<E> {
137 for (child, child_state) in self.children.iter_mut().zip(state.children.iter_mut()) {
138 match child.on_event(ctx, event.clone(), child_state)? {
139 Propagate::Ignored => {},
140 bubbled @ Propagate::BubbleUp(_, _) => return bubbled.into(),
141 }
142 }
143
144 Propagate::Ignored.into()
145 }
146
147 fn layout(
148 &self,
149 ctx: &mut UiCtx<Message>,
150 state: &mut StateNode,
151 styler: &S,
152 limits: &crate::layout::Limits,
153 viewport: &Viewport,
154 ) -> crate::layout::LayoutNode {
155 Layout::flex(
156 ctx,
157 state,
158 styler,
159 D::AXIS,
160 limits,
161 self.size,
162 crate::layout::Position::Relative,
163 viewport,
164 self.padding,
165 self.gap,
166 self.align,
167 &self.children,
168 )
169 }
170
171 fn draw(
172 &self,
173 ctx: &mut UiCtx<Message>,
174 state: &mut StateNode,
175 renderer: &mut R,
176 styler: &S,
177 layout: crate::layout::Layout,
178 ) {
179 for ((child, child_state), child_layout) in
181 self.children.iter().zip(state.children.iter_mut()).zip(layout.children())
182 {
183 child.draw(ctx, child_state, renderer, styler, child_layout);
184 }
185 }
186}
187
188impl<'a, Message, R, E, S, D> From<Linear<'a, Message, R, E, S, D>> for El<'a, Message, R, E, S>
189where
190 Message: 'a,
191 R: Renderer + 'a,
192 E: Event + 'a,
193 S: 'a,
194 D: LinearDirection + 'a,
195{
196 fn from(value: Linear<'a, Message, R, E, S, D>) -> Self {
197 Self::new(value)
198 }
199}