use std::collections::HashMap;
use crate::item_tree::node::{InternalItem, NodeId};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DropPosition {
Before,
Into,
After,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ItemDragMsg {
Pressed(NodeId),
Entered(NodeId, DropPosition),
Exited(NodeId, DropPosition),
Released(NodeId, DropPosition),
Cancelled,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ItemDragOutcome {
None,
Clicked(NodeId),
Completed {
sources: Vec<NodeId>,
target: NodeId,
position: DropPosition,
},
}
#[derive(Debug, Clone)]
pub(crate) struct ItemDragState {
pub(crate) sources: Vec<NodeId>,
pub(crate) primary: NodeId,
pub(crate) hover: Option<(NodeId, DropPosition)>,
}
pub(crate) fn is_valid_drop<T>(
store: &HashMap<NodeId, InternalItem<T>>,
sources: &[NodeId],
target: NodeId,
position: DropPosition,
) -> bool {
let Some(target_item) = store.get(&target) else {
return false;
};
if sources.contains(&target) {
return false;
}
let effective_parent = match position {
DropPosition::Into => target,
DropPosition::Before | DropPosition::After => match target_item.parent_id {
Some(p) => p,
None => return false, },
};
for &s in sources {
if is_ancestor_or_self(store, s, effective_parent) {
return false;
}
}
true
}
fn is_ancestor_or_self<T>(
store: &HashMap<NodeId, InternalItem<T>>,
maybe_ancestor: NodeId,
node: NodeId,
) -> bool {
let mut cur = Some(node);
while let Some(c) = cur {
if c == maybe_ancestor {
return true;
}
cur = store.get(&c).and_then(|item| item.parent_id);
}
false
}
#[cfg(test)]
mod tests;