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    Restore,
27}
28
29/// Titlebar button component.
30#[derive(PartialEq)]
31pub struct TitlebarButton {
32    pub(crate) theme: Option<TitlebarButtonThemePartial>,
33    pub(crate) action: TitlebarAction,
34    pub(crate) on_press: Option<EventHandler<Event<PressEventData>>>,
35    key: DiffKey,
36}
37
38impl KeyExt for TitlebarButton {
39    fn write_key(&mut self) -> &mut DiffKey {
40        &mut self.key
41    }
42}
43
44impl TitlebarButton {
45    pub fn new(action: TitlebarAction) -> Self {
46        Self {
47            theme: None,
48            action,
49            on_press: None,
50            key: DiffKey::None,
51        }
52    }
53
54    pub fn on_press(mut self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
55        self.on_press = Some(on_press.into());
56        self
57    }
58}
59
60impl Component for TitlebarButton {
61    fn render(&self) -> impl IntoElement {
62        let mut hovering = use_state(|| false);
63        let theme = get_theme!(
64            &self.theme,
65            TitlebarButtonThemePreference,
66            "titlebar_button"
67        );
68
69        let icon_svg = match self.action {
70            TitlebarAction::Minimize => {
71                r#"<svg viewBox="0 0 12 12"><rect x="1" y="5" width="10" height="2" fill="currentColor"/></svg>"#
72            }
73            TitlebarAction::Maximize => {
74                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>"#
75            }
76            TitlebarAction::Restore => {
77                r#"<svg viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg">
78                  <rect x="1.5" y="3.5" width="6.5" height="6.5" fill="none" stroke="currentColor" stroke-width="1.5"/>
79                  <path d="M4 3.5 V2 H10 V8 H8.5" fill="none" stroke="currentColor" stroke-width="1.5"/>
80                </svg>"#
81            }
82            TitlebarAction::Close => {
83                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>"#
84            }
85        };
86
87        let icon = svg(Bytes::from_static(icon_svg.as_bytes()))
88            .width(Size::px(12.))
89            .height(Size::px(12.));
90
91        let background = if hovering() {
92            theme.hover_background
93        } else {
94            theme.background
95        };
96
97        rect()
98            .width(theme.width)
99            .height(theme.height)
100            .background(background)
101            .center()
102            .on_pointer_enter(move |_| {
103                hovering.set(true);
104            })
105            .on_pointer_leave(move |_| {
106                hovering.set(false);
107            })
108            .map(self.on_press.clone(), |el, on_press| el.on_press(on_press))
109            .child(icon)
110    }
111
112    fn render_key(&self) -> DiffKey {
113        self.key.clone().or(self.default_key())
114    }
115}