use std::any::Any;
use std::collections::HashMap;
use crate::core::Rectangle;
use crate::core::widget;
use crate::core::widget::Operation;
use crate::core::widget::operation::Outcome;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Id(pub(crate) widget::Id);
impl Id {
pub fn new(id: impl Into<widget::Id>) -> Self {
Self(id.into())
}
pub fn unique() -> Self {
Self(widget::Id::unique())
}
}
impl From<Id> for widget::Id {
fn from(id: Id) -> Self {
id.0
}
}
pub trait Position {
fn set(&mut self, index: usize, bounds: Rectangle);
fn get(&self, index: usize) -> Option<Rectangle>;
fn clear(&mut self);
}
pub struct State(Box<dyn Position>);
impl Default for State {
fn default() -> Self {
Self(Box::new(PositionMap::default()))
}
}
impl State {
pub fn get(&self, index: usize) -> Option<Rectangle> {
self.0.get(index)
}
pub fn set(&mut self, index: usize, bounds: Rectangle) {
self.0.set(index, bounds);
}
pub fn clear(&mut self) {
self.0.clear();
}
}
#[derive(Default)]
struct PositionMap(HashMap<usize, Rectangle>);
impl Position for PositionMap {
fn set(&mut self, index: usize, bounds: Rectangle) {
self.0.insert(index, bounds);
}
fn get(&self, index: usize) -> Option<Rectangle> {
self.0.get(&index).copied()
}
fn clear(&mut self) {
self.0.clear();
}
}
pub fn find_position(
target: Id,
index: usize,
) -> iced_runtime::Task<Option<Rectangle>> {
iced_runtime::task::widget(FindPosition {
target,
index,
result: None,
})
}
struct FindPosition {
target: Id,
index: usize,
result: Option<Option<Rectangle>>,
}
impl Operation<Option<Rectangle>> for FindPosition {
fn traverse(
&mut self,
operate: &mut dyn FnMut(&mut dyn Operation<Option<Rectangle>>),
) {
if self.result.is_none() {
operate(self);
}
}
fn custom(
&mut self,
id: Option<&widget::Id>,
_bounds: Rectangle,
state: &mut dyn Any,
) {
if self.result.is_none()
&& let Some(id) = id
&& *id == self.target.0
&& let Some(positions) = state.downcast_ref::<State>()
{
self.result = Some(positions.get(self.index));
}
}
fn finish(&self) -> Outcome<Option<Rectangle>> {
match self.result {
Some(result) => Outcome::Some(result),
None => Outcome::None,
}
}
}