use daggy::Walker;
use position::{Point, Rect};
use fnv;
use super::{EdgeIndex, Graph};
use widget;
#[derive(Clone)]
#[allow(missing_copy_implementations)]
pub struct PickWidgets {
xy: Point,
idx: usize,
}
#[derive(Clone)]
#[allow(missing_copy_implementations)]
pub struct PickScrollableWidgets {
pick_widgets: PickWidgets,
}
impl PickWidgets {
pub fn next_including_graphics_children(&mut self,
graph: &Graph,
depth_order: &[widget::Id]) -> Option<widget::Id>
{
while self.idx > 0 {
self.idx -= 1;
match depth_order.get(self.idx) {
None => break,
Some(&idx) => {
if let Some(visible_rect) = cropped_area_of_widget(graph, idx) {
if visible_rect.is_over(self.xy) {
return Some(idx);
}
}
},
}
}
None
}
pub fn next(&mut self, graph: &Graph, depth_order: &[widget::Id]) -> Option<widget::Id> {
self.next_including_graphics_children(graph, depth_order)
.map(|idx| {
graph.graphic_parent_recursion(idx)
.last_node(graph)
.unwrap_or(idx)
})
}
}
impl PickScrollableWidgets {
pub fn next(&mut self, graph: &Graph, depth_order: &[widget::Id]) -> Option<widget::Id> {
while let Some(idx) = self.pick_widgets.next_including_graphics_children(graph, depth_order) {
if let Some(ref container) = graph.widget(idx) {
if container.maybe_x_scroll_state.is_some()
|| container.maybe_y_scroll_state.is_some() {
return Some(idx)
}
}
}
None
}
}
pub fn pick_widgets(depth_order: &[widget::Id], xy: Point) -> PickWidgets {
PickWidgets {
xy: xy,
idx: depth_order.len(),
}
}
pub fn pick_scrollable_widgets(depth_order: &[widget::Id], xy: Point) -> PickScrollableWidgets {
PickScrollableWidgets {
pick_widgets: pick_widgets(depth_order, xy),
}
}
pub fn cropped_area_of_widget(graph: &Graph, idx: widget::Id) -> Option<Rect> {
cropped_area_of_widget_maybe_within_depth(graph, idx, None)
}
pub fn cropped_area_of_widget_within_depth(graph: &Graph,
idx: widget::Id,
deepest_parent_idx: widget::Id) -> Option<Rect>
{
cropped_area_of_widget_maybe_within_depth(graph, idx, Some(deepest_parent_idx))
}
fn cropped_area_of_widget_maybe_within_depth(graph: &Graph,
mut id: widget::Id,
deepest_id: Option<widget::Id>) -> Option<Rect>
{
graph.widget(id).and_then(|widget| {
let mut overlapping_rect = widget.rect;
let mut depth_parents = graph.depth_parent_recursion(id);
while let Some(depth_parent) = depth_parents.next_node(graph) {
if Some(depth_parent) == deepest_id {
break;
}
if let Some(depth_parent_widget) = graph.widget(depth_parent) {
if depth_parent_widget.maybe_x_scroll_state.is_some()
|| depth_parent_widget.maybe_y_scroll_state.is_some() {
if !graph.does_graphic_edge_exist(depth_parent, id) {
match overlapping_rect.overlap(depth_parent_widget.kid_area.rect) {
Some(overlap) => overlapping_rect = overlap,
None => return None,
}
}
}
}
id = depth_parent;
}
Some(overlapping_rect)
})
}
pub fn kids_bounding_box(graph: &Graph,
prev_updated: &fnv::FnvHashSet<widget::Id>,
idx: widget::Id) -> Option<Rect>
{
let kid_filter = &|g: &Graph, _e, n| -> bool {
let is_not_graphic_kid = !g.graphic_parent(n).is_some();
let is_set = prev_updated.contains(&n);
is_not_graphic_kid && is_set
};
fn kids_dfs<F>(graph: &Graph,
idx: widget::Id,
deepest_parent_idx: widget::Id,
kid_filter: &F) -> Option<Rect>
where F: Fn(&Graph, EdgeIndex, widget::Id) -> bool,
{
cropped_area_of_widget_within_depth(graph, idx, deepest_parent_idx).map(|rect| {
let kids_bounds = graph.depth_children(idx).filter(kid_filter).iter(graph).nodes()
.filter_map(|n| kids_dfs(graph, n, deepest_parent_idx, kid_filter));
kids_bounds.fold(rect, |max, next| max.max(next))
})
}
graph.widget(idx).and_then(|_| {
let mut kids_bounds = graph.depth_children(idx).filter(kid_filter).iter(graph).nodes()
.filter_map(|n| kids_dfs(graph, n, idx, kid_filter));
kids_bounds.next().map(|first| {
kids_bounds.fold(first, |max, next| max.max(next))
})
})
}
pub fn scroll_offset(graph: &Graph, idx: widget::Id) -> Point {
const NO_OFFSET: Point = [0.0, 0.0];
if let Some(depth_parent) = graph.depth_parent(idx) {
if let Some(depth_parent_widget) = graph.widget(depth_parent) {
if depth_parent_widget.maybe_x_scroll_state.is_some()
|| depth_parent_widget.maybe_y_scroll_state.is_some() {
if graph.graphic_parent_recursion(idx)
.any(graph, |_g, _e, n| n == depth_parent)
{
return NO_OFFSET;
}
let is_already_offset = |mut position_parents: super::RecursiveWalk<_>| {
while let Some(position_parent) = position_parents.next_node(graph) {
if graph.depth_parent_recursion(position_parent)
.any(graph, |_g, _e, n| n == depth_parent)
{
return true;
}
}
false
};
let x_offset = depth_parent_widget.maybe_x_scroll_state.map(|scroll| {
let position_parents = graph.x_position_parent_recursion(idx);
if is_already_offset(position_parents) { 0.0 } else { scroll.offset }
}).unwrap_or(0.0);
let y_offset = depth_parent_widget.maybe_y_scroll_state.map(|scroll| {
let position_parents = graph.y_position_parent_recursion(idx);
if is_already_offset(position_parents) { 0.0 } else { scroll.offset }
}).unwrap_or(0.0);
return [x_offset, y_offset];
}
}
}
NO_OFFSET
}