1use std::{
2 any::{Any, TypeId},
3 collections::HashMap,
4 sync::Arc,
5};
6
7use crate::{
8 core::{Size, UiEventContext, UiRect},
9 platform::dpi::ScalePreference,
10};
11
12use super::WindowId;
13
14pub type WindowDragExclusion = fn(f32, f32) -> UiRect;
15
16#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
17pub enum WindowPosition {
18 #[default]
19 Centered,
20 AdjacentToOwner {
21 gap: i32,
22 },
23 NearCursor {
24 gap: i32,
25 },
26 Absolute {
27 x: i32,
28 y: i32,
29 },
30}
31
32#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
33pub enum WindowMode {
34 #[default]
35 Windowed,
36 Fullscreen,
37}
38
39#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
40pub enum ClosePolicy {
41 #[default]
42 Exit,
43 Hide,
44 Notify,
45}
46
47pub type WindowCloseHandler = fn(&mut UiEventContext);
48
49#[derive(Clone, Default)]
50struct WindowOptionExtensions {
51 values: HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
52}
53
54impl std::fmt::Debug for WindowOptionExtensions {
55 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 formatter
57 .debug_struct("WindowOptionExtensions")
58 .field("count", &self.values.len())
59 .finish()
60 }
61}
62
63#[derive(Clone, Debug)]
64pub struct WindowOptions {
65 pub id: WindowId,
66 pub owner: Option<WindowId>,
67 pub title: String,
68 pub visible: bool,
69 pub size: Size,
70 pub minimum_size: Option<Size>,
71 pub maximum_size: Option<Size>,
72 pub resizable: bool,
73 pub native_titlebar: bool,
74 pub position: WindowPosition,
75 pub transparent: bool,
76 pub corner_radius: i32,
77 pub topmost: bool,
78 pub hide_on_deactivate: bool,
79 pub background_memory_optimization: bool,
80 pub titlebar_drag_height: Option<f32>,
82 pub drag_exclusion: Option<WindowDragExclusion>,
84 pub scale_reference_size: Option<Size>,
85 pub scale_preference: ScalePreference,
86 pub mode: WindowMode,
87 pub close_policy: ClosePolicy,
88 pub close_handler: Option<WindowCloseHandler>,
89 extensions: WindowOptionExtensions,
90}
91
92impl WindowOptions {
93 pub fn new(id: impl Into<WindowId>) -> Self {
94 let id = id.into();
95 Self {
96 title: id.as_str().to_owned(),
97 id,
98 ..Self::default()
99 }
100 }
101
102 pub fn title(mut self, title: impl Into<String>) -> Self {
103 self.title = title.into();
104 self
105 }
106
107 pub fn visible(mut self, visible: bool) -> Self {
108 self.visible = visible;
109 self
110 }
111
112 pub fn owner(mut self, owner: impl Into<WindowId>) -> Self {
113 self.owner = Some(owner.into());
114 self
115 }
116
117 pub fn size(mut self, size: Size) -> Self {
118 self.size = size;
119 self
120 }
121
122 pub fn minimum_size(mut self, size: Size) -> Self {
123 self.minimum_size = Some(size);
124 self
125 }
126
127 pub fn maximum_size(mut self, size: Size) -> Self {
128 self.maximum_size = Some(size);
129 self
130 }
131
132 pub fn resizable(mut self, resizable: bool) -> Self {
133 self.resizable = resizable;
134 self
135 }
136
137 pub fn native_titlebar(mut self, enabled: bool) -> Self {
138 self.native_titlebar = enabled;
139 self
140 }
141
142 pub fn position(mut self, position: WindowPosition) -> Self {
143 self.position = position;
144 self
145 }
146
147 pub fn transparent(mut self, transparent: bool) -> Self {
148 self.transparent = transparent;
149 self
150 }
151
152 pub fn corner_radius(mut self, radius: i32) -> Self {
153 self.corner_radius = radius.max(0);
154 self
155 }
156
157 pub fn topmost(mut self, topmost: bool) -> Self {
158 self.topmost = topmost;
159 self
160 }
161
162 pub fn hide_on_deactivate(mut self, hide: bool) -> Self {
163 self.hide_on_deactivate = hide;
164 self
165 }
166
167 pub fn background_memory_optimization(mut self, enabled: bool) -> Self {
171 self.background_memory_optimization = enabled;
172 self
173 }
174
175 #[deprecated(
176 note = "geometry-based titlebar drag is a compatibility path; migrate immediately to Element::window_drag_region"
177 )]
178 pub fn titlebar_drag(mut self, height: f32, exclusion: Option<WindowDragExclusion>) -> Self {
179 self.titlebar_drag_height = Some(height.max(0.0));
180 self.drag_exclusion = exclusion;
181 self
182 }
183
184 pub fn scale_reference_size(mut self, size: Size) -> Self {
185 self.scale_reference_size = Some(size);
186 self
187 }
188
189 pub fn scale_preference(mut self, preference: ScalePreference) -> Self {
190 self.scale_preference = preference;
191 self
192 }
193
194 pub fn mode(mut self, mode: WindowMode) -> Self {
195 self.mode = mode;
196 self
197 }
198
199 pub fn close_policy(mut self, policy: ClosePolicy) -> Self {
200 self.close_policy = policy;
201 if policy != ClosePolicy::Notify {
202 self.close_handler = None;
203 }
204 self
205 }
206
207 pub fn on_close_requested(mut self, handler: WindowCloseHandler) -> Self {
208 self.close_policy = ClosePolicy::Notify;
209 self.close_handler = Some(handler);
210 self
211 }
212
213 pub fn with_platform_options<T>(mut self, options: T) -> Self
214 where
215 T: Any + Send + Sync,
216 {
217 self.extensions
218 .values
219 .insert(TypeId::of::<T>(), Arc::new(options));
220 self
221 }
222
223 pub fn platform_options<T>(&self) -> Option<&T>
224 where
225 T: Any + Send + Sync,
226 {
227 self.extensions
228 .values
229 .get(&TypeId::of::<T>())
230 .and_then(|options| options.downcast_ref())
231 }
232}
233
234impl Default for WindowOptions {
235 fn default() -> Self {
236 Self {
237 id: WindowId::new("main"),
238 owner: None,
239 title: "lgui".to_owned(),
240 visible: true,
241 size: Size::new(1024.0, 720.0),
242 minimum_size: None,
243 maximum_size: None,
244 resizable: true,
245 native_titlebar: true,
246 position: WindowPosition::Centered,
247 transparent: false,
248 corner_radius: 0,
249 topmost: false,
250 hide_on_deactivate: false,
251 background_memory_optimization: false,
252 titlebar_drag_height: None,
253 drag_exclusion: None,
254 scale_reference_size: None,
255 scale_preference: ScalePreference::Auto,
256 mode: WindowMode::Windowed,
257 close_policy: ClosePolicy::Exit,
258 close_handler: None,
259 extensions: WindowOptionExtensions::default(),
260 }
261 }
262}