1use std::marker::PhantomData;
5
6use masonry::core::{FromDynWidget, Widget, WidgetMut};
7use masonry::properties::types::Length;
8use masonry::widgets;
9
10use crate::core::{
11 AppendVec, ElementSplice, MessageContext, MessageResult, Mut, SuperElement, View, ViewElement,
12 ViewMarker, ViewSequence,
13};
14use crate::{Pod, ViewCtx, WidgetView};
15
16pub use masonry::widgets::GridParams;
17pub fn grid<State, Action, Seq: GridSequence<State, Action>>(
50 sequence: Seq,
51 width: i32,
52 height: i32,
53) -> Grid<Seq, State, Action> {
54 Grid {
55 sequence,
56 spacing: Length::ZERO,
57 height,
58 width,
59 phantom: PhantomData,
60 }
61}
62
63#[must_use = "View values do nothing unless provided to Xilem."]
67pub struct Grid<Seq, State, Action = ()> {
68 sequence: Seq,
69 spacing: Length,
70 width: i32,
71 height: i32,
72
73 phantom: PhantomData<fn() -> (State, Action)>,
77}
78
79impl<Seq, State, Action> Grid<Seq, State, Action> {
80 #[track_caller]
82 pub fn spacing(mut self, spacing: Length) -> Self {
83 self.spacing = spacing;
84 self
85 }
86}
87
88mod hidden {
89 use super::GridElement;
90 use crate::core::AppendVec;
91
92 #[doc(hidden)]
93 #[expect(
94 unnameable_types,
95 reason = "Implementation detail, public because of trait visibility rules"
96 )]
97 pub struct GridState<SeqState> {
98 pub(crate) seq_state: SeqState,
99 pub(crate) scratch: AppendVec<GridElement>,
100 }
101}
102
103use hidden::GridState;
104
105impl<Seq, State, Action> ViewMarker for Grid<Seq, State, Action> {}
106
107impl<State, Action, Seq> View<State, Action, ViewCtx> for Grid<Seq, State, Action>
108where
109 State: 'static,
110 Action: 'static,
111 Seq: GridSequence<State, Action>,
112{
113 type Element = Pod<widgets::Grid>;
114
115 type ViewState = GridState<Seq::SeqState>;
116
117 fn build(&self, ctx: &mut ViewCtx, app_state: &mut State) -> (Self::Element, Self::ViewState) {
118 let mut elements = AppendVec::default();
119 let mut widget = widgets::Grid::with_dimensions(self.width, self.height);
120 widget = widget.with_spacing(self.spacing);
121 let seq_state = self.sequence.seq_build(ctx, &mut elements, app_state);
122 for element in elements.drain() {
123 widget = widget.with_child(element.child.new_widget, element.params);
124 }
125 let pod = ctx.create_pod(widget);
126 (
127 pod,
128 GridState {
129 seq_state,
130 scratch: elements,
131 },
132 )
133 }
134
135 fn rebuild(
136 &self,
137 prev: &Self,
138 GridState { seq_state, scratch }: &mut Self::ViewState,
139 ctx: &mut ViewCtx,
140 mut element: Mut<'_, Self::Element>,
141 app_state: &mut State,
142 ) {
143 if prev.height != self.height {
144 widgets::Grid::set_height(&mut element, self.height);
145 }
146 if prev.width != self.width {
147 widgets::Grid::set_width(&mut element, self.width);
148 }
149 if prev.spacing != self.spacing {
150 widgets::Grid::set_spacing(&mut element, self.spacing);
151 }
152
153 let mut splice = GridSplice::new(element, scratch);
154 self.sequence
155 .seq_rebuild(&prev.sequence, seq_state, ctx, &mut splice, app_state);
156 debug_assert!(scratch.is_empty());
157 }
158
159 fn teardown(
160 &self,
161 GridState { seq_state, scratch }: &mut Self::ViewState,
162 ctx: &mut ViewCtx,
163 element: Mut<'_, Self::Element>,
164 ) {
165 let mut splice = GridSplice::new(element, scratch);
166 self.sequence.seq_teardown(seq_state, ctx, &mut splice);
167 debug_assert!(scratch.is_empty());
168 }
169
170 fn message(
171 &self,
172 GridState { seq_state, scratch }: &mut Self::ViewState,
173 message: &mut MessageContext,
174 element: Mut<'_, Self::Element>,
175 app_state: &mut State,
176 ) -> MessageResult<Action> {
177 let mut splice = GridSplice::new(element, scratch);
178 let result = self
179 .sequence
180 .seq_message(seq_state, message, &mut splice, app_state);
181 debug_assert!(scratch.is_empty());
182 result
183 }
184}
185
186impl ViewElement for GridElement {
188 type Mut<'w> = GridElementMut<'w>;
189}
190
191impl SuperElement<Self, ViewCtx> for GridElement {
193 fn upcast(_ctx: &mut ViewCtx, child: Self) -> Self {
194 child
195 }
196
197 fn with_downcast_val<R>(
198 mut this: Mut<'_, Self>,
199 f: impl FnOnce(Mut<'_, Self>) -> R,
200 ) -> (Self::Mut<'_>, R) {
201 let r = {
202 let parent = this.parent.reborrow_mut();
203 let reborrow = GridElementMut {
204 idx: this.idx,
205 parent,
206 };
207 f(reborrow)
208 };
209 (this, r)
210 }
211}
212
213impl<W: Widget + FromDynWidget + ?Sized> SuperElement<Pod<W>, ViewCtx> for GridElement {
214 fn upcast(_: &mut ViewCtx, child: Pod<W>) -> Self {
215 Self {
221 child: child.erased(),
222 params: GridParams::new(1, 1, 1, 1),
224 }
225 }
226
227 fn with_downcast_val<R>(
228 mut this: Mut<'_, Self>,
229 f: impl FnOnce(Mut<'_, Pod<W>>) -> R,
230 ) -> (Mut<'_, Self>, R) {
231 let ret = {
232 let mut child = widgets::Grid::child_mut(&mut this.parent, this.idx);
233 let downcast = child.downcast();
234 f(downcast)
235 };
236
237 (this, ret)
238 }
239}
240
241impl ElementSplice<GridElement> for GridSplice<'_, '_> {
243 fn with_scratch<R>(&mut self, f: impl FnOnce(&mut AppendVec<GridElement>) -> R) -> R {
244 let ret = f(self.scratch);
245 for element in self.scratch.drain() {
246 widgets::Grid::insert_grid_child_at(
247 &mut self.element,
248 self.idx,
249 element.child.new_widget,
250 element.params,
251 );
252 self.idx += 1;
253 }
254 ret
255 }
256
257 fn insert(&mut self, element: GridElement) {
258 widgets::Grid::insert_grid_child_at(
259 &mut self.element,
260 self.idx,
261 element.child.new_widget,
262 element.params,
263 );
264 self.idx += 1;
265 }
266
267 fn mutate<R>(&mut self, f: impl FnOnce(Mut<'_, GridElement>) -> R) -> R {
268 let child = GridElementMut {
269 parent: self.element.reborrow_mut(),
270 idx: self.idx,
271 };
272 let ret = f(child);
273 self.idx += 1;
274 ret
275 }
276
277 fn skip(&mut self, n: usize) {
278 self.idx += n;
279 }
280
281 fn index(&self) -> usize {
282 self.idx
283 }
284
285 fn delete<R>(&mut self, f: impl FnOnce(Mut<'_, GridElement>) -> R) -> R {
286 let ret = {
287 let child = GridElementMut {
288 parent: self.element.reborrow_mut(),
289 idx: self.idx,
290 };
291 f(child)
292 };
293 widgets::Grid::remove_child(&mut self.element, self.idx);
294 ret
295 }
296}
297
298pub trait GridSequence<State, Action = ()>:
300 ViewSequence<State, Action, ViewCtx, GridElement>
301{
302}
303
304impl<Seq, State, Action> GridSequence<State, Action> for Seq where
305 Seq: ViewSequence<State, Action, ViewCtx, GridElement>
306{
307}
308
309pub trait GridExt<State, Action>: WidgetView<State, Action> {
311 fn grid_item(self, params: impl Into<GridParams>) -> GridItem<Self, State, Action>
328 where
329 State: 'static,
330 Action: 'static,
331 Self: Sized,
332 {
333 grid_item(self, params)
334 }
335
336 fn grid_pos(self, x: i32, y: i32) -> GridItem<Self, State, Action>
355 where
356 State: 'static,
357 Action: 'static,
358 Self: Sized,
359 {
360 grid_item(self, GridParams::new(x, y, 1, 1))
361 }
362}
363
364impl<State, Action, V: WidgetView<State, Action>> GridExt<State, Action> for V {}
365
366pub struct GridElement {
368 child: Pod<dyn Widget>,
370 params: GridParams,
372}
373
374pub struct GridElementMut<'w> {
376 parent: WidgetMut<'w, widgets::Grid>,
377 idx: usize,
378}
379
380struct GridSplice<'w, 's> {
382 idx: usize,
383 element: WidgetMut<'w, widgets::Grid>,
384 scratch: &'s mut AppendVec<GridElement>,
385}
386
387impl<'w, 's> GridSplice<'w, 's> {
388 fn new(element: WidgetMut<'w, widgets::Grid>, scratch: &'s mut AppendVec<GridElement>) -> Self {
389 Self {
390 idx: 0,
391 element,
392 scratch,
393 }
394 }
395}
396
397pub struct GridItem<V, State, Action> {
399 view: V,
400 params: GridParams,
401 phantom: PhantomData<fn() -> (State, Action)>,
402}
403
404pub fn grid_item<V, State, Action>(
406 view: V,
407 params: impl Into<GridParams>,
408) -> GridItem<V, State, Action>
409where
410 State: 'static,
411 Action: 'static,
412 V: WidgetView<State, Action>,
413{
414 GridItem {
415 view,
416 params: params.into(),
417 phantom: PhantomData,
418 }
419}
420
421impl<V, State, Action> ViewMarker for GridItem<V, State, Action> {}
422
423impl<State, Action, V> View<State, Action, ViewCtx> for GridItem<V, State, Action>
424where
425 State: 'static,
426 Action: 'static,
427 V: WidgetView<State, Action>,
428{
429 type Element = GridElement;
430
431 type ViewState = V::ViewState;
432
433 fn build(&self, ctx: &mut ViewCtx, app_state: &mut State) -> (Self::Element, Self::ViewState) {
434 let (pod, state) = self.view.build(ctx, app_state);
435 (
436 GridElement {
437 child: pod.erased(),
438 params: self.params,
439 },
440 state,
441 )
442 }
443
444 fn rebuild(
445 &self,
446 prev: &Self,
447 view_state: &mut Self::ViewState,
448 ctx: &mut ViewCtx,
449 mut element: Mut<'_, Self::Element>,
450 app_state: &mut State,
451 ) {
452 {
453 if self.params != prev.params {
454 widgets::Grid::update_child_grid_params(
455 &mut element.parent,
456 element.idx,
457 self.params,
458 );
459 }
460 let mut child = widgets::Grid::child_mut(&mut element.parent, element.idx);
461 self.view
462 .rebuild(&prev.view, view_state, ctx, child.downcast(), app_state);
463 }
464 }
465
466 fn teardown(
467 &self,
468 view_state: &mut Self::ViewState,
469 ctx: &mut ViewCtx,
470 mut element: Mut<'_, Self::Element>,
471 ) {
472 let mut child = widgets::Grid::child_mut(&mut element.parent, element.idx);
473 self.view.teardown(view_state, ctx, child.downcast());
474 }
475
476 fn message(
477 &self,
478 view_state: &mut Self::ViewState,
479 message: &mut MessageContext,
480 mut element: Mut<'_, Self::Element>,
481 app_state: &mut State,
482 ) -> MessageResult<Action> {
483 let mut child = widgets::Grid::child_mut(&mut element.parent, element.idx);
484 self.view
485 .message(view_state, message, child.downcast(), app_state)
486 }
487}