Skip to main content

perspective_viewer/components/containers/
tab_list.rs

1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ ██████ ██████ ██████       █      █      █      █      █ █▄  ▀███ █       ┃
3// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█  ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄  ▀█ █ ▀▀▀▀▀ ┃
4// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄   █ ▄▄▄▄▄ ┃
5// ┃ █      ██████ █  ▀█▄       █ ██████      █      ███▌▐███ ███████▄ █       ┃
6// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7// ┃ Copyright (c) 2017, the Perspective Authors.                              ┃
8// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9// ┃ This file is part of the Perspective library, distributed under the terms ┃
10// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
13use yew::{Callback, Children, Component, Html, Properties, classes, html};
14
15use crate::presentation::ColumnTab;
16
17#[derive(Properties, Debug, PartialEq)]
18pub struct TabListProps<T: ColumnTab> {
19    /// All tabs
20    pub tabs: Vec<T>,
21
22    /// Fires when the selected tab changes in the UI.
23    pub on_tab_change: Callback<(usize, T)>,
24
25    // Which tab is selected.
26    pub selected_tab: Option<usize>,
27
28    // The currently instantiated tabs.
29    pub children: Children,
30}
31
32pub enum TabListMsg {
33    SetSelected(usize),
34}
35
36pub struct TabList<T: ColumnTab> {
37    t: std::marker::PhantomData<T>,
38    selected_idx: usize,
39}
40
41impl<T: ColumnTab> Component for TabList<T> {
42    type Message = TabListMsg;
43    type Properties = TabListProps<T>;
44
45    fn create(_ctx: &yew::Context<Self>) -> Self {
46        Self {
47            t: std::marker::PhantomData,
48            selected_idx: 0,
49        }
50    }
51
52    fn update(&mut self, ctx: &yew::Context<Self>, msg: Self::Message) -> bool {
53        match msg {
54            TabListMsg::SetSelected(idx) => {
55                ctx.props()
56                    .on_tab_change
57                    .emit((idx, ctx.props().tabs[idx].clone()));
58                self.selected_idx = idx;
59                true
60            },
61        }
62    }
63
64    fn changed(&mut self, ctx: &yew::Context<Self>, _old_props: &Self::Properties) -> bool {
65        self.selected_idx = ctx.props().selected_tab.unwrap_or_default();
66        true
67    }
68
69    fn view(&self, ctx: &yew::Context<Self>) -> Html {
70        let p = ctx.props();
71        let gutter_tabs = p.tabs.iter().enumerate().map(|(idx, tab)| {
72            let mut class = classes!("settings_tab");
73            if idx == self.selected_idx {
74                class.push("selected_tab");
75            }
76
77            let onclick = ctx.link().callback(move |_| TabListMsg::SetSelected(idx));
78            html! {
79                <span {class} {onclick}>
80                    <div class="tab-title" id={tab.to_string()} />
81                    <div class="tab-border" />
82                </span>
83            }
84        });
85
86        html! {
87            <>
88                <div id="settings_tab_bar">{ for gutter_tabs }</div>
89                <div id="format-tab" class="tab-content scrollable">
90                    { ctx.props().children.iter().nth(self.selected_idx) }
91                </div>
92            </>
93        }
94    }
95}