1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//! ViewGroup definition and implementation for common types.

use embedded_graphics::{prelude::Point, primitives::Rectangle};

use crate::{prelude::RectExt, View};

mod object_chain;
mod views;

pub use views::Views;

/// A set of operations required to implement [`View`] containers.
pub trait ViewGroup: View {
    /// Returns the number of [`View`] objects in this view group.
    fn len(&self) -> usize;

    /// Returns a shared reference the [`View`] object at position `idx`.
    fn at(&self, idx: usize) -> &dyn View;

    /// Returns an exclusive reference to the [`View`] object at position `idx`.
    fn at_mut(&mut self, idx: usize) -> &mut dyn View;
}

/// A [`ViewGroup`] that contains no [`View`] objects.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct EmptyViewGroup;

/// A single instance of [`EmptyViewGroup`].
pub static mut EMPTY_VIEW_GROUP: EmptyViewGroup = EmptyViewGroup;

impl View for EmptyViewGroup {
    fn translate_impl(&mut self, _by: Point) {}

    fn bounds(&self) -> Rectangle {
        Rectangle::zero()
    }
}

impl ViewGroup for EmptyViewGroup {
    fn len(&self) -> usize {
        0
    }

    fn at(&self, _idx: usize) -> &dyn View {
        self
    }

    fn at_mut(&mut self, _idx: usize) -> &mut dyn View {
        self
    }
}

/// Utility struct to simplify implementing [`View`] operations for any [`ViewGroup`].
pub struct ViewGroupHelper;

impl ViewGroupHelper {
    /// Translates every [`View`] object in a view group.
    #[inline]
    pub fn translate(vg: &mut impl ViewGroup, by: Point) {
        for i in 0..ViewGroup::len(vg) {
            vg.at_mut(i).translate_impl(by);
        }
    }

    /// Returns the smallest bounding box that envelopes all [`View`] objects in a view group.
    #[inline]
    pub fn bounds(vg: &impl ViewGroup) -> Rectangle {
        if ViewGroup::len(vg) == 0 {
            return EmptyViewGroup.bounds();
        }

        let mut rect = vg.at(0).bounds();

        for i in 1..vg.len() {
            rect = rect.enveloping(&vg.at(i).bounds());
        }

        rect
    }
}