use iced_core::{Rectangle, Vector};
use iced_core::widget::{Id, Operation};
use iced_core::widget::operation::{Outcome, Scrollable};
pub fn find_zones<F>(
filter: F,
options: Option<Vec<Id>>,
depth: Option<usize>,
) -> impl Operation<Vec<(Id, Rectangle)>>
where
F: Fn(&Rectangle) -> bool + Send + 'static,
{
struct FindDropZone<F> {
filter: F,
options: Option<Vec<Id>>,
zones: Vec<(Id, Rectangle)>,
max_depth: Option<usize>,
c_depth: usize,
offset: Vector,
goto_next: bool,
}
impl<F> Operation<Vec<(Id, Rectangle)>> for FindDropZone<F>
where
F: Fn(&Rectangle) -> bool + Send + 'static,
{
fn traverse(
&mut self,
operate: &mut dyn FnMut(&mut dyn Operation<Vec<(Id, Rectangle)>>),
) {
if self.goto_next {
operate(self);
}
}
fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
if let Some(id) = id {
let is_option = match &self.options {
Some(options) => options.contains(id),
None => true,
};
let bounds = bounds - self.offset;
if is_option && (self.filter)(&bounds) {
self.c_depth += 1;
self.zones.push((id.clone(), bounds));
}
}
self.goto_next = match &self.max_depth {
Some(m_depth) => self.c_depth < *m_depth,
None => true,
};
}
fn scrollable(
&mut self,
_id: Option<&Id>,
bounds: Rectangle,
_content_bounds: Rectangle,
translation: Vector,
_state: &mut dyn Scrollable,
) {
if (self.filter)(&bounds) {
self.offset += translation;
}
}
fn finish(&self) -> Outcome<Vec<(Id, Rectangle)>> {
Outcome::Some(self.zones.clone())
}
}
FindDropZone {
filter,
options,
zones: vec![],
max_depth: depth,
c_depth: 0,
offset: Vector { x: 0.0, y: 0.0 },
goto_next: false,
}
}