Skip to main content

panes/
panel.rs

1use crate::error::{ConstraintError, PaneError, TreeError};
2use crate::node::PanelId;
3use crate::validate::{check_f32_non_negative, float_invalid_to_constraint};
4
5/// Generates sequential, unique `PanelId` values.
6#[derive(Default)]
7pub struct PanelIdGenerator {
8    counter: u32,
9}
10
11impl PanelIdGenerator {
12    /// Create a generator starting at zero.
13    pub fn new() -> Self {
14        Self::default()
15    }
16
17    /// The number of IDs generated so far (one past the last issued ID).
18    pub fn high_water(&self) -> u32 {
19        self.counter
20    }
21
22    /// Produce the next unique `PanelId`.
23    ///
24    /// Returns an error if the counter reaches `u32::MAX`.
25    pub fn next_id(&mut self) -> Result<PanelId, PaneError> {
26        let id = PanelId::from_raw(self.counter);
27        self.counter = self
28            .counter
29            .checked_add(1)
30            .ok_or(PaneError::InvalidTree(TreeError::PanelIdExhausted))?;
31        Ok(id)
32    }
33}
34
35/// Spatial constraints for a panel within a layout.
36#[derive(Debug, Clone, Copy, PartialEq, Default)]
37#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
38pub struct Constraints {
39    /// Flex grow factor. Mutually exclusive with `fixed`.
40    pub grow: Option<f32>,
41    /// Fixed size in layout units. Mutually exclusive with `grow`.
42    pub fixed: Option<f32>,
43    /// Minimum size along the parent axis.
44    pub min: Option<f32>,
45    /// Maximum size along the parent axis.
46    pub max: Option<f32>,
47}
48
49impl Constraints {
50    /// Set the minimum size constraint.
51    pub fn min(mut self, value: f32) -> Self {
52        self.min = Some(value);
53        self
54    }
55
56    /// Set the maximum size constraint.
57    pub fn max(mut self, value: f32) -> Self {
58        self.max = Some(value);
59        self
60    }
61
62    /// Reject invalid constraint combinations.
63    pub fn validate(&self) -> Result<(), PaneError> {
64        Self::reject_bad_f32("grow", self.grow)?;
65        Self::reject_bad_f32("fixed", self.fixed)?;
66        Self::reject_bad_f32("min", self.min)?;
67        Self::reject_bad_f32("max", self.max)?;
68
69        match (self.grow, self.fixed, self.min, self.max) {
70            (Some(_), Some(_), _, _) => Err(PaneError::InvalidConstraint(
71                ConstraintError::GrowFixedExclusive,
72            )),
73            (_, _, Some(lo), Some(hi)) if lo > hi => {
74                Err(PaneError::InvalidConstraint(ConstraintError::MinExceedsMax))
75            }
76            _ => Ok(()),
77        }
78    }
79
80    fn reject_bad_f32(name: &'static str, value: Option<f32>) -> Result<(), PaneError> {
81        let Some(v) = value else { return Ok(()) };
82        check_f32_non_negative(v)
83            .map_err(|e| PaneError::InvalidConstraint(float_invalid_to_constraint(name, e)))
84    }
85}
86
87/// Create constraints with a grow factor.
88pub fn grow(value: f32) -> Constraints {
89    Constraints {
90        grow: Some(value),
91        ..Constraints::default()
92    }
93}
94
95/// Create constraints with a fixed size.
96pub fn fixed(value: f32) -> Constraints {
97    Constraints {
98        fixed: Some(value),
99        ..Constraints::default()
100    }
101}