use super::{Graph, Node};
use daggy::Walker;
use fnv;
use std;
use widget;
#[derive(Debug)]
pub struct DepthOrder {
pub indices: Vec<widget::Id>,
floating: Vec<widget::Id>,
}
impl DepthOrder {
pub fn new() -> DepthOrder {
DepthOrder {
indices: Vec::new(),
floating: Vec::new(),
}
}
pub fn with_node_capacity(n_nodes: usize) -> DepthOrder {
let n_indices = n_nodes * 2;
DepthOrder {
indices: Vec::with_capacity(n_indices),
floating: Vec::with_capacity(n_nodes),
}
}
pub fn update(
&mut self,
graph: &Graph,
root: widget::Id,
updated_widgets: &fnv::FnvHashSet<widget::Id>,
) {
let DepthOrder {
ref mut indices,
ref mut floating,
} = *self;
let num_nodes = graph.node_count();
indices.clear();
indices.reserve(num_nodes);
floating.clear();
floating.reserve(num_nodes);
visit_by_depth(graph, root, updated_widgets, indices, floating);
floating.sort_by(|&a, &b| match (&graph[a], &graph[b]) {
(&Node::Widget(ref a), &Node::Widget(ref b)) => {
let a_floating = a.maybe_floating.expect("Not floating");
let b_floating = b.maybe_floating.expect("Not floating");
a_floating
.time_last_clicked
.cmp(&b_floating.time_last_clicked)
}
_ => std::cmp::Ordering::Equal,
});
while !floating.is_empty() {
let idx = floating.remove(0);
visit_by_depth(graph, idx, updated_widgets, indices, floating);
}
}
}
fn visit_by_depth(
graph: &Graph,
idx: widget::Id,
updated_widgets: &fnv::FnvHashSet<widget::Id>,
depth_order: &mut Vec<widget::Id>,
floating_deque: &mut Vec<widget::Id>,
) {
match graph.widget(idx).is_some() && updated_widgets.contains(&idx) {
true => depth_order.push(idx),
false => return,
}
let mut child_sorter: Vec<widget::Id> =
graph.depth_children(idx).iter(&graph).nodes().collect();
child_sorter.sort_by(|&a, &b| {
use std::cmp::Ordering;
if let (&Node::Widget(ref a), &Node::Widget(ref b)) = (&graph[a], &graph[b]) {
match b.depth.partial_cmp(&a.depth).expect("Depth was NaN!") {
Ordering::Equal => a.instantiation_order_idx.cmp(&b.instantiation_order_idx),
ordering => ordering,
}
} else {
Ordering::Equal
}
});
for child_idx in child_sorter.into_iter() {
let maybe_is_floating = graph.widget(child_idx).map(|w| w.maybe_floating.is_some());
match maybe_is_floating {
Some(true) => floating_deque.push(child_idx),
_ => visit_by_depth(
graph,
child_idx,
updated_widgets,
depth_order,
floating_deque,
),
}
}
}