use crate::{Rect, WindowId};
use super::view::{ColIndex, LineIndex};
pub const CLICK_THROUGH_THRESHOLD: f32 = 0.1;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct LayerId(pub u16);
impl LayerId {
#[must_use]
pub const fn new(id: u16) -> Self {
Self(id)
}
#[must_use]
pub const fn as_u16(self) -> u16 {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Zone {
Tiled,
Float,
Overlay,
}
impl Zone {
#[must_use]
pub const fn z_offset(self) -> u16 {
match self {
Self::Tiled => 0,
Self::Float => 10,
Self::Overlay => 50,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct ZOrder(u16);
impl ZOrder {
#[must_use]
pub const fn new(value: u16) -> Self {
Self(value)
}
#[must_use]
pub const fn as_u16(self) -> u16 {
self.0
}
#[must_use]
pub const fn layer_base(layer_id: LayerId) -> Self {
Self(layer_id.as_u16() * 100)
}
#[must_use]
pub const fn for_window(layer_base: Self, zone: Zone, index: u16) -> Self {
Self(layer_base.0 + zone.z_offset() + index)
}
#[must_use]
pub const fn offset(self, delta: u16) -> Self {
Self(self.0 + delta)
}
}
#[derive(Debug, Clone)]
pub struct Layer {
pub id: LayerId,
pub label: String,
pub z_base: ZOrder,
pub bounds: Rect,
pub opacity: f32,
pub visible: bool,
}
impl Layer {
#[must_use]
pub fn new(id: LayerId, label: impl Into<String>, z_base: ZOrder) -> Self {
Self {
id,
label: label.into(),
z_base,
bounds: Rect::default(),
opacity: 1.0,
visible: true,
}
}
#[must_use]
pub fn is_click_through(&self) -> bool {
self.opacity < CLICK_THROUGH_THRESHOLD
}
#[must_use]
pub const fn z_for(&self, zone: Zone, index: u16) -> ZOrder {
ZOrder::for_window(self.z_base, zone, index)
}
}
#[derive(Debug, Clone)]
pub struct WindowPlacement {
pub window_id: WindowId,
pub layer_id: LayerId,
pub zone: Zone,
pub bounds: Rect,
pub z_order: ZOrder,
pub visible: bool,
pub focusable: bool,
pub opacity: f32,
}
impl WindowPlacement {
#[must_use]
pub const fn new(
window_id: WindowId,
layer_id: LayerId,
zone: Zone,
bounds: Rect,
z_order: ZOrder,
) -> Self {
Self {
window_id,
layer_id,
zone,
bounds,
z_order,
visible: true,
focusable: true,
opacity: 1.0,
}
}
#[must_use]
pub fn is_click_through(&self) -> bool {
self.opacity < CLICK_THROUGH_THRESHOLD
}
}
#[derive(Debug, Clone, Copy)]
#[allow(clippy::doc_markdown)] pub enum Anchor {
Cursor {
window: WindowId,
line: LineIndex,
col: ColIndex,
},
Screen {
x: u16,
y: u16,
},
Center,
Below(WindowId),
}
#[derive(Debug, Clone)]
pub struct OverlayConstraints {
pub anchor: Anchor,
pub preferred_width: Option<u16>,
pub preferred_height: Option<u16>,
pub max_width: Option<u16>,
pub max_height: Option<u16>,
}
impl OverlayConstraints {
#[must_use]
pub const fn at_cursor(window: WindowId, line: LineIndex, col: ColIndex) -> Self {
Self {
anchor: Anchor::Cursor { window, line, col },
preferred_width: None,
preferred_height: None,
max_width: None,
max_height: None,
}
}
#[must_use]
pub const fn at_cursor_raw(window: WindowId, line: usize, col: usize) -> Self {
Self {
anchor: Anchor::Cursor {
window,
line: LineIndex::new(line),
col: ColIndex::new(col),
},
preferred_width: None,
preferred_height: None,
max_width: None,
max_height: None,
}
}
#[must_use]
pub const fn at_position(x: u16, y: u16) -> Self {
Self {
anchor: Anchor::Screen { x, y },
preferred_width: None,
preferred_height: None,
max_width: None,
max_height: None,
}
}
#[must_use]
pub const fn centered() -> Self {
Self {
anchor: Anchor::Center,
preferred_width: None,
preferred_height: None,
max_width: None,
max_height: None,
}
}
#[must_use]
pub const fn with_size(mut self, width: u16, height: u16) -> Self {
self.preferred_width = Some(width);
self.preferred_height = Some(height);
self
}
#[must_use]
pub const fn with_max_size(mut self, width: u16, height: u16) -> Self {
self.max_width = Some(width);
self.max_height = Some(height);
self
}
}
#[derive(Debug, Clone)]
pub struct LayerConfig {
pub label: String,
pub bounds: Option<Rect>,
pub opacity: f32,
}
impl LayerConfig {
#[must_use]
pub fn fullscreen(label: impl Into<String>) -> Self {
Self {
label: label.into(),
bounds: None,
opacity: 1.0,
}
}
#[must_use]
pub fn with_bounds(label: impl Into<String>, bounds: Rect) -> Self {
Self {
label: label.into(),
bounds: Some(bounds),
opacity: 1.0,
}
}
}
#[cfg(test)]
#[path = "layer_tests.rs"]
mod tests;