audio_processor_iced_design_system/
tree_view.rs

1// Augmented Audio: Audio libraries and applications
2// Copyright (c) 2022 Pedro Tacla Yamada
3//
4// The MIT License (MIT)
5//
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to deal
8// in the Software without restriction, including without limitation the rights
9// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10// copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12//
13// The above copyright notice and this permission notice shall be included in
14// all copies or substantial portions of the Software.
15//
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22// THE SOFTWARE.
23use iced::{widget::Column, Element, Length};
24
25pub use item::ItemState;
26
27use crate::updatable::Updatable;
28
29pub struct State<InnerState: Updatable> {
30    items: Vec<ItemState<InnerState>>,
31}
32
33impl<InnerState: Updatable> State<InnerState> {
34    pub fn new(items: Vec<ItemState<InnerState>>) -> Self {
35        State { items }
36    }
37}
38
39#[derive(Debug, Clone)]
40pub enum Message<InnerMessage> {
41    Child(usize, item::Message<InnerMessage>),
42}
43
44impl<InnerState: Updatable + 'static> State<InnerState> {
45    pub fn update(&mut self, msg: Message<InnerState::Message>) {
46        match msg {
47            Message::Child(index, msg) => {
48                self.items[index].update(msg);
49            }
50        }
51    }
52
53    pub fn view(&self) -> Element<Message<InnerState::Message>> {
54        let children = self
55            .items
56            .iter()
57            .enumerate()
58            .map(|(index, item)| item.view().map(move |msg| Message::Child(index, msg)))
59            .collect();
60        Column::with_children(children).width(Length::Fill).into()
61    }
62}
63
64mod item {
65    use std::fmt::Debug;
66
67    use iced::{widget::Button, widget::Column, widget::Container, widget::Text, Element};
68
69    use crate::spacing::Spacing;
70    use crate::updatable::Updatable;
71
72    #[derive(Debug, Clone)]
73    pub enum Message<InnerMessage> {
74        Toggle,
75        Child(usize, Box<Message<InnerMessage>>),
76        Inner(InnerMessage),
77    }
78
79    #[derive(Debug, Clone)]
80    pub enum ItemState<InnerState> {
81        Item {
82            title: String,
83            state: InnerState,
84        },
85        Parent {
86            title: String,
87            children: Vec<ItemState<InnerState>>,
88            is_collapsed: bool,
89        },
90    }
91
92    impl ItemState<()> {
93        pub fn child(title: String) -> Self {
94            ItemState::Item { title, state: () }
95        }
96    }
97
98    impl<InnerState> ItemState<InnerState>
99    where
100        InnerState: Updatable + 'static,
101    {
102        pub fn child_with(title: String, state: InnerState) -> Self {
103            ItemState::Item { title, state }
104        }
105
106        pub fn parent(title: String, children: Vec<ItemState<InnerState>>) -> Self {
107            ItemState::Parent {
108                title,
109                children,
110                is_collapsed: false,
111            }
112        }
113
114        pub fn update(&mut self, message: Message<InnerState::Message>) {
115            match self {
116                ItemState::Parent {
117                    is_collapsed,
118                    children,
119                    ..
120                } => match message {
121                    Message::Toggle => {
122                        *is_collapsed = !*is_collapsed;
123                    }
124                    Message::Child(index, msg) => {
125                        children[index].update(*msg);
126                    }
127                    _ => {}
128                },
129                ItemState::Item { state, .. } => {
130                    if let Message::Inner(inner) = message {
131                        state.update(inner);
132                    }
133                }
134            }
135        }
136
137        pub fn view(&self) -> Element<Message<InnerState::Message>> {
138            match self {
139                ItemState::Item { title, .. } => Text::new(title).into(),
140                ItemState::Parent {
141                    title,
142                    children,
143                    is_collapsed,
144                } => {
145                    let child_elements = Container::new(Column::with_children(
146                        children
147                            .iter()
148                            .enumerate()
149                            .map(|(index, item)| {
150                                item.view()
151                                    .map(move |msg| Message::Child(index, Box::new(msg)))
152                            })
153                            .collect(),
154                    ))
155                    .padding([0, 0, 0, Spacing::base_spacing()])
156                    .into();
157
158                    let toggle_button = Button::new(Text::new(title))
159                        .padding(0)
160                        .style(crate::style::ChromelessButton.into())
161                        .on_press(Message::Toggle)
162                        .into();
163
164                    let children = if *is_collapsed {
165                        vec![toggle_button]
166                    } else {
167                        vec![toggle_button, child_elements]
168                    };
169
170                    Column::with_children(children).into()
171                }
172            }
173        }
174    }
175}