use std::collections::HashMap;
use crate::types::{Rect, ScrollState};
use super::super::resize_drag::ResizeDrag;
pub const DEFAULT_SIDEBAR_WIDTH: f64 = 340.0;
pub const MIN_SIDEBAR_WIDTH: f64 = 280.0;
pub const MIN_SIDEBAR_HEIGHT: f64 = 60.0;
pub const DEFAULT_SIDEBAR_VIEWPORT_FRAC: f64 = 0.20;
pub const MAX_SIDEBAR_WIDTH: f64 = 4000.0;
#[derive(Debug, Clone)]
pub struct SidebarState {
pub is_collapsed: bool,
pub width: f64,
pub active_tab: Option<String>,
pub scroll_per_panel: HashMap<String, ScrollState>,
pub resize_drag: Option<ResizeDrag>,
pub header_action_hovered: Option<String>,
pub body_compress_factor: super::super::overflow::CompressFactor,
}
impl Default for SidebarState {
fn default() -> Self {
Self {
is_collapsed: false,
width: 0.0,
active_tab: None,
scroll_per_panel: HashMap::new(),
resize_drag: None,
header_action_hovered: None,
body_compress_factor: super::super::overflow::CompressFactor::one(),
}
}
}
impl SidebarState {
pub fn compress_factor(&self) -> super::super::overflow::CompressFactor {
self.body_compress_factor
}
pub fn ensure_sized(&mut self, viewport_w: f64, viewport_h: f64, is_horizontal_kind: bool) {
if self.width > 0.0 {
return;
}
let axis = if is_horizontal_kind { viewport_w } else { viewport_h };
let min = if is_horizontal_kind { MIN_SIDEBAR_WIDTH } else { MIN_SIDEBAR_HEIGHT };
self.width = (axis * DEFAULT_SIDEBAR_VIEWPORT_FRAC).max(min);
}
pub fn get_or_insert_scroll(&mut self, panel_id: &str) -> &mut ScrollState {
self.scroll_per_panel
.entry(panel_id.to_owned())
.or_default()
}
pub fn start_resize(
&mut self,
edge: crate::layout::ResizeEdge,
start_rect: Rect,
cursor: (f64, f64),
min_size: f64,
cap_size: f64,
) {
self.resize_drag = Some(ResizeDrag::begin(
edge, start_rect, cursor, (min_size, min_size), (cap_size, cap_size),
));
}
pub fn update_resize(&mut self, cursor: (f64, f64), is_horizontal_axis: bool) {
if let Some(drag) = self.resize_drag {
let r = drag.resolve(cursor);
let raw = if is_horizontal_axis { r.width } else { r.height };
self.width = raw.clamp(MIN_SIDEBAR_WIDTH, MAX_SIDEBAR_WIDTH);
}
}
pub fn end_resize(&mut self) {
self.resize_drag = None;
}
pub fn toggle_collapse(&mut self) {
self.is_collapsed = !self.is_collapsed;
}
pub fn set_active_tab(&mut self, id: impl Into<String>) {
self.active_tab = Some(id.into());
}
pub fn handle_wheel(&mut self, rect: crate::types::Rect, dy: f64, content_h: f64) {
const HEADER_H: f64 = 40.0;
const SCROLL_STEP: f64 = 30.0;
let viewport_h = (rect.height - HEADER_H).max(0.0);
let max = (content_h - viewport_h).max(0.0);
let scroll = self.get_or_insert_scroll("default");
scroll.offset = (scroll.offset - dy * SCROLL_STEP).clamp(0.0, max);
}
pub fn scrollbar_track_rect(sidebar_rect: crate::types::Rect) -> crate::types::Rect {
const HEADER_H: f64 = 40.0;
const TRACK_W: f64 = 8.0;
let viewport_h = (sidebar_rect.height - HEADER_H).max(0.0);
crate::types::Rect::new(
sidebar_rect.x + sidebar_rect.width - TRACK_W,
sidebar_rect.y + HEADER_H,
TRACK_W,
viewport_h,
)
}
}