summaryrefslogtreecommitdiff
path: root/iced_drop/src/widget/operation/drop.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--iced_drop/src/widget/operation/drop.rs89
1 files changed, 89 insertions, 0 deletions
diff --git a/iced_drop/src/widget/operation/drop.rs b/iced_drop/src/widget/operation/drop.rs
new file mode 100644
index 0000000..12a2e30
--- /dev/null
+++ b/iced_drop/src/widget/operation/drop.rs
@@ -0,0 +1,89 @@
+use iced::{
+ advanced::widget::{
+ operation::{Outcome, Scrollable},
+ Id, Operation,
+ },
+ Rectangle, Vector,
+};
+
+/// Produces an [`Operation`] that will find the drop zones that pass a filter on the zone's bounds.
+/// For any drop zone to be considered, the Element must have some Id.
+/// If `options` is `None`, all drop zones will be considered.
+/// Depth determines how how deep into nested drop zones to go.
+/// If 'depth' is `None`, nested dropzones will be fully explored
+pub fn find_zones<F>(
+ filter: F,
+ options: Option<Vec<Id>>,
+ depth: Option<usize>,
+) -> impl Operation<Vec<(Id, Rectangle)>>
+where
+ F: Fn(&Rectangle) -> bool + 'static,
+{
+ struct FindDropZone<F> {
+ filter: F,
+ options: Option<Vec<Id>>,
+ zones: Vec<(Id, Rectangle)>,
+ max_depth: Option<usize>,
+ c_depth: usize,
+ offset: Vector,
+ }
+
+ impl<F> Operation<Vec<(Id, Rectangle)>> for FindDropZone<F>
+ where
+ F: Fn(&Rectangle) -> bool + 'static,
+ {
+ fn container(
+ &mut self,
+ id: Option<&Id>,
+ bounds: iced::Rectangle,
+ operate_on_children: &mut dyn FnMut(&mut dyn Operation<Vec<(Id, Rectangle)>>),
+ ) {
+ match id {
+ Some(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));
+ }
+ }
+ None => (),
+ }
+ let goto_next = match &self.max_depth {
+ Some(m_depth) => self.c_depth < *m_depth,
+ None => true,
+ };
+ if goto_next {
+ operate_on_children(self);
+ }
+ }
+
+ fn finish(&self) -> Outcome<Vec<(Id, Rectangle)>> {
+ Outcome::Some(self.zones.clone())
+ }
+
+ fn scrollable(
+ &mut self,
+ _state: &mut dyn Scrollable,
+ _id: Option<&Id>,
+ bounds: Rectangle,
+ translation: Vector,
+ ) {
+ if (self.filter)(&bounds) {
+ self.offset = self.offset + translation;
+ }
+ }
+ }
+
+ FindDropZone {
+ filter,
+ options,
+ zones: vec![],
+ max_depth: depth,
+ c_depth: 0,
+ offset: Vector { x: 0.0, y: 0.0 },
+ }
+}