perspective_viewer/components/
string_column_style.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::prelude::*;
14use yew::*;
15
16use super::form::color_selector::*;
17use super::modal::{ModalLink, SetModalLink};
18use super::style::LocalStyle;
19use crate::components::form::select_field::SelectEnumField;
20use crate::config::*;
21use crate::utils::WeakScope;
22use crate::*;
23
24pub enum StringColumnStyleMsg {
25    Reset(StringColumnStyleConfig),
26    FormatChanged(Option<FormatMode>),
27    ColorModeChanged(Option<StringColorMode>),
28    ColorChanged(String),
29}
30
31#[derive(Properties)]
32pub struct StringColumnStyleProps {
33    pub config: Option<StringColumnStyleConfig>,
34    pub default_config: StringColumnStyleDefaultConfig,
35
36    #[prop_or_default]
37    pub on_change: Callback<ColumnConfigValueUpdate>,
38
39    #[prop_or_default]
40    weak_link: WeakScope<StringColumnStyle>,
41}
42
43impl ModalLink<StringColumnStyle> for StringColumnStyleProps {
44    fn weak_link(&self) -> &'_ WeakScope<StringColumnStyle> {
45        &self.weak_link
46    }
47}
48
49impl PartialEq for StringColumnStyleProps {
50    fn eq(&self, _other: &Self) -> bool {
51        false
52    }
53}
54
55/// A component for the style form control for [`String`] columns.
56pub struct StringColumnStyle {
57    config: StringColumnStyleConfig,
58    default_config: StringColumnStyleDefaultConfig,
59}
60
61impl StringColumnStyle {
62    /// When this config has changed, we must signal the wrapper element.
63    fn dispatch_config(&self, ctx: &Context<Self>) {
64        let update = Some(self.config.clone()).filter(|x| x != &StringColumnStyleConfig::default());
65        ctx.props()
66            .on_change
67            .emit(ColumnConfigValueUpdate::DatagridStringStyle(update));
68    }
69
70    /// Generate a color selector component for a specific `StringColorMode`
71    /// variant.
72    fn color_select_row(&self, ctx: &Context<Self>, mode: &StringColorMode, title: &str) -> Html {
73        let on_color = ctx.link().callback(StringColumnStyleMsg::ColorChanged);
74        let color = self
75            .config
76            .color
77            .clone()
78            .unwrap_or_else(|| self.default_config.color.to_owned());
79
80        let color_props = props!(ColorProps {
81            title: title.to_owned(),
82            color,
83            on_color
84        });
85
86        if &self.config.string_color_mode == mode {
87            html! { <div class="row"><ColorSelector ..color_props /></div> }
88        } else {
89            html! {}
90        }
91    }
92}
93
94impl Component for StringColumnStyle {
95    type Message = StringColumnStyleMsg;
96    type Properties = StringColumnStyleProps;
97
98    fn create(ctx: &Context<Self>) -> Self {
99        ctx.set_modal_link();
100        Self {
101            config: ctx.props().config.clone().unwrap_or_default(),
102            default_config: ctx.props().default_config.clone(),
103        }
104    }
105
106    // Always re-render when config changes.
107    fn changed(&mut self, ctx: &Context<Self>, _old: &Self::Properties) -> bool {
108        let mut new_config = ctx.props().config.clone().unwrap_or_default();
109        if self.config != new_config {
110            std::mem::swap(&mut self.config, &mut new_config);
111            true
112        } else {
113            false
114        }
115    }
116
117    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
118        match msg {
119            StringColumnStyleMsg::Reset(config) => {
120                self.config = config;
121                true
122            },
123            StringColumnStyleMsg::FormatChanged(val) => {
124                self.config.format = val.unwrap_or_default();
125                self.dispatch_config(ctx);
126                true
127            },
128            StringColumnStyleMsg::ColorModeChanged(mode) => {
129                self.config.string_color_mode = mode.unwrap_or_default();
130                self.dispatch_config(ctx);
131                true
132            },
133            StringColumnStyleMsg::ColorChanged(color) => {
134                self.config.color = Some(color);
135                self.dispatch_config(ctx);
136                false
137            },
138        }
139    }
140
141    fn view(&self, ctx: &Context<Self>) -> Html {
142        let format_mode_selected = self.config.format;
143        let format_mode_changed = ctx.link().callback(StringColumnStyleMsg::FormatChanged);
144        let selected_color_mode = self.config.string_color_mode;
145        let color_mode_changed = ctx.link().callback(StringColumnStyleMsg::ColorModeChanged);
146        let color_controls = match selected_color_mode {
147            StringColorMode::Foreground => {
148                self.color_select_row(ctx, &StringColorMode::Foreground, "foreground-label")
149            },
150            StringColorMode::Background => {
151                self.color_select_row(ctx, &StringColorMode::Background, "background-label")
152            },
153            StringColorMode::Series => {
154                self.color_select_row(ctx, &StringColorMode::Series, "series-label")
155            },
156            StringColorMode::None => html! {},
157        };
158
159        html! {
160            <>
161                <LocalStyle href={css!("column-style")} />
162                <div id="column-style-container" class="string-column-style-container">
163                    <SelectEnumField<FormatMode>
164                        label="format"
165                        on_change={format_mode_changed}
166                        current_value={format_mode_selected}
167                    />
168                    <SelectEnumField<StringColorMode>
169                        label="color"
170                        on_change={color_mode_changed}
171                        current_value={selected_color_mode}
172                    />
173                    { color_controls }
174                </div>
175            </>
176        }
177    }
178}