freya_components/
titlebar.rs

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