Skip to main content

lgui_core/window/
options.rs

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    /// COMPATIBILITY: remove after consumers migrate to `Element::window_drag_region`.
81    pub titlebar_drag_height: Option<f32>,
82    /// COMPATIBILITY: remove after consumers migrate to `Element::window_drag_region`.
83    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    /// Releases reconstructible render state while hidden. When all top-level windows are
168    /// hidden, shared caches and the process working set are also trimmed. Component state,
169    /// effects and background tasks remain alive.
170    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}