audio_processor_iced_design_system/
tabs.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 std::fmt::Debug;
24
25use iced::{
26    widget::button, widget::Button, widget::Column, widget::Container, widget::Row, widget::Text,
27    Background, Color, Element, Length,
28};
29
30use crate::spacing::Spacing;
31use crate::style;
32
33#[derive(Clone, Debug)]
34pub enum Message<InnerMessage> {
35    SetTab(usize),
36    Inner(InnerMessage),
37}
38
39#[derive(Default)]
40pub struct State {
41    selected_tab: usize,
42}
43
44impl State {
45    pub fn new() -> Self {
46        State { selected_tab: 0 }
47    }
48
49    pub fn update<InnerMessage: Clone + Debug>(&mut self, message: Message<InnerMessage>) {
50        if let Message::SetTab(index) = message {
51            self.selected_tab = index;
52        }
53    }
54
55    pub fn view<'a, InnerMessage: 'static + Clone + Debug>(
56        &'a self,
57        mut items: Vec<Tab<'a, InnerMessage>>,
58    ) -> Element<Message<InnerMessage>> {
59        let selected_tab = self.selected_tab;
60        let heading = Row::with_children(
61            items
62                .iter()
63                .enumerate()
64                .map(|(index, tab)| {
65                    Button::new(Text::new(tab.title.clone()).size(Spacing::small_font_size()))
66                        .style(
67                            style::button::Button::default()
68                                .set_active(button::Appearance {
69                                    background: if index == selected_tab {
70                                        Some(Background::Color(Color::BLACK))
71                                    } else {
72                                        None
73                                    },
74                                    border_width: 0.0,
75                                    ..style::button::button_base_style()
76                                })
77                                .into(),
78                        )
79                        .on_press(Message::SetTab(index))
80                        .into()
81                })
82                .collect(),
83        );
84
85        let tab = items.swap_remove(self.selected_tab);
86        let element = tab.content.map(Message::Inner);
87
88        Container::new(Column::with_children(vec![
89            heading.into(),
90            iced::widget::rule::Rule::horizontal(1)
91                .style(style::Rule)
92                .into(),
93            element,
94        ]))
95        .style(style::Container0::default())
96        .width(Length::Fill)
97        .height(Length::Fill)
98        .into()
99    }
100}
101
102pub struct Tab<'a, InnerMessage> {
103    title: String,
104    content: Element<'a, InnerMessage>,
105}
106
107impl<'a, InnerMessage> Tab<'a, InnerMessage> {
108    pub fn new(title: impl Into<String>, content: impl Into<Element<'a, InnerMessage>>) -> Self {
109        Tab {
110            title: title.into(),
111            content: content.into(),
112        }
113    }
114}