freya_components/
titlebar.rs1use 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#[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}