klondike_lib/display/stack/
mod.rs

1use std::fmt;
2
3use crate::model::stack::{Orientation, Stack};
4
5use super::{card::CardWidget, geometry, selector::SelectorWidget, Widget};
6
7use self::common::Offsets;
8
9mod common;
10mod horizontal;
11mod vertical;
12
13#[derive(Debug)]
14pub struct StackWidget<'a> {
15    pub bounds: geometry::Rect<u16>,
16    pub stack: &'a Stack<'a>,
17}
18
19impl<'a> Widget for StackWidget<'a> {
20    fn bounds(&self) -> geometry::Rect<u16> {
21        let offsets = self.offsets();
22
23        let mut bounds = geometry::Rect::new(self.bounds.origin, geometry::Size2D::zero());
24
25        for card_widget in self.card_widget_iter(&offsets) {
26            bounds = bounds.union(&card_widget.bounds());
27        }
28
29        if let Some(selector_widget) = self.selector_widget(&offsets) {
30            bounds = bounds.union(&selector_widget.bounds());
31        }
32
33        bounds
34    }
35}
36
37impl<'a> fmt::Display for StackWidget<'a> {
38    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
39        let offsets = self.offsets();
40
41        for card_widget in self.card_widget_iter(&offsets) {
42            write!(fmt, "{}", card_widget)?;
43        }
44
45        if let Some(selector_widget) = self.selector_widget(&offsets) {
46            write!(fmt, "{}", selector_widget)?;
47        }
48
49        Ok(())
50    }
51}
52
53impl<'a> StackWidget<'a> {
54    fn offsets(&self) -> Offsets {
55        match self.stack.details.orientation {
56            Orientation::Horizontal => horizontal::offsets(self),
57            Orientation::Vertical => vertical::offsets(self),
58        }
59    }
60
61    fn card_widget_iter(&'a self, offsets: &'a Offsets) -> impl Iterator<Item = CardWidget<'a>> {
62        // We can't just match and return the iterators like we do for the other methods, because
63        // they have different opaque iterator types. So we'll create separate variables for both
64        // but only populate one, and then we'll chain the optional iterators.
65        let mut horizontal_iter = None;
66        let mut vertical_iter = None;
67
68        match self.stack.details.orientation {
69            Orientation::Horizontal => {
70                horizontal_iter = Some(horizontal::card_widget_iter(self, offsets))
71            }
72            Orientation::Vertical => {
73                vertical_iter = Some(vertical::card_widget_iter(self, offsets))
74            }
75        }
76
77        // Flatten the optional iterators to regular (possibly empty) iterators.
78        let horizontal_iter = horizontal_iter.into_iter().flatten();
79        let vertical_iter = vertical_iter.into_iter().flatten();
80
81        horizontal_iter.chain(vertical_iter)
82    }
83
84    fn selector_widget(&self, offsets: &Offsets) -> Option<SelectorWidget> {
85        match self.stack.details.orientation {
86            Orientation::Horizontal => horizontal::selector_widget(self, offsets),
87            Orientation::Vertical => vertical::selector_widget(self, offsets),
88        }
89    }
90}