use crate::input::core::coordinator::InputCoordinator;
use crate::layout::docking::DockPanel;
use crate::layout::LayoutManager;
use crate::ui::widgets::atomic::tooltip::TooltipState;
use crate::ui::widgets::composite::context_menu::ContextMenuState;
use super::types::{ChromeColors, ChromeHit};
#[derive(Debug, Clone, Default)]
pub struct TabState {
pub id: String,
pub hovered: bool,
pub pressed: bool,
pub close_hovered: bool,
}
impl TabState {
pub fn new(id: impl Into<String>) -> Self {
Self {
id: id.into(),
hovered: false,
pressed: false,
close_hovered: false,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct ChromeState {
pub hovered: ChromeHit,
pub is_maximized: bool,
pub dragging_window: bool,
pub tabs_state: Vec<TabState>,
pub active_tab_id: Option<String>,
pub tab_widths: Vec<f64>,
pub tooltip: TooltipState,
pub context_menu: ContextMenuState,
pub colors: ChromeColors,
pub chrome_button: Option<super::types::ChromeButton>,
pub title: String,
}
impl ChromeState {
pub fn new() -> Self {
Self::default()
}
pub fn sync_tabs(&mut self, ids: &[&str]) {
self.tabs_state.retain(|ts| ids.contains(&ts.id.as_str()));
for &id in ids {
if !self.tabs_state.iter().any(|ts| ts.id == id) {
self.tabs_state.push(TabState::new(id));
}
}
let ordered: Vec<TabState> = ids
.iter()
.filter_map(|&id| {
self.tabs_state.iter().find(|ts| ts.id == id).cloned()
})
.collect();
self.tabs_state = ordered;
}
pub fn update_tab_widths(
&mut self,
text_widths: &[f64],
tab_padding_h: f64,
tab_close_size: f64,
) {
self.tab_widths = text_widths
.iter()
.map(|&tw| tab_padding_h + tw + tab_close_size + tab_padding_h)
.collect();
}
pub fn clear_hover(&mut self) {
self.hovered = ChromeHit::None;
self.chrome_button = None;
for ts in &mut self.tabs_state {
ts.hovered = false;
ts.pressed = false;
ts.close_hovered = false;
}
}
pub fn sync_hover_from_coordinator(&mut self, coord: &InputCoordinator, chrome_id: &str) {
let hovered = coord.hovered_widget().map(|w| w.0.clone());
self.apply_hover_from_id(hovered, chrome_id);
}
pub fn sync_hover_from_layout<P: DockPanel>(&mut self, layout: &LayoutManager<P>, chrome_id: &str) {
let hovered = layout.hovered_widget().map(|w| w.0.clone());
self.apply_hover_from_id(hovered, chrome_id);
}
fn apply_hover_from_id(&mut self, hovered: Option<String>, chrome_id: &str) {
use super::types::ChromeHit;
let tab_prefix = format!("{chrome_id}:tab:");
let close_prefix = format!("{chrome_id}:tab_close:");
for (i, ts) in self.tabs_state.iter_mut().enumerate() {
let idx_str = i.to_string();
ts.hovered = hovered.as_deref().map(|h| h == format!("{}{}", tab_prefix, idx_str)).unwrap_or(false);
ts.close_hovered = hovered.as_deref().map(|h| h == format!("{}{}", close_prefix, idx_str)).unwrap_or(false);
}
self.hovered = match hovered.as_deref() {
Some(h) if h == format!("{chrome_id}:new_win") => ChromeHit::NewWindowBtn,
Some(h) if h == format!("{chrome_id}:menu") => ChromeHit::Menu,
Some(h) if h == format!("{chrome_id}:close_win") => ChromeHit::CloseWindowBtn,
Some(h) if h == format!("{chrome_id}:min") => ChromeHit::MinBtn,
Some(h) if h == format!("{chrome_id}:max") => ChromeHit::MaxBtn,
Some(h) if h == format!("{chrome_id}:close") => ChromeHit::CloseBtn,
_ => ChromeHit::None,
};
}
}