halley-wl 0.3.0

Wayland backend and rendering implementation for the Halley Wayland compositor.
use super::naming::cluster_mode_selection_banner;
use super::*;

impl<T: DerefMut<Target = Halley>> ClusterSystemController<T> {
    pub fn cluster_bloom_for_monitor(
        &mut self,
        monitor: &str,
    ) -> Option<halley_core::cluster::ClusterId> {
        self.cluster_read_controller()
            .cluster_bloom_for_monitor(monitor)
    }

    pub fn open_cluster_bloom_for_monitor(
        &mut self,
        monitor: &str,
        cid: halley_core::cluster::ClusterId,
    ) -> bool {
        let _ = self.sync_cluster_monitor(cid, Some(monitor));
        let opened = self
            .cluster_mutation_controller()
            .open_cluster_bloom_for_monitor(monitor, cid);
        if opened
            && let Some(core_id) = self
                .model
                .field
                .cluster(cid)
                .and_then(|cluster| cluster.core)
        {
            self.set_interaction_focus(Some(core_id), 30_000, Instant::now());
        }
        opened
    }

    pub fn close_cluster_bloom_for_monitor(&mut self, monitor: &str) -> bool {
        let core_id = self.cluster_bloom_for_monitor(monitor).and_then(|cid| {
            self.model
                .field
                .cluster(cid)
                .and_then(|cluster| cluster.core)
        });
        let closed = self
            .cluster_mutation_controller()
            .close_cluster_bloom_for_monitor(monitor);
        if closed {
            let now = Instant::now();
            if let Some(core_id) = core_id {
                self.set_recent_top_node(core_id, now + std::time::Duration::from_millis(1200));
                self.set_interaction_focus(Some(core_id), 30_000, now);
            }
        }
        closed
    }

    pub fn enter_cluster_mode(&mut self) -> bool {
        let monitor = self.model.monitor_state.current_monitor.clone();
        if self
            .active_cluster_workspace_for_monitor(monitor.as_str())
            .is_some()
        {
            let now_ms = self.now_ms(Instant::now());
            self.ui.render_state.show_overlay_toast(
                monitor.as_str(),
                "Cluster mode unavailable\nExit the workspace first",
                3200,
                now_ms,
            );
            return false;
        }
        if !self
            .cluster_mutation_controller()
            .enter_cluster_mode(monitor.as_str())
        {
            return false;
        }
        self.begin_modal_keyboard_capture();
        cluster_mode_selection_banner(self, monitor.as_str());
        true
    }

    pub fn exit_cluster_mode(&mut self) -> bool {
        let monitor = self.model.monitor_state.current_monitor.clone();
        if !self
            .cluster_mutation_controller()
            .exit_cluster_mode(monitor.as_str())
        {
            return false;
        }
        self.model
            .cluster_state
            .cluster_name_prompt
            .remove(monitor.as_str());
        if self
            .input
            .interaction_state
            .cluster_name_prompt_drag_monitor
            .as_deref()
            == Some(monitor.as_str())
        {
            self.input
                .interaction_state
                .cluster_name_prompt_drag_monitor = None;
        }
        if self
            .input
            .interaction_state
            .cluster_name_prompt_repeat
            .as_ref()
            .is_some_and(|repeat| repeat.monitor == monitor)
        {
            self.input.interaction_state.cluster_name_prompt_repeat = None;
        }
        self.ui
            .render_state
            .clear_persistent_mode_banner(monitor.as_str());
        let focused_surface = self
            .model
            .focus_state
            .primary_interaction_focus
            .filter(|&id| {
                self.model.field.node(id).is_some_and(|node| {
                    self.model.field.is_visible(id)
                        && node.kind == halley_core::field::NodeKind::Surface
                })
            })
            .or_else(|| self.last_input_surface_node_for_monitor(monitor.as_str()));
        self.schedule_modal_focus_restore(focused_surface, Instant::now());
        true
    }

    pub fn toggle_cluster_mode_selection(&mut self, node_id: NodeId) -> bool {
        let monitor = self.model.monitor_state.current_monitor.clone();
        self.cluster_mutation_controller()
            .toggle_cluster_mode_selection(monitor.as_str(), node_id)
    }

    pub(super) fn order_cluster_creation_members(&self, members: Vec<NodeId>) -> Vec<NodeId> {
        if members.len() <= 1 {
            return members;
        }

        let selected = members.iter().copied().collect::<HashSet<_>>();
        let master = self
            .model
            .focus_state
            .primary_interaction_focus
            .filter(|id| selected.contains(id))
            .or_else(|| {
                members.iter().copied().max_by_key(|id| {
                    (
                        self.model
                            .focus_state
                            .last_surface_focus_ms
                            .get(id)
                            .copied()
                            .unwrap_or(0),
                        std::cmp::Reverse(id.as_u64()),
                    )
                })
            })
            .unwrap_or(members[0]);

        let mut secondaries = members
            .into_iter()
            .filter(|id| *id != master)
            .collect::<Vec<_>>();
        secondaries.sort_by_key(|id| id.as_u64());

        let mut ordered = Vec::with_capacity(secondaries.len() + 1);
        ordered.push(master);
        ordered.extend(secondaries);
        ordered
    }

    pub fn confirm_cluster_mode(&mut self, now: Instant) -> bool {
        self.open_cluster_name_prompt(now)
    }
}