use crate::tree::{LayoutRect, NodeId};
use astrelis_core::math::Vec2;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum SplitDirection {
#[default]
Horizontal,
Vertical,
}
impl SplitDirection {
pub fn perpendicular(&self) -> Self {
match self {
SplitDirection::Horizontal => SplitDirection::Vertical,
SplitDirection::Vertical => SplitDirection::Horizontal,
}
}
pub fn is_horizontal(&self) -> bool {
matches!(self, SplitDirection::Horizontal)
}
pub fn is_vertical(&self) -> bool {
matches!(self, SplitDirection::Vertical)
}
}
pub const DEFAULT_MIN_PANEL_SIZE: f32 = 50.0;
#[derive(Debug, Clone, Copy)]
pub struct PanelConstraints {
pub min_size: f32,
pub max_size: Option<f32>,
}
impl Default for PanelConstraints {
fn default() -> Self {
Self {
min_size: DEFAULT_MIN_PANEL_SIZE,
max_size: None,
}
}
}
impl PanelConstraints {
pub fn min(min_size: f32) -> Self {
Self {
min_size,
max_size: None,
}
}
pub fn min_max(min_size: f32, max_size: f32) -> Self {
Self {
min_size,
max_size: Some(max_size),
}
}
pub fn clamp(&self, size: f32) -> f32 {
let mut result = size.max(self.min_size);
if let Some(max) = self.max_size {
result = result.min(max);
}
result
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DockZone {
Left,
Right,
Top,
Bottom,
Center,
}
impl DockZone {
pub fn split_direction(&self) -> Option<SplitDirection> {
match self {
DockZone::Left | DockZone::Right => Some(SplitDirection::Horizontal),
DockZone::Top | DockZone::Bottom => Some(SplitDirection::Vertical),
DockZone::Center => None,
}
}
pub fn is_before(&self) -> bool {
matches!(self, DockZone::Left | DockZone::Top)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DragType {
SplitterResize {
splitter_node: NodeId,
direction: SplitDirection,
},
PanelMove {
panel_node: NodeId,
},
TabDrag {
tabs_node: NodeId,
tab_index: usize,
},
TabGroupDrag {
tabs_node: NodeId,
},
}
pub const DRAG_THRESHOLD: f32 = 5.0;
#[derive(Debug, Clone)]
pub struct DragState {
pub drag_type: DragType,
pub start_pos: Vec2,
pub current_pos: Vec2,
pub is_active: bool,
pub original_value: f32,
}
impl DragState {
pub fn new(drag_type: DragType, start_pos: Vec2, original_value: f32) -> Self {
Self {
drag_type,
start_pos,
current_pos: start_pos,
is_active: false,
original_value,
}
}
pub fn update(&mut self, pos: Vec2) {
self.current_pos = pos;
if !self.is_active {
let delta = pos - self.start_pos;
if delta.length() >= DRAG_THRESHOLD {
self.is_active = true;
}
}
}
pub fn delta(&self) -> Vec2 {
self.current_pos - self.start_pos
}
}
#[derive(Debug, Clone, Copy)]
pub struct SeparatorHit {
pub splitter_node: NodeId,
pub direction: SplitDirection,
pub current_ratio: f32,
}
pub fn calculate_separator_bounds(
layout: &LayoutRect,
direction: SplitDirection,
split_ratio: f32,
separator_size: f32,
) -> LayoutRect {
match direction {
SplitDirection::Horizontal => {
let split_x = layout.width * split_ratio;
let sep_x = split_x - separator_size / 2.0;
LayoutRect {
x: layout.x + sep_x,
y: layout.y,
width: separator_size,
height: layout.height,
}
}
SplitDirection::Vertical => {
let split_y = layout.height * split_ratio;
let sep_y = split_y - separator_size / 2.0;
LayoutRect {
x: layout.x,
y: layout.y + sep_y,
width: layout.width,
height: separator_size,
}
}
}
}
pub fn calculate_panel_layouts(
layout: &LayoutRect,
direction: SplitDirection,
split_ratio: f32,
separator_size: f32,
) -> (LayoutRect, LayoutRect) {
let half_sep = separator_size / 2.0;
match direction {
SplitDirection::Horizontal => {
let split_x = layout.width * split_ratio;
let first = LayoutRect {
x: layout.x,
y: layout.y,
width: (split_x - half_sep).max(0.0),
height: layout.height,
};
let second = LayoutRect {
x: layout.x + split_x + half_sep,
y: layout.y,
width: (layout.width - split_x - half_sep).max(0.0),
height: layout.height,
};
(first, second)
}
SplitDirection::Vertical => {
let split_y = layout.height * split_ratio;
let first = LayoutRect {
x: layout.x,
y: layout.y,
width: layout.width,
height: (split_y - half_sep).max(0.0),
};
let second = LayoutRect {
x: layout.x,
y: layout.y + split_y + half_sep,
width: layout.width,
height: (layout.height - split_y - half_sep).max(0.0),
};
(first, second)
}
}
}