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