Skip to main content

dampen_dev/persistence/
window_state.rs

1use crate::persistence::error::PersistenceError;
2use serde::{Deserialize, Serialize};
3
4/// Persisted window state for Dampen applications.
5#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6pub struct WindowState {
7    /// Window width in logical pixels
8    pub width: u32,
9
10    /// Window height in logical pixels
11    pub height: u32,
12
13    /// Window X position (None if platform doesn't support absolute positioning)
14    ///
15    /// On Linux with Wayland, absolute window positioning is generally not supported
16    /// by compositors. In this case, `x` and `y` will be `None`, and the window
17    /// position will be determined by the compositor.
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub x: Option<i32>,
20
21    /// Window Y position (None if platform doesn't support absolute positioning)
22    ///
23    /// On Linux with Wayland, absolute window positioning is generally not supported
24    /// by compositors. In this case, `x` and `y` will be `None`, and the window
25    /// position will be determined by the compositor.
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub y: Option<i32>,
28
29    /// Whether the window was maximized.
30    ///
31    /// If true, the application should initialize the window in a maximized state,
32    /// regardless of the saved width/height/position.
33    pub maximized: bool,
34}
35
36impl WindowState {
37    /// Create a default WindowState with the given dimensions.
38    pub fn with_defaults(width: u32, height: u32) -> Self {
39        Self {
40            width,
41            height,
42            x: None,
43            y: None,
44            maximized: false,
45        }
46    }
47
48    /// Convert to Iced Size for use with `.window_size()`.
49    pub fn size(&self) -> iced::Size {
50        iced::Size::new(self.width as f32, self.height as f32)
51    }
52
53    /// Convert to Iced Point for use with `.position()`.
54    pub fn position(&self) -> Option<iced::Point> {
55        match (self.x, self.y) {
56            (Some(x), Some(y)) => Some(iced::Point::new(x as f32, y as f32)),
57            _ => None,
58        }
59    }
60
61    /// Validate the state against reasonable bounds
62    pub fn validate(&self) -> Result<(), PersistenceError> {
63        if self.width < 100 || self.height < 100 {
64            return Err(PersistenceError::InvalidState {
65                reason: format!(
66                    "Window dimensions {}x{} are below minimum 100x100",
67                    self.width, self.height
68                ),
69            });
70        }
71        if self.width > 16384 || self.height > 16384 {
72            return Err(PersistenceError::InvalidState {
73                reason: format!(
74                    "Window dimensions {}x{} exceed maximum 16384x16384",
75                    self.width, self.height
76                ),
77            });
78        }
79        Ok(())
80    }
81}