Skip to main content

freya_components/
titlebar.rs

1use freya_core::prelude::*;
2use torin::size::Size;
3
4use crate::{
5    define_theme,
6    get_theme,
7};
8
9define_theme! {
10    %[component]
11    pub TitlebarButton {
12        %[fields]
13        background: Color,
14        hover_background: Color,
15        corner_radius: CornerRadius,
16        width: Size,
17        height: Size,
18    }
19}
20
21#[derive(Clone, PartialEq, Copy)]
22pub enum TitlebarAction {
23    Minimize,
24    Maximize,
25    Close,
26}
27
28/// Titlebar button component.
29#[derive(PartialEq)]
30pub struct TitlebarButton {
31    pub(crate) theme: Option<TitlebarButtonThemePartial>,
32    pub(crate) action: TitlebarAction,
33    pub(crate) on_press: Option<EventHandler<Event<PressEventData>>>,
34    key: DiffKey,
35}
36
37impl KeyExt for TitlebarButton {
38    fn write_key(&mut self) -> &mut DiffKey {
39        &mut self.key
40    }
41}
42
43impl TitlebarButton {
44    pub fn new(action: TitlebarAction) -> Self {
45        Self {
46            theme: None,
47            action,
48            on_press: None,
49            key: DiffKey::None,
50        }
51    }
52
53    pub fn on_press(mut self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
54        self.on_press = Some(on_press.into());
55        self
56    }
57}
58
59impl Component for TitlebarButton {
60    fn render(&self) -> impl IntoElement {
61        let mut hovering = use_state(|| false);
62        let theme = get_theme!(
63            &self.theme,
64            TitlebarButtonThemePreference,
65            "titlebar_button"
66        );
67
68        let icon_svg = match self.action {
69            TitlebarAction::Minimize => {
70                r#"<svg viewBox="0 0 12 12"><rect x="1" y="5" width="10" height="2" fill="currentColor"/></svg>"#
71            }
72            TitlebarAction::Maximize => {
73                r#"<svg viewBox="0 0 12 12"><rect x="2" y="2" width="8" height="8" fill="none" stroke="currentColor" stroke-width="1.5"/></svg>"#
74            }
75            TitlebarAction::Close => {
76                r#"<svg viewBox="0 0 12 12"><path d="M3 3l6 6M9 3l-6 6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>"#
77            }
78        };
79
80        let icon = svg(Bytes::from_static(icon_svg.as_bytes()))
81            .width(Size::px(12.))
82            .height(Size::px(12.));
83
84        let background = if hovering() {
85            theme.hover_background
86        } else {
87            theme.background
88        };
89
90        rect()
91            .width(theme.width)
92            .height(theme.height)
93            .background(background)
94            .center()
95            .on_pointer_enter(move |_| {
96                hovering.set(true);
97            })
98            .on_pointer_leave(move |_| {
99                hovering.set(false);
100            })
101            .map(self.on_press.clone(), |el, on_press| el.on_press(on_press))
102            .child(icon)
103    }
104
105    fn render_key(&self) -> DiffKey {
106        self.key.clone().or(self.default_key())
107    }
108}