use std::collections::HashMap;
use crate::layout::docking::{PanelRect, DockPanel};
use super::dock_state::DockState;
use super::window::{WindowKey, WindowProvider};
use crate::core::types::Rect;
use crate::input::core::coordinator::LayerId;
use crate::input::WidgetKind;
use crate::types::WidgetId;
use crate::ui::widgets::composite::modal::state::ModalState;
use crate::ui::widgets::composite::popup::state::PopupState;
use crate::ui::widgets::composite::dropdown::state::DropdownState;
use crate::ui::widgets::composite::toolbar::state::ToolbarState;
use crate::ui::widgets::composite::sidebar::state::SidebarState;
use crate::ui::widgets::composite::context_menu::state::ContextMenuState;
use crate::ui::widgets::composite::chrome::state::ChromeState;
use crate::app_context::ContextManager;
use super::chrome_slot::ChromeSlot;
use super::edge_panels::EdgePanels;
use super::handles::{
ContextMenuHandle, DropdownHandle, ModalHandle, OverlayHandle,
PopupHandle, SidebarHandle, ToolbarHandle,
};
use super::overlay_stack::{OverlayStack, OverlayEntry};
use super::tree::{LayoutNode as TreeLayoutNode, LayoutNodeId, LayoutTree};
use super::z_layers::ZLayerTable;
use super::types::{OverlayKind, LayoutSolved};
use super::solve::solve_layout;
use super::styles::StyleManager;
use super::branch::{WindowBranch, WindowSlot};
use super::registry::{
CompositeKind, CompositeRegistration, DismissFrame,
layer_for_widget_kind,
};
fn panel_rect_from_rect(r: Rect) -> PanelRect {
PanelRect::new(r.x as f32, r.y as f32, r.width as f32, r.height as f32)
}
fn panel_rect_to_rect(pr: PanelRect) -> Rect {
Rect::new(pr.x as f64, pr.y as f64, pr.width as f64, pr.height as f64)
}
pub struct LayoutManager<P: DockPanel> {
pub(crate) windows: std::collections::HashMap<
crate::layout::window::WindowKey,
WindowSlot<P>,
>,
pub(crate) current_window: Option<crate::layout::window::WindowKey>,
z_layers: ZLayerTable,
pub(crate) frame_time_ms: f64,
styles: StyleManager,
pub(crate) sync_registry: super::sync::SyncRegistry,
pub(crate) agent_log: super::agent::AgentLog,
pub(crate) blackbox_agents: std::collections::HashMap<
String,
std::sync::Arc<std::sync::Mutex<dyn super::agent::BlackboxAgentSurface>>,
>,
}
impl<P: DockPanel> LayoutManager<P> {
pub fn new() -> Self {
Self {
windows: HashMap::new(),
current_window: None,
z_layers: ZLayerTable::default(),
frame_time_ms: 0.0,
styles: StyleManager::default(),
sync_registry: super::sync::SyncRegistry::defaults(),
agent_log: super::agent::AgentLog::default(),
blackbox_agents: std::collections::HashMap::new(),
}
}
pub fn register_blackbox_agent(
&mut self,
slot_id: impl Into<String>,
surface: std::sync::Arc<std::sync::Mutex<dyn super::agent::BlackboxAgentSurface>>,
) {
let id = slot_id.into();
let existed = self.blackbox_agents.contains_key(&id);
self.blackbox_agents.insert(id.clone(), surface);
if !existed {
let win = self.current_window.as_ref().map(|k| k.as_str().to_owned());
self.agent_log.push(
self.frame_time_ms,
win,
"lm.blackbox.register",
serde_json::json!({ "slot_id": id }),
);
}
}
pub fn unregister_blackbox_agent(&mut self, slot_id: &str) {
if self.blackbox_agents.remove(slot_id).is_some() {
let win = self.current_window.as_ref().map(|k| k.as_str().to_owned());
self.agent_log.push(
self.frame_time_ms,
win,
"lm.blackbox.unregister",
serde_json::json!({ "slot_id": slot_id }),
);
}
}
pub fn blackbox_slots(&self) -> Vec<String> {
let mut v: Vec<String> = self.blackbox_agents.keys().cloned().collect();
v.sort();
v
}
pub fn find_blackbox_agent(
&self,
slot_id: &str,
) -> Option<std::sync::Arc<std::sync::Mutex<dyn super::agent::BlackboxAgentSurface>>> {
self.blackbox_agents.get(slot_id).cloned()
}
pub fn agent_log(&self) -> &super::agent::AgentLog {
&self.agent_log
}
pub fn agent_log_push(
&mut self,
category: impl Into<String>,
payload: serde_json::Value,
) -> u64 {
let ts = self.frame_time_ms;
let win = self.current_window.as_ref().map(|k| k.as_str().to_owned());
self.agent_log.push(ts, win, category, payload)
}
pub fn agent_log_note(&mut self, message: impl Into<String>) -> u64 {
let payload = serde_json::json!({ "message": message.into() });
self.agent_log_push("note", payload)
}
pub fn apply_style_preset<Pr: super::styles::Preset + ?Sized>(
&mut self,
preset: &Pr,
name: impl Into<String>,
) {
let name_string = name.into();
self.styles.apply_named(preset, name_string.clone());
self.agent_log_push(
"lm.style.preset",
serde_json::json!({ "name": name_string }),
);
}
pub fn sync_registry(&self) -> &super::sync::SyncRegistry {
&self.sync_registry
}
pub fn sync_registry_mut(&mut self) -> &mut super::sync::SyncRegistry {
&mut self.sync_registry
}
pub fn set_current_window(&mut self, key: crate::layout::window::WindowKey) {
self.current_window = Some(key);
}
pub fn current_window(&self) -> Option<&crate::layout::window::WindowKey> {
self.current_window.as_ref()
}
fn cur_branch(&self) -> &WindowBranch<P> {
let key = self.current_window.as_ref()
.expect("LayoutManager: no current_window — platform layer must call set_current_window");
self.windows.get(key)
.unwrap_or_else(|| panic!("LayoutManager: current_window {:?} not attached", key))
}
fn cur_branch_mut(&mut self) -> &mut WindowBranch<P> {
let key = self.current_window.clone()
.expect("LayoutManager: no current_window — platform layer must call set_current_window");
self.windows.get_mut(&key)
.unwrap_or_else(|| panic!("LayoutManager: current_window not attached"))
}
pub fn chrome(&self) -> &ChromeSlot {
&self.cur_branch().chrome
}
pub fn chrome_mut(&mut self) -> &mut ChromeSlot {
&mut self.cur_branch_mut().chrome
}
pub fn edges(&self) -> &EdgePanels {
&self.cur_branch().edges
}
pub fn edges_mut(&mut self) -> &mut EdgePanels {
&mut self.cur_branch_mut().edges
}
pub fn overlays(&self) -> &OverlayStack {
&self.cur_branch().overlays
}
pub fn overlays_mut(&mut self) -> &mut OverlayStack {
&mut self.cur_branch_mut().overlays
}
pub fn z_layers(&self) -> &ZLayerTable {
&self.z_layers
}
pub fn z_layers_mut(&mut self) -> &mut ZLayerTable {
&mut self.z_layers
}
pub fn ctx(&self) -> &ContextManager {
&self.cur_branch().ctx
}
pub fn ctx_mut(&mut self) -> &mut ContextManager {
&mut self.cur_branch_mut().ctx
}
pub fn dispatcher(&self) -> &super::ClickDispatcher {
&self.cur_branch().dispatcher
}
pub fn sidebar_default_size(&self, is_horizontal_kind: bool, frac: f64) -> Option<f64> {
let win = self.cur_branch().last_window?;
let axis = if is_horizontal_kind { win.width } else { win.height };
Some(axis * frac)
}
pub fn dispatcher_mut(&mut self) -> &mut super::ClickDispatcher {
&mut self.cur_branch_mut().dispatcher
}
pub fn dispatch_click(&mut self, x: f64, y: f64) -> Option<super::DispatchEvent> {
let b = self.cur_branch_mut();
let clicked = b.ctx.input.process_click(x, y)?;
Some(
b.dispatcher
.dispatch(&clicked)
.unwrap_or(super::DispatchEvent::Unhandled(clicked)),
)
}
pub fn dispatch_widget(&self, id: &crate::types::WidgetId) -> super::DispatchEvent {
self.cur_branch().dispatcher
.dispatch(id)
.unwrap_or_else(|| super::DispatchEvent::Unhandled(id.clone()))
}
pub fn dispatch_widget_logged(&mut self, id: &crate::types::WidgetId) -> super::DispatchEvent {
let event = self.cur_branch().dispatcher
.dispatch(id)
.unwrap_or_else(|| super::DispatchEvent::Unhandled(id.clone()));
let window = self.current_window.as_ref().map(|k| k.as_str().to_owned());
let ts = self.frame_time_ms;
self.agent_log.push(
ts,
window,
"lm.dispatch",
serde_json::json!({
"widget_id": id.as_str(),
"event": format!("{:?}", event),
}),
);
event
}
pub fn dispatcher_begin_frame(&mut self) {
let b = self.cur_branch_mut();
b.dispatcher.clear();
b.dismiss_frames.clear();
b.composite_registry.clear();
}
pub fn add_modal(&mut self, id: &str) -> ModalHandle {
let widget_id = WidgetId(id.to_owned());
self.cur_branch_mut().modals.entry(widget_id.clone()).or_default();
ModalHandle { id: widget_id }
}
pub fn add_popup(&mut self, id: &str) -> PopupHandle {
let widget_id = WidgetId(id.to_owned());
self.cur_branch_mut().popups.entry(widget_id.clone()).or_default();
PopupHandle { id: widget_id }
}
pub fn add_dropdown(&mut self, id: &str) -> DropdownHandle {
let widget_id = WidgetId(id.to_owned());
self.cur_branch_mut().dropdowns.entry(widget_id.clone()).or_default();
DropdownHandle { id: widget_id }
}
pub fn add_toolbar(&mut self, id: &str) -> ToolbarHandle {
let widget_id = WidgetId(id.to_owned());
self.cur_branch_mut().toolbars.entry(widget_id.clone()).or_default();
ToolbarHandle { id: widget_id }
}
pub fn add_sidebar(&mut self, id: &str) -> SidebarHandle {
let widget_id = WidgetId(id.to_owned());
self.cur_branch_mut().sidebars.entry(widget_id.clone()).or_default();
SidebarHandle { id: widget_id }
}
pub fn add_context_menu(&mut self, id: &str) -> ContextMenuHandle {
let widget_id = WidgetId(id.to_owned());
self.cur_branch_mut().context_menus.entry(widget_id.clone()).or_default();
ContextMenuHandle { id: widget_id }
}
pub fn modals_map_mut(&mut self) -> &mut HashMap<WidgetId, ModalState> { &mut self.cur_branch_mut().modals }
pub fn popups_map_mut(&mut self) -> &mut HashMap<WidgetId, PopupState> { &mut self.cur_branch_mut().popups }
pub fn dropdowns_map_mut(&mut self) -> &mut HashMap<WidgetId, DropdownState> { &mut self.cur_branch_mut().dropdowns }
pub fn toolbars_map_mut(&mut self) -> &mut HashMap<WidgetId, ToolbarState> { &mut self.cur_branch_mut().toolbars }
pub fn sidebars_map_mut(&mut self) -> &mut HashMap<WidgetId, SidebarState> { &mut self.cur_branch_mut().sidebars }
pub fn context_menus_map_mut(&mut self) -> &mut HashMap<WidgetId, ContextMenuState> { &mut self.cur_branch_mut().context_menus }
pub fn chrome_widget_state_mut(&mut self) -> &mut ChromeState { &mut self.cur_branch_mut().chrome_widget_state }
pub fn modal(&self, h: &ModalHandle) -> &ModalState {
self.cur_branch().modals.get(&h.id)
.expect("modal handle invalidated — state dropped from registry")
}
pub fn modal_mut(&mut self, h: &ModalHandle) -> &mut ModalState {
self.cur_branch_mut().modals.get_mut(&h.id)
.expect("modal handle invalidated — state dropped from registry")
}
pub fn popup(&self, h: &PopupHandle) -> &PopupState {
self.cur_branch().popups.get(&h.id)
.expect("popup handle invalidated — state dropped from registry")
}
pub fn popup_mut(&mut self, h: &PopupHandle) -> &mut PopupState {
self.cur_branch_mut().popups.get_mut(&h.id)
.expect("popup handle invalidated — state dropped from registry")
}
pub fn dropdown(&self, h: &DropdownHandle) -> &DropdownState {
self.cur_branch().dropdowns.get(&h.id)
.expect("dropdown handle invalidated — state dropped from registry")
}
pub fn dropdown_mut(&mut self, h: &DropdownHandle) -> &mut DropdownState {
self.cur_branch_mut().dropdowns.get_mut(&h.id)
.expect("dropdown handle invalidated — state dropped from registry")
}
pub fn toolbar(&self, h: &ToolbarHandle) -> &ToolbarState {
self.cur_branch().toolbars.get(&h.id)
.expect("toolbar handle invalidated — state dropped from registry")
}
pub fn toolbar_mut(&mut self, h: &ToolbarHandle) -> &mut ToolbarState {
self.cur_branch_mut().toolbars.get_mut(&h.id)
.expect("toolbar handle invalidated — state dropped from registry")
}
pub fn frame_time_ms(&self) -> f64 {
self.frame_time_ms
}
pub fn set_frame_time_ms(&mut self, t: f64) {
self.frame_time_ms = t;
}
pub fn cursor_pos(&self) -> Option<(f64, f64)> {
self.cur_branch().ctx.input.pointer_pos()
}
pub fn hovered_widget(&self) -> Option<&crate::types::WidgetId> {
self.cur_branch().last_hovered.as_ref()
}
pub fn was_pressed(&self, id: &WidgetId) -> bool {
self.cur_branch().last_pressed.as_ref() == Some(id)
}
pub fn last_pressed_widget(&self) -> Option<&WidgetId> {
self.cur_branch().last_pressed.as_ref()
}
pub fn pointer_pos(&self) -> Option<(f64, f64)> {
self.cur_branch().last_pointer_pos
}
pub fn scroll_delta(&self) -> (f64, f64) {
self.cur_branch().last_scroll
}
pub fn inputs_begin_frame(&mut self) {
let b = self.cur_branch_mut();
b.last_click = None;
b.last_right_click = None;
b.last_pressed = None;
b.last_scroll = (0.0, 0.0);
}
pub fn begin_frame(&mut self, time_ms: f64, viewport: crate::core::types::Rect) {
self.cur_branch_mut().ctx.begin_frame_widgets_only(time_ms / 1000.0, viewport);
}
pub fn end_frame_inputs(&mut self) {
self.inputs_begin_frame();
}
pub fn was_clicked(&self, id: &WidgetId) -> bool {
self.cur_branch().last_click.as_ref().map_or(false, |(c, _)| c == id)
}
pub fn dock_leaves(&self) -> impl Iterator<Item = (crate::layout::docking::LeafId, Rect)> + '_ {
self.cur_branch().dock.panel_rects().iter().map(|(&id, &pr)| {
(id, panel_rect_to_rect(pr))
}).collect::<Vec<_>>().into_iter()
}
pub fn sidebar(&self, h: &SidebarHandle) -> &SidebarState {
self.cur_branch().sidebars.get(&h.id)
.expect("sidebar handle invalidated — state dropped from registry")
}
pub fn sidebar_mut(&mut self, h: &SidebarHandle) -> &mut SidebarState {
self.cur_branch_mut().sidebars.get_mut(&h.id)
.expect("sidebar handle invalidated — state dropped from registry")
}
pub fn context_menu(&self, h: &ContextMenuHandle) -> &ContextMenuState {
self.cur_branch().context_menus.get(&h.id)
.expect("context_menu handle invalidated — state dropped from registry")
}
pub fn context_menu_mut(&mut self, h: &ContextMenuHandle) -> &mut ContextMenuState {
self.cur_branch_mut().context_menus.get_mut(&h.id)
.expect("context_menu handle invalidated — state dropped from registry")
}
pub fn chrome_state(&self) -> &ChromeState {
&self.cur_branch().chrome_widget_state
}
pub fn chrome_state_mut(&mut self) -> &mut ChromeState {
&mut self.cur_branch_mut().chrome_widget_state
}
pub fn styles(&self) -> &StyleManager {
&self.styles
}
pub fn styles_mut(&mut self) -> &mut StyleManager {
&mut self.styles
}
pub fn push_composite_registration(&mut self, reg: CompositeRegistration) {
self.cur_branch_mut().composite_registry.push(reg);
}
pub fn consume_event(
&mut self,
event: super::DispatchEvent,
cursor: (f64, f64),
viewport: (f64, f64),
) -> Option<super::DispatchEvent> {
use super::DispatchEvent;
use crate::ui::widgets::composite::modal::input as modal_input;
use crate::ui::widgets::composite::popup::input as popup_input;
use crate::ui::widgets::composite::dropdown::input as dropdown_input;
use crate::ui::widgets::composite::toolbar::input as toolbar_input;
use crate::ui::widgets::composite::sidebar::input as sidebar_input;
let registry: Vec<CompositeRegistration> = self.cur_branch().composite_registry.clone();
let mut opt_ev: Option<DispatchEvent> = Some(event);
for priority in [
CompositeKind::Modal,
CompositeKind::Popup,
CompositeKind::Dropdown,
CompositeKind::ContextMenu,
CompositeKind::Toolbar,
CompositeKind::Sidebar,
] {
for reg in registry.iter().filter(|r| r.kind == priority) {
let ev = match opt_ev.take() {
Some(e) => e,
None => return None,
};
opt_ev = match priority {
CompositeKind::Modal => {
let mut st = self.cur_branch_mut().modals.remove(®.widget_id).unwrap_or_default();
let result = modal_input::consume_event(
ev, &mut st, ®.widget_id,
modal_input::ConsumeEventCtx { cursor, frame_rect: reg.frame_rect, viewport },
);
self.cur_branch_mut().modals.insert(reg.widget_id.clone(), st);
result
}
CompositeKind::Popup => {
let mut st = self.cur_branch_mut().popups.remove(®.widget_id).unwrap_or_default();
let result = popup_input::consume_event(
ev, &mut st, ®.widget_id,
popup_input::ConsumeEventCtx { cursor, frame_rect: reg.frame_rect, viewport },
);
self.cur_branch_mut().popups.insert(reg.widget_id.clone(), st);
result
}
CompositeKind::Dropdown => {
let mut st = self.cur_branch_mut().dropdowns.remove(®.widget_id).unwrap_or_default();
let result = dropdown_input::consume_event(
ev, &mut st, ®.widget_id,
dropdown_input::ConsumeEventCtx { cursor, frame_rect: reg.frame_rect, viewport },
);
self.cur_branch_mut().dropdowns.insert(reg.widget_id.clone(), st);
result
}
CompositeKind::ContextMenu => Some(ev),
CompositeKind::Toolbar => {
let mut st = self.cur_branch_mut().toolbars.remove(®.widget_id).unwrap_or_default();
let result = toolbar_input::consume_event(
ev, &mut st, ®.widget_id,
toolbar_input::ConsumeEventCtx { cursor, frame_rect: reg.frame_rect, viewport },
);
self.cur_branch_mut().toolbars.insert(reg.widget_id.clone(), st);
result
}
CompositeKind::Sidebar => {
let mut st = self.cur_branch_mut().sidebars.remove(®.widget_id).unwrap_or_default();
let result = sidebar_input::consume_event(
ev, &mut st, ®.widget_id,
sidebar_input::ConsumeEventCtx { cursor, frame_rect: reg.frame_rect, viewport },
);
self.cur_branch_mut().sidebars.insert(reg.widget_id.clone(), st);
result
}
CompositeKind::Chrome => Some(ev),
};
}
}
opt_ev
}
pub fn tree(&self) -> &LayoutTree {
&self.cur_branch().tree
}
pub fn tree_mut(&mut self) -> &mut LayoutTree {
&mut self.cur_branch_mut().tree
}
pub fn begin_frame_widgets(&mut self) {
let b = self.cur_branch_mut();
b.tree.clear_widgets();
b.dismiss_frames.clear();
}
pub fn push_dismiss_frame(&mut self, frame: DismissFrame) {
self.cur_branch_mut().dismiss_frames.push(frame);
}
pub fn overlay_kind_for(&self, overlay_id: &str) -> Option<super::OverlayKind> {
self.cur_branch().overlays.get(overlay_id).map(|e| e.kind)
}
pub fn dismiss_topmost_at(&self, pos: (f64, f64)) -> Option<WidgetId> {
let b = self.cur_branch();
if b.dismiss_frames.is_empty() {
return None;
}
let topmost = b.dismiss_frames
.iter()
.enumerate()
.rev()
.max_by_key(|(i, f)| (f.z, *i))?
.1;
if topmost.rect.contains(pos.0, pos.1) { None }
else { Some(topmost.overlay_id.clone()) }
}
pub fn compute_layer_for(&self, node_id: LayoutNodeId) -> LayerId {
let tree = &self.cur_branch().tree;
let chain = tree.parent_chain(node_id);
let mut effective = LayerId::main();
for ancestor_id in &chain {
if let Some(entry) = tree.entry(*ancestor_id) {
match &entry.node {
TreeLayoutNode::Widget(ref w) => {
if let Some(layer) = layer_for_widget_kind(w.kind) {
effective = layer;
}
}
TreeLayoutNode::System(ref s) => {
use super::tree::SystemNodeKind;
match s {
SystemNodeKind::OverlayStack => {}
SystemNodeKind::Chrome => { effective = LayerId::new("chrome"); }
SystemNodeKind::DockRoot | SystemNodeKind::EdgeSide { .. } => { effective = LayerId::main(); }
SystemNodeKind::FloatingLayer => { effective = LayerId::new("floating"); }
}
}
}
}
}
effective
}
pub fn dock(&self) -> &DockState<P> {
&self.cur_branch().dock
}
pub fn dock_mut(&mut self) -> &mut DockState<P> {
&mut self.cur_branch_mut().dock
}
#[doc(hidden)]
pub fn panels(&self) -> &DockState<P> {
&self.cur_branch().dock
}
#[doc(hidden)]
pub fn panels_mut(&mut self) -> &mut DockState<P> {
&mut self.cur_branch_mut().dock
}
pub fn attach_window(
&mut self,
key: crate::layout::window::WindowKey,
provider: Box<dyn WindowProvider>,
) {
let rect = provider.window_rect();
let key_str = key.as_str().to_owned();
self.windows.insert(key, WindowSlot::new(provider, rect));
self.agent_log.push(
self.frame_time_ms,
Some(key_str.clone()),
"lm.window.attach",
serde_json::json!({ "window": key_str }),
);
}
pub fn detach_window(&mut self, key: &crate::layout::window::WindowKey) -> Option<WindowSlot<P>> {
let removed = self.windows.remove(key);
if removed.is_some() {
self.agent_log.push(
self.frame_time_ms,
Some(key.as_str().to_owned()),
"lm.window.detach",
serde_json::json!({ "window": key.as_str() }),
);
}
removed
}
pub fn window(&self, key: &crate::layout::window::WindowKey) -> Option<&WindowSlot<P>> {
self.windows.get(key)
}
pub fn window_mut(&mut self, key: &crate::layout::window::WindowKey) -> Option<&mut WindowSlot<P>> {
self.windows.get_mut(key)
}
pub fn has_windows(&self) -> bool {
!self.windows.is_empty()
}
pub fn window_keys(&self) -> impl Iterator<Item = &crate::layout::window::WindowKey> {
self.windows.keys()
}
fn branch_mut(&mut self, key: &WindowKey) -> &mut WindowBranch<P> {
self.windows.get_mut(key)
.unwrap_or_else(|| panic!("LayoutManager: no window attached for key {:?}", key))
}
fn branch(&self, key: &WindowKey) -> &WindowBranch<P> {
self.windows.get(key)
.unwrap_or_else(|| panic!("LayoutManager: no window attached for key {:?}", key))
}
pub fn solve_window(&mut self, key: &WindowKey, window: Rect) -> &LayoutSolved {
let b = self.branch_mut(key);
let solved = solve_layout(window, &b.chrome, &b.edges, &mut b.tree);
let dock_pr = panel_rect_from_rect(solved.dock_area);
b.dock.layout(dock_pr);
b.last_solved = Some(solved);
b.last_window = Some(window);
b.rect = window;
b.last_solved.as_ref().expect("just assigned")
}
pub fn last_solved_for(&self, key: &WindowKey) -> Option<&LayoutSolved> {
self.windows.get(key).and_then(|b| b.last_solved.as_ref())
}
pub fn last_window_for(&self, key: &WindowKey) -> Option<Rect> {
self.windows.get(key).and_then(|b| b.last_window)
}
pub fn on_pointer_move_in(&mut self, key: &WindowKey, x: f64, y: f64) {
let b = self.branch_mut(key);
b.ctx.input.set_cursor_pos(x, y);
b.last_pointer_pos = Some((x, y));
b.last_hovered = b.ctx.input.process_click(x, y)
.or_else(|| b.ctx.input.process_hover(x, y));
}
pub fn on_pointer_down_in(&mut self, key: &WindowKey, x: f64, y: f64) {
let b = self.branch_mut(key);
b.ctx.input.set_cursor_pos(x, y);
b.last_pointer_pos = Some((x, y));
b.last_pressed = b.ctx.input.process_drag_press(x, y);
}
pub fn on_pointer_up_in(&mut self, key: &WindowKey, x: f64, y: f64) -> PointerUpOutcome {
{
let b = self.branch_mut(key);
b.ctx.input.set_cursor_pos(x, y);
b.last_pointer_pos = Some((x, y));
let hit = b.ctx.input.process_click(x, y);
if let Some(ref id) = hit {
b.last_click = Some((id.clone(), (x, y)));
}
}
match self.handle_click_in(key, (x, y)) {
ClickOutcome::DismissOverlay(h) => PointerUpOutcome::DismissedOverlay(h),
ClickOutcome::DispatchEvent(ev) => {
let id = match &ev {
super::DispatchEvent::Unhandled(id) => id.clone(),
_ => crate::types::WidgetId::new(""),
};
PointerUpOutcome::Click(id, ev)
}
ClickOutcome::Unhandled { .. } => PointerUpOutcome::Unhandled,
}
}
pub fn on_pointer_right_up_in(&mut self, key: &WindowKey, x: f64, y: f64) {
let b = self.branch_mut(key);
b.ctx.input.set_cursor_pos(x, y);
b.last_pointer_pos = Some((x, y));
let hit = b.ctx.input.process_right_click(x, y);
if let Some(id) = hit {
b.last_right_click = Some((id, (x, y)));
}
}
pub fn on_scroll_in(&mut self, key: &WindowKey, dx: f64, dy: f64) {
let b = self.branch_mut(key);
b.last_scroll.0 += dx;
b.last_scroll.1 += dy;
}
pub fn handle_click_in(&mut self, key: &WindowKey, pos: (f64, f64)) -> ClickOutcome {
if let Some(overlay_id) = self.dismiss_topmost_at_in(key, pos) {
let kind = self.overlay_kind_for_in(key, overlay_id.0.as_str());
let handle = self.make_overlay_handle_in(key, overlay_id, kind);
return ClickOutcome::DismissOverlay(handle);
}
let clicked = {
let b = self.branch_mut(key);
b.ctx.input.process_click(pos.0, pos.1)
};
match clicked {
Some(id) => {
let event = self.dispatch_widget_in(key, &id);
ClickOutcome::DispatchEvent(event)
}
None => ClickOutcome::Unhandled { pos },
}
}
pub fn dispatch_widget_in(&self, key: &WindowKey, id: &WidgetId) -> super::DispatchEvent {
self.branch(key).dispatcher
.dispatch(id)
.unwrap_or_else(|| super::DispatchEvent::Unhandled(id.clone()))
}
pub fn dismiss_topmost_at_in(&self, key: &WindowKey, pos: (f64, f64)) -> Option<WidgetId> {
let b = self.branch(key);
if b.dismiss_frames.is_empty() {
return None;
}
let topmost = b
.dismiss_frames
.iter()
.enumerate()
.rev()
.max_by_key(|(i, f)| (f.z, *i))?
.1;
if topmost.rect.contains(pos.0, pos.1) {
None
} else {
Some(topmost.overlay_id.clone())
}
}
pub fn overlay_kind_for_in(&self, key: &WindowKey, overlay_id: &str) -> Option<super::OverlayKind> {
self.branch(key).overlays.get(overlay_id).map(|e| e.kind)
}
fn make_overlay_handle_in(
&self,
key: &WindowKey,
overlay_id: WidgetId,
kind: Option<super::OverlayKind>,
) -> OverlayHandle {
let slot = overlay_id.0.as_str();
let b = self.branch(key);
if let Some(reg) = b.composite_registry.iter().find(|r| r.slot_id == slot) {
let wid = ®.widget_id;
return match reg.kind {
CompositeKind::Modal => OverlayHandle::Modal(ModalHandle { id: wid.clone() }),
CompositeKind::Popup => OverlayHandle::Popup(PopupHandle { id: wid.clone() }),
CompositeKind::Dropdown => OverlayHandle::Dropdown(DropdownHandle { id: wid.clone() }),
CompositeKind::ContextMenu => OverlayHandle::ContextMenu(ContextMenuHandle { id: wid.clone() }),
_ => OverlayHandle::Other { overlay_id, kind },
};
}
OverlayHandle::Other { overlay_id, kind }
}
pub fn dispatcher_begin_frame_in(&mut self, key: &WindowKey) {
let b = self.branch_mut(key);
b.dispatcher.clear();
b.dismiss_frames.clear();
b.composite_registry.clear();
}
pub fn begin_frame_widgets_in(&mut self, key: &WindowKey) {
let b = self.branch_mut(key);
b.tree.clear_widgets();
b.dismiss_frames.clear();
}
pub fn begin_frame_in(&mut self, key: &WindowKey, time_ms: f64, viewport: Rect) {
let b = self.branch_mut(key);
b.ctx.begin_frame_widgets_only(time_ms / 1000.0, viewport);
}
pub fn inputs_begin_frame_in(&mut self, key: &WindowKey) {
let b = self.branch_mut(key);
b.last_click = None;
b.last_right_click = None;
b.last_pressed = None;
b.last_scroll = (0.0, 0.0);
}
pub fn end_frame_inputs_in(&mut self, key: &WindowKey) {
self.inputs_begin_frame_in(key);
}
pub fn chrome_for(&self, key: &WindowKey) -> &ChromeSlot { &self.branch(key).chrome }
pub fn chrome_mut_for(&mut self, key: &WindowKey) -> &mut ChromeSlot { &mut self.branch_mut(key).chrome }
pub fn edges_for(&self, key: &WindowKey) -> &EdgePanels { &self.branch(key).edges }
pub fn edges_mut_for(&mut self, key: &WindowKey) -> &mut EdgePanels { &mut self.branch_mut(key).edges }
pub fn dock_for(&self, key: &WindowKey) -> &DockState<P> { &self.branch(key).dock }
pub fn dock_mut_for(&mut self, key: &WindowKey) -> &mut DockState<P> { &mut self.branch_mut(key).dock }
pub fn tree_for(&self, key: &WindowKey) -> &LayoutTree { &self.branch(key).tree }
pub fn tree_mut_for(&mut self, key: &WindowKey) -> &mut LayoutTree { &mut self.branch_mut(key).tree }
pub fn ctx_for(&self, key: &WindowKey) -> &ContextManager { &self.branch(key).ctx }
pub fn ctx_mut_for(&mut self, key: &WindowKey) -> &mut ContextManager { &mut self.branch_mut(key).ctx }
pub fn overlays_for(&self, key: &WindowKey) -> &OverlayStack { &self.branch(key).overlays }
pub fn overlays_mut_for(&mut self, key: &WindowKey) -> &mut OverlayStack { &mut self.branch_mut(key).overlays }
pub fn dispatcher_for(&self, key: &WindowKey) -> &super::ClickDispatcher { &self.branch(key).dispatcher }
pub fn dispatcher_mut_for(&mut self, key: &WindowKey) -> &mut super::ClickDispatcher { &mut self.branch_mut(key).dispatcher }
pub fn chrome_state_for(&self, key: &WindowKey) -> &ChromeState { &self.branch(key).chrome_widget_state }
pub fn chrome_state_mut_for(&mut self, key: &WindowKey) -> &mut ChromeState { &mut self.branch_mut(key).chrome_widget_state }
pub fn rect_for_chrome_in(&self, key: &WindowKey) -> Option<Rect> {
self.branch(key).last_solved.as_ref().and_then(|s| s.chrome)
}
pub fn rect_for_dock_area_in(&self, key: &WindowKey) -> Option<Rect> {
self.branch(key).last_solved.as_ref().map(|s| s.dock_area)
}
pub fn last_pressed_widget_in(&self, key: &WindowKey) -> Option<&WidgetId> {
self.branch(key).last_pressed.as_ref()
}
pub fn hovered_widget_in(&self, key: &WindowKey) -> Option<&WidgetId> {
self.branch(key).last_hovered.as_ref()
}
pub fn pointer_pos_in(&self, key: &WindowKey) -> Option<(f64, f64)> {
self.branch(key).last_pointer_pos
}
pub fn was_clicked_in(&self, key: &WindowKey, id: &WidgetId) -> bool {
self.branch(key).last_click.as_ref().map_or(false, |(c, _)| c == id)
}
pub fn modal_in(&self, key: &WindowKey, h: &ModalHandle) -> &ModalState {
self.branch(key).modals.get(&h.id).expect("modal handle invalidated")
}
pub fn modal_mut_in(&mut self, key: &WindowKey, h: &ModalHandle) -> &mut ModalState {
self.branch_mut(key).modals.get_mut(&h.id).expect("modal handle invalidated")
}
pub fn popup_in(&self, key: &WindowKey, h: &PopupHandle) -> &PopupState {
self.branch(key).popups.get(&h.id).expect("popup handle invalidated")
}
pub fn popup_mut_in(&mut self, key: &WindowKey, h: &PopupHandle) -> &mut PopupState {
self.branch_mut(key).popups.get_mut(&h.id).expect("popup handle invalidated")
}
pub fn dropdown_in(&self, key: &WindowKey, h: &DropdownHandle) -> &DropdownState {
self.branch(key).dropdowns.get(&h.id).expect("dropdown handle invalidated")
}
pub fn dropdown_mut_in(&mut self, key: &WindowKey, h: &DropdownHandle) -> &mut DropdownState {
self.branch_mut(key).dropdowns.get_mut(&h.id).expect("dropdown handle invalidated")
}
pub fn toolbar_in(&self, key: &WindowKey, h: &ToolbarHandle) -> &ToolbarState {
self.branch(key).toolbars.get(&h.id).expect("toolbar handle invalidated")
}
pub fn toolbar_mut_in(&mut self, key: &WindowKey, h: &ToolbarHandle) -> &mut ToolbarState {
self.branch_mut(key).toolbars.get_mut(&h.id).expect("toolbar handle invalidated")
}
pub fn sidebar_in(&self, key: &WindowKey, h: &SidebarHandle) -> &SidebarState {
self.branch(key).sidebars.get(&h.id).expect("sidebar handle invalidated")
}
pub fn sidebar_mut_in(&mut self, key: &WindowKey, h: &SidebarHandle) -> &mut SidebarState {
self.branch_mut(key).sidebars.get_mut(&h.id).expect("sidebar handle invalidated")
}
pub fn context_menu_in(&self, key: &WindowKey, h: &ContextMenuHandle) -> &ContextMenuState {
self.branch(key).context_menus.get(&h.id).expect("context_menu handle invalidated")
}
pub fn context_menu_mut_in(&mut self, key: &WindowKey, h: &ContextMenuHandle) -> &mut ContextMenuState {
self.branch_mut(key).context_menus.get_mut(&h.id).expect("context_menu handle invalidated")
}
pub fn add_modal_in(&mut self, key: &WindowKey, id: &str) -> ModalHandle {
let widget_id = WidgetId(id.to_owned());
self.branch_mut(key).modals.entry(widget_id.clone()).or_default();
ModalHandle { id: widget_id }
}
pub fn add_popup_in(&mut self, key: &WindowKey, id: &str) -> PopupHandle {
let widget_id = WidgetId(id.to_owned());
self.branch_mut(key).popups.entry(widget_id.clone()).or_default();
PopupHandle { id: widget_id }
}
pub fn add_dropdown_in(&mut self, key: &WindowKey, id: &str) -> DropdownHandle {
let widget_id = WidgetId(id.to_owned());
self.branch_mut(key).dropdowns.entry(widget_id.clone()).or_default();
DropdownHandle { id: widget_id }
}
pub fn add_toolbar_in(&mut self, key: &WindowKey, id: &str) -> ToolbarHandle {
let widget_id = WidgetId(id.to_owned());
self.branch_mut(key).toolbars.entry(widget_id.clone()).or_default();
ToolbarHandle { id: widget_id }
}
pub fn add_sidebar_in(&mut self, key: &WindowKey, id: &str) -> SidebarHandle {
let widget_id = WidgetId(id.to_owned());
self.branch_mut(key).sidebars.entry(widget_id.clone()).or_default();
SidebarHandle { id: widget_id }
}
pub fn add_context_menu_in(&mut self, key: &WindowKey, id: &str) -> ContextMenuHandle {
let widget_id = WidgetId(id.to_owned());
self.branch_mut(key).context_menus.entry(widget_id.clone()).or_default();
ContextMenuHandle { id: widget_id }
}
pub fn push_composite_registration_in(&mut self, key: &WindowKey, reg: CompositeRegistration) {
self.branch_mut(key).composite_registry.push(reg);
}
pub fn push_dismiss_frame_in(&mut self, key: &WindowKey, frame: DismissFrame) {
self.branch_mut(key).dismiss_frames.push(frame);
}
pub fn push_overlay_in(&mut self, key: &WindowKey, entry: OverlayEntry) {
self.branch_mut(key).overlays.push(entry);
}
pub fn solve(&mut self, window: Rect) -> &LayoutSolved {
let b = self.cur_branch_mut();
let solved = solve_layout(window, &b.chrome, &b.edges, &mut b.tree);
let dock_pr = panel_rect_from_rect(solved.dock_area);
b.dock.layout(dock_pr);
b.last_solved = Some(solved);
b.last_window = Some(window);
b.rect = window;
b.last_solved.as_ref().expect("just assigned")
}
pub fn last_solved(&self) -> Option<&LayoutSolved> {
self.cur_branch().last_solved.as_ref()
}
pub fn last_window(&self) -> Option<Rect> {
self.cur_branch().last_window
}
pub fn rect_for_chrome(&self) -> Option<Rect> {
self.cur_branch().last_solved.as_ref().and_then(|s| s.chrome)
}
pub fn rect_for_dock_area(&self) -> Option<Rect> {
self.cur_branch().last_solved.as_ref().map(|s| s.dock_area)
}
pub fn rect_for_floating_area(&self) -> Option<Rect> {
self.cur_branch().last_solved.as_ref().map(|s| s.floating_area)
}
pub fn rect_for_overlay(&self, id: &str) -> Option<Rect> {
self.cur_branch().overlays.get(id).map(|e| e.rect)
}
pub fn modal_rect(&self, h: &ModalHandle) -> Option<Rect> {
self.rect_for_overlay(h.id_str())
}
pub fn popup_rect(&self, h: &PopupHandle) -> Option<Rect> {
self.rect_for_overlay(h.id_str())
}
pub fn dropdown_rect(&self, h: &DropdownHandle) -> Option<Rect> {
self.rect_for_overlay(h.id_str())
}
pub fn context_menu_rect(&self, h: &ContextMenuHandle) -> Option<Rect> {
self.rect_for_overlay(h.id_str())
}
pub fn modal_body_rect(&self, h: &ModalHandle) -> Option<Rect> {
use crate::ui::widgets::composite::modal::{
render::body_rect as modal_body_rect_fn, settings::ModalSettings,
types::{BackdropKind, ModalRenderKind, ModalView},
};
let frame = self.modal_rect(h)?;
let view = ModalView {
title: None,
tabs: &[],
footer_buttons: &[],
wizard_pages: &[],
backdrop: BackdropKind::Dim,
overflow: crate::types::OverflowMode::Clip,
resizable: false,
};
let settings = ModalSettings::default();
let kind = ModalRenderKind::WithHeader;
Some(modal_body_rect_fn(frame, &view, &settings, &kind))
}
pub fn popup_body_rect(&self, h: &PopupHandle) -> Option<Rect> {
use crate::ui::widgets::composite::popup::{
render::body_rect as popup_body_rect_fn, settings::PopupSettings,
};
let frame = self.popup_rect(h)?;
let settings = PopupSettings::default();
Some(popup_body_rect_fn(frame, &settings))
}
pub fn rect_for_edge_slot(&self, id: &str) -> Option<Rect> {
let b = self.cur_branch();
let solved = b.last_solved.as_ref()?;
let slot = b.edges.get(id)?;
use super::types::EdgeSide;
let visible: Vec<_> = b.edges.slots_for(slot.side).collect();
let idx = visible.iter().position(|s| s.id == id)?;
let rects = match slot.side {
EdgeSide::Top => &solved.edges.top,
EdgeSide::Bottom => &solved.edges.bottom,
EdgeSide::Left => &solved.edges.left,
EdgeSide::Right => &solved.edges.right,
};
rects.get(idx).copied()
}
pub fn rect_for(&self, slot_id: &str) -> Option<Rect> {
if slot_id == "chrome" {
return self.rect_for_chrome();
}
if let Some(r) = self.rect_for_edge_slot(slot_id) {
return Some(r);
}
if let Some(r) = self.rect_for_overlay(slot_id) {
return Some(r);
}
if let Some(pr) = self.cur_branch().dock.rect_for_leaf_str(slot_id) {
return Some(panel_rect_to_rect(pr));
}
if let Some(pr) = self.cur_branch().dock.rect_for_panel_id(slot_id) {
return Some(panel_rect_to_rect(pr));
}
None
}
pub fn push_overlay(&mut self, entry: OverlayEntry) {
self.cur_branch_mut().overlays.push(entry);
}
pub fn clear_overlays(&mut self) {
self.cur_branch_mut().overlays.clear();
}
pub fn overlays_in_draw_order(&mut self) -> &[OverlayEntry] {
let z = self.z_layers.clone();
let b = self.cur_branch_mut();
b.overlays.sort_by_z(&z);
b.overlays.entries()
}
pub fn z_for(&self, kind: OverlayKind) -> i32 {
self.z_layers.z_for(kind)
}
pub fn register_dock_separators(&mut self, layer: &LayerId) {
use crate::layout::docking::SeparatorOrientation as SepOrient;
let b = self.cur_branch_mut();
let sep_rects: Vec<(usize, Rect)> = b
.dock
.separators()
.iter()
.enumerate()
.map(|(i, s)| {
let thickness = s.thickness_for_state() as f64;
let (x, y, w, h) = match s.orientation {
SepOrient::Vertical => (
s.position as f64 - thickness / 2.0,
s.start as f64,
thickness,
s.length as f64,
),
SepOrient::Horizontal => (
s.start as f64,
s.position as f64 - thickness / 2.0,
s.length as f64,
thickness,
),
};
(i, Rect::new(x, y, w, h))
})
.collect();
let coord = &mut b.ctx.input;
for (i, rect) in &sep_rects {
coord.register_atomic(
WidgetId::new(format!("dock-sep-{i}")),
WidgetKind::DragHandle,
*rect,
crate::input::Sense::DRAG | crate::input::Sense::CLICK,
layer,
);
}
b.dispatcher.on_prefix(
"dock-sep-",
super::EventBuilder::DockSeparatorFromSuffix,
);
}
pub fn register_widget_slot(&mut self, widget_id: &WidgetId, slot_id: &str) {
self.cur_branch_mut().widget_to_slot.insert(widget_id.clone(), slot_id.to_string());
}
pub fn resize_handle_to_separator(
&self,
host_id: &str,
edge: super::ResizeEdge,
) -> Option<usize> {
let branch = self.cur_branch();
let dock = &branch.dock;
let slot = branch
.widget_to_slot
.get(&WidgetId::new(host_id))
.cloned();
let leaf = if let Some(slot) = slot.as_deref() {
dock.leaf_for_panel_id(slot)
} else {
dock.leaf_for_panel_id(host_id)
}?;
dock.separator_for_edge(leaf, edge)
}
pub fn handle_click(&mut self, pos: (f64, f64)) -> ClickOutcome {
if let Some(overlay_id) = self.dismiss_topmost_at(pos) {
let kind = self.overlay_kind_for(overlay_id.0.as_str());
let handle = self.make_overlay_handle(overlay_id, kind);
return ClickOutcome::DismissOverlay(handle);
}
let clicked = self.cur_branch_mut().ctx.input.process_click(pos.0, pos.1);
match clicked {
Some(id) => {
let event = self.dispatch_widget_logged(&id);
ClickOutcome::DispatchEvent(event)
}
None => ClickOutcome::Unhandled { pos },
}
}
fn make_overlay_handle(
&self,
overlay_id: WidgetId,
kind: Option<super::OverlayKind>,
) -> OverlayHandle {
let slot = overlay_id.0.as_str();
if let Some(reg) = self.cur_branch().composite_registry.iter().find(|r| r.slot_id == slot) {
let wid = ®.widget_id;
return match reg.kind {
CompositeKind::Modal => OverlayHandle::Modal(ModalHandle { id: wid.clone() }),
CompositeKind::Popup => OverlayHandle::Popup(PopupHandle { id: wid.clone() }),
CompositeKind::Dropdown => OverlayHandle::Dropdown(DropdownHandle { id: wid.clone() }),
CompositeKind::ContextMenu => OverlayHandle::ContextMenu(ContextMenuHandle { id: wid.clone() }),
_ => OverlayHandle::Other { overlay_id, kind },
};
}
OverlayHandle::Other { overlay_id, kind }
}
}
#[derive(Debug, Clone)]
pub enum PointerUpOutcome {
DismissedOverlay(super::handles::OverlayHandle),
Click(crate::types::WidgetId, super::DispatchEvent),
Unhandled,
}
#[derive(Debug, Clone)]
pub enum ClickOutcome {
DismissOverlay(OverlayHandle),
DispatchEvent(super::DispatchEvent),
Unhandled { pos: (f64, f64) },
}
impl<P: DockPanel> LayoutManager<P> {
pub fn on_pointer_move(&mut self, x: f64, y: f64) {
let b = self.cur_branch_mut();
b.ctx.input.set_cursor_pos(x, y);
b.last_pointer_pos = Some((x, y));
b.last_hovered = b.ctx.input.process_click(x, y)
.or_else(|| b.ctx.input.process_hover(x, y));
}
pub fn on_pointer_down(&mut self, x: f64, y: f64) {
let b = self.cur_branch_mut();
b.ctx.input.set_cursor_pos(x, y);
b.last_pointer_pos = Some((x, y));
b.last_pressed = b.ctx.input.process_drag_press(x, y);
}
pub fn on_pointer_up(&mut self, x: f64, y: f64) -> PointerUpOutcome {
let mut clicked_id: Option<String> = None;
let window_key: Option<String> = self.current_window.as_ref().map(|k| k.as_str().to_owned());
{
let b = self.cur_branch_mut();
b.ctx.input.set_cursor_pos(x, y);
b.last_pointer_pos = Some((x, y));
let hit = b.ctx.input.process_click(x, y);
if let Some(ref id) = hit {
b.last_click = Some((id.clone(), (x, y)));
clicked_id = Some(id.as_str().to_owned());
}
}
if let Some(id) = clicked_id {
let ts = self.frame_time_ms;
self.agent_log.push(
ts,
window_key,
"lm.click",
serde_json::json!({ "widget_id": id, "x": x, "y": y }),
);
}
match self.handle_click((x, y)) {
ClickOutcome::DismissOverlay(h) => PointerUpOutcome::DismissedOverlay(h),
ClickOutcome::DispatchEvent(ev) => {
let id = match &ev {
super::DispatchEvent::Unhandled(id) => id.clone(),
_ => crate::types::WidgetId::new(""),
};
PointerUpOutcome::Click(id, ev)
}
ClickOutcome::Unhandled { .. } => PointerUpOutcome::Unhandled,
}
}
pub fn on_pointer_right_up(&mut self, x: f64, y: f64) {
let b = self.cur_branch_mut();
b.ctx.input.set_cursor_pos(x, y);
b.last_pointer_pos = Some((x, y));
let hit = b.ctx.input.process_right_click(x, y);
if let Some(id) = hit {
b.last_right_click = Some((id, (x, y)));
}
}
pub fn on_scroll(&mut self, dx: f64, dy: f64) {
let b = self.cur_branch_mut();
b.last_scroll.0 += dx;
b.last_scroll.1 += dy;
}
pub fn handle_chrome_press<H: super::host::WindowHost + ?Sized>(
&mut self,
x: f64,
y: f64,
host: &mut H,
time_ms: f64,
) -> bool {
use crate::ui::widgets::composite::chrome::{
chrome_hit_test, handle_chrome_action, ChromeAction, ChromeRenderKind,
ChromeSettings, ChromeView,
};
use crate::ui::widgets::composite::chrome::types::{ChromeHit, ResizeCorner};
use crate::platform::types::ResizeDirection;
if let Some(chrome_rect) = self.rect_for_chrome() {
let view = ChromeView {
tabs: &[],
active_tab_id: None,
show_new_tab_btn: false,
show_menu_btn: false,
show_new_window_btn: true,
show_close_window_btn: true,
is_maximized: host.is_maximized(),
cursor_x: x,
cursor_y: y,
time_ms,
};
let settings = ChromeSettings::default();
let kind = ChromeRenderKind::Default;
let hit = chrome_hit_test(
self.chrome_state(), &view, &settings, &kind,
chrome_rect, (x, y),
);
match handle_chrome_action(hit) {
ChromeAction::WindowDragStart => {
host.drag_window();
return true;
}
ChromeAction::Minimize => {
host.set_minimized(true);
return true;
}
ChromeAction::MaximizeRestore => {
host.set_maximized(!host.is_maximized());
return true;
}
ChromeAction::CloseWindow => {
host.close_window();
return true;
}
ChromeAction::CloseApp => {
host.close_app();
return true;
}
ChromeAction::NewWindow => {
return false; }
ChromeAction::BeginResize(h) => {
let dir = match h {
ChromeHit::ResizeTop => Some(ResizeDirection::North),
ChromeHit::ResizeBottom => Some(ResizeDirection::South),
ChromeHit::ResizeLeft => Some(ResizeDirection::West),
ChromeHit::ResizeRight => Some(ResizeDirection::East),
ChromeHit::ResizeCorner(ResizeCorner::TopLeft) => Some(ResizeDirection::NorthWest),
ChromeHit::ResizeCorner(ResizeCorner::TopRight) => Some(ResizeDirection::NorthEast),
ChromeHit::ResizeCorner(ResizeCorner::BottomLeft) => Some(ResizeDirection::SouthWest),
ChromeHit::ResizeCorner(ResizeCorner::BottomRight) => Some(ResizeDirection::SouthEast),
_ => None,
};
if let Some(d) = dir {
host.drag_resize_window(d);
return true;
}
}
_ => {}
}
}
let win = self.last_window().unwrap_or_default();
let bezel = 6.0_f64;
if win.width > 0.0 && win.height > 0.0 {
let on_left = x >= win.x && x < win.x + bezel;
let on_right = x >= win.x + win.width - bezel && x < win.x + win.width;
let on_top = y >= win.y && y < win.y + bezel;
let on_bottom = y >= win.y + win.height - bezel && y < win.y + win.height;
let dir = match (on_top, on_bottom, on_left, on_right) {
(true, _, true, _ ) => Some(ResizeDirection::NorthWest),
(true, _, _, true) => Some(ResizeDirection::NorthEast),
(_, true, true, _ ) => Some(ResizeDirection::SouthWest),
(_, true, _, true) => Some(ResizeDirection::SouthEast),
(true, _, _, _ ) => Some(ResizeDirection::North),
(_, true, _, _ ) => Some(ResizeDirection::South),
(_, _, true, _ ) => Some(ResizeDirection::West),
(_, _, _, true) => Some(ResizeDirection::East),
_ => None,
};
if let Some(d) = dir {
host.drag_resize_window(d);
return true;
}
}
false
}
}
impl<P: DockPanel> Default for LayoutManager<P> {
fn default() -> Self {
Self::new()
}
}