kas_core/widgets/
decorations.rs1use super::{Label, MarkButton};
11use crate::event::CursorIcon;
12use crate::prelude::*;
13use crate::theme::MarkStyle;
14use crate::window::ResizeDirection;
15use kas_macros::impl_self;
16use std::fmt::Debug;
17
18#[impl_self]
19mod Border {
20 #[widget]
24 pub(crate) struct Border {
25 core: widget_core!(),
26 resizable: bool,
27 direction: ResizeDirection,
28 }
29
30 impl Self {
31 pub fn new(direction: ResizeDirection) -> Self {
32 Border {
33 core: Default::default(),
34 resizable: true,
35 direction,
36 }
37 }
38
39 pub fn set_resizable(&mut self, resizable: bool) {
40 self.resizable = resizable;
41 }
42 }
43
44 impl Layout for Self {
45 fn size_rules(&mut self, _: SizeCx, _axis: AxisInfo) -> SizeRules {
46 SizeRules::EMPTY
47 }
48
49 fn draw(&self, _: DrawCx) {}
50 }
51
52 impl Tile for Self {
53 fn role(&self, _: &mut dyn RoleCx) -> Role<'_> {
54 Role::Border
55 }
56 }
57
58 impl Events for Self {
59 type Data = ();
60
61 fn mouse_over_icon(&self) -> Option<CursorIcon> {
62 if self.resizable {
63 Some(self.direction.into())
64 } else {
65 None
66 }
67 }
68
69 fn handle_event(&mut self, cx: &mut EventCx, _: &Self::Data, event: Event) -> IsUsed {
70 match event {
71 Event::PressStart(_) => {
72 cx.drag_resize_window(self.direction);
73 Used
74 }
75 _ => Unused,
76 }
77 }
78 }
79}
80
81#[derive(Copy, Clone, Debug)]
82enum TitleBarButton {
83 Minimize,
84 Maximize,
85 Close,
86}
87
88#[impl_self]
89mod TitleBarButtons {
90 #[derive(Clone, Default)]
94 #[widget]
95 #[layout(row! [
96 MarkButton::new_msg(MarkStyle::Chevron(Direction::Down), "Minimize", TitleBarButton::Minimize),
97 MarkButton::new_msg(MarkStyle::Chevron(Direction::Up), "Maximize", TitleBarButton::Maximize),
98 MarkButton::new_msg(MarkStyle::X, "Close", TitleBarButton::Close),
99 ])]
100 pub struct TitleBarButtons {
101 core: widget_core!(),
102 }
103
104 impl Self {
105 #[inline]
107 pub fn new() -> Self {
108 TitleBarButtons {
109 core: Default::default(),
110 }
111 }
112 }
113
114 impl Events for Self {
115 type Data = ();
116
117 fn handle_messages(&mut self, cx: &mut EventCx, _: &Self::Data) {
118 if let Some(msg) = cx.try_pop() {
119 match msg {
120 TitleBarButton::Minimize => {
121 if let Some(w) = cx.winit_window() {
122 w.set_minimized(true);
123 }
124 }
125 TitleBarButton::Maximize => {
126 if let Some(w) = cx.winit_window() {
127 w.set_maximized(!w.is_maximized());
128 }
129 }
130 TitleBarButton::Close => cx.action(self, Action::CLOSE),
131 }
132 }
133 }
134 }
135}
136
137#[impl_self]
138mod TitleBar {
139 #[derive(Clone, Default)]
141 #[widget]
142 #[layout(row! [self.title.align(AlignHints::CENTER), self.buttons])]
143 pub struct TitleBar {
144 core: widget_core!(),
145 #[widget]
146 title: Label<String>,
147 #[widget]
148 buttons: TitleBarButtons,
149 }
150
151 impl Self {
152 #[inline]
154 pub fn new(title: impl ToString) -> Self {
155 TitleBar {
156 core: Default::default(),
157 title: Label::new(title.to_string()),
158 buttons: Default::default(),
159 }
160 }
161
162 pub fn title(&self) -> &str {
164 self.title.as_str()
165 }
166
167 pub fn set_title(&mut self, cx: &mut EventState, title: String) {
169 self.title.set_string(cx, title)
170 }
171 }
172
173 impl Tile for Self {
174 fn role(&self, cx: &mut dyn RoleCx) -> Role<'_> {
175 cx.set_label(self.title.id());
176 Role::TitleBar
177 }
178 }
179
180 impl Events for Self {
181 type Data = ();
182
183 fn handle_event(&mut self, cx: &mut EventCx, _: &Self::Data, event: Event) -> IsUsed {
184 match event {
185 Event::PressStart(_) => {
186 cx.drag_window();
187 Used
188 }
189 _ => Unused,
190 }
191 }
192 }
193}