use crate::docking::panels::DockPanel;
use crate::input::core::coordinator::InputCoordinator;
use crate::layout::LayoutManager;
#[derive(Debug, Clone, Default)]
pub struct ContextMenuState {
pub is_open: bool,
pub x: f64,
pub y: f64,
pub target_id: Option<String>,
pub hovered_index: Option<usize>,
pub primed_index: Option<usize>,
}
impl ContextMenuState {
pub fn open_smart(
&mut self,
x: f64,
y: f64,
screen_w: f64,
screen_h: f64,
menu_w: f64,
menu_h: f64,
target_id: Option<String>,
) {
let clamped_x = if x + menu_w > screen_w {
(x - menu_w).max(0.0)
} else {
x
};
let clamped_y = if y + menu_h > screen_h {
(y - menu_h).max(0.0)
} else {
y
};
self.is_open = true;
self.x = clamped_x;
self.y = clamped_y;
self.target_id = target_id;
self.hovered_index = None;
self.primed_index = None;
}
pub fn open_raw(&mut self, x: f64, y: f64, target_id: Option<String>) {
self.is_open = true;
self.x = x;
self.y = y;
self.target_id = target_id;
self.hovered_index = None;
self.primed_index = None;
}
pub fn close(&mut self) {
self.is_open = false;
self.hovered_index = None;
self.primed_index = None;
}
pub fn is_open(&self) -> bool {
self.is_open
}
pub fn set_hovered(&mut self, index: Option<usize>) {
self.hovered_index = index;
}
pub fn set_primed(&mut self, index: Option<usize>) {
self.primed_index = index;
}
pub fn sync_hover_from(&mut self, coord: &InputCoordinator, widget_id_prefix: &str) {
if !self.is_open {
return;
}
let hovered = coord.hovered_widget().map(|id| id.0.clone());
self.apply_hover(hovered, widget_id_prefix);
}
pub fn sync_hover_from_layout<P: DockPanel>(
&mut self,
layout: &LayoutManager<P>,
widget_id_prefix: &str,
) {
if !self.is_open {
return;
}
let hovered = layout.hovered_widget().map(|id| id.0.clone());
self.apply_hover(hovered, widget_id_prefix);
}
fn apply_hover(&mut self, hovered: Option<String>, widget_id_prefix: &str) {
self.hovered_index = hovered
.as_deref()
.filter(|s| s.starts_with(widget_id_prefix))
.and_then(|s| s[widget_id_prefix.len()..].parse::<usize>().ok());
}
}