agentmux_cef\reducer/
drag.rs

1// Copyright 2026, AgentMux Corp.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Drag state (Phase H.3) reducer handlers. Extracted from reducer/mod.rs in
5//! task #182 PR-F-2 for navigability.
6
7
8use crate::state::*;
9
10use super::{DispatchOutput, DragOutcome, HostEvent, HostState, emit_error};
11
12// ── H.3 — drag state ─────────────────────────────────────────────────────
13
14pub(super) fn handle_start_drag(state: &mut HostState, session: DragSession) -> DispatchOutput {
15    if state.active_drag.is_some() {
16        return emit_error(state, "start_drag: drag session already active".to_string());
17    }
18    let drag_id = session.drag_id.clone();
19    let source_window = session.source_window.clone();
20    state.active_drag = Some(session);
21    let v = state.bump_version();
22    DispatchOutput {
23        events: vec![HostEvent::DragStarted { drag_id, source_window, version: v }],
24        ..Default::default()
25    }
26}
27
28pub(super) fn handle_end_drag(
29    state: &mut HostState,
30    drag_id: String,
31    outcome: DragOutcome,
32) -> DispatchOutput {
33    let active_id = state.active_drag.as_ref().map(|s| s.drag_id.clone());
34    match active_id {
35        Some(id) if id == drag_id => {
36            // PR #5 H.3 — return the prior session via output so callers
37            // (cross-drag complete / cancel) can build the renderer-side
38            // event payload without a separate read of state.active_drag.
39            let session = state.active_drag.take();
40            let v = state.bump_version();
41            DispatchOutput {
42                events: vec![HostEvent::DragEnded { drag_id, outcome, version: v }],
43                ended_drag_session: session,
44                ..Default::default()
45            }
46        }
47        _ => DispatchOutput::default(), // mismatched or no drag; idempotent no-op
48    }
49}
50