use std::any::{Any, TypeId};
use std::cell::Cell;
use std::collections::{HashMap, VecDeque};
use std::hash::Hash;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex, Weak};
use utils::{iter_diff, IterDiff};
use {color, widget, Color, Colorable, Point, Positionable, Scalar, Ui, UiCell, Widget};
pub use self::node::{Node, SocketLayout, SocketSide};
pub mod node;
pub trait NodeId: 'static + Copy + Clone + PartialEq + Eq + Hash + Send {}
impl<T> NodeId for T where T: 'static + Copy + Clone + PartialEq + Eq + Hash + Send {}
#[derive(Clone, Debug, PartialEq)]
pub struct Layout<NI>
where
NI: Eq + Hash,
{
map: HashMap<NI, Point>,
}
impl<NI> Deref for Layout<NI>
where
NI: NodeId,
{
type Target = HashMap<NI, Point>;
fn deref(&self) -> &Self::Target {
&self.map
}
}
impl<NI> DerefMut for Layout<NI>
where
NI: NodeId,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.map
}
}
#[derive(Clone, Debug, WidgetCommon_)]
pub struct Graph<'a, N, E>
where
N: Iterator,
N::Item: NodeId,
E: Iterator<Item = (NodeSocket<N::Item>, NodeSocket<N::Item>)>,
{
#[conrod(common_builder)]
pub common: widget::CommonBuilder,
pub style: Style,
pub nodes: N,
pub edges: E,
pub layout: &'a Layout<N::Item>,
}
#[derive(Copy, Clone, Debug, Default, PartialEq, WidgetStyle_)]
pub struct Style {
#[conrod(default = "color::TRANSPARENT")]
pub background_color: Option<Color>,
}
widget_ids! {
struct Ids {
background,
}
}
pub struct State<NI>
where
NI: NodeId,
{
ids: Ids,
shared: Arc<Mutex<Shared<NI>>>,
}
struct Shared<NI>
where
NI: NodeId,
{
events: VecDeque<Event<NI>>,
nodes: HashMap<NI, NodeInner>,
node_ids: Vec<NI>,
edges: Vec<(NodeSocket<NI>, NodeSocket<NI>)>,
widget_id_map: WidgetIdMap<NI>,
}
#[derive(Copy, Clone, Debug)]
struct SocketLayouts {
input: SocketLayout,
output: SocketLayout,
}
#[derive(Default)]
struct TypeWidgetIds {
next_index: usize,
widget_ids: Vec<widget::Id>,
}
impl TypeWidgetIds {
fn next_id(&mut self, generator: &mut widget::id::Generator) -> widget::Id {
loop {
match self.widget_ids.get(self.next_index).map(|&id| id) {
None => self.widget_ids.push(generator.next()),
Some(id) => {
self.next_index += 1;
break id;
}
}
}
}
}
#[derive(Default)]
struct WidgetIdMap<NI>
where
NI: NodeId,
{
type_widget_ids: HashMap<TypeId, TypeWidgetIds>,
node_widget_ids: HashMap<NI, widget::Id>,
}
impl<NI> WidgetIdMap<NI>
where
NI: NodeId,
{
fn reset_indices(&mut self) {
for type_widget_ids in self.type_widget_ids.values_mut() {
type_widget_ids.next_index = 0;
}
}
fn clear_node_mappings(&mut self) {
self.node_widget_ids.clear();
}
fn next_id_for_node<T>(
&mut self,
node_id: NI,
generator: &mut widget::id::Generator,
) -> widget::Id
where
T: Any,
{
let type_id = TypeId::of::<T>();
let type_widget_ids = self
.type_widget_ids
.entry(type_id)
.or_insert_with(TypeWidgetIds::default);
let widget_id = type_widget_ids.next_id(generator);
self.node_widget_ids.insert(node_id, widget_id);
widget_id
}
fn next_id_for_edge<T>(&mut self, generator: &mut widget::id::Generator) -> widget::Id
where
T: Any,
{
let type_id = TypeId::of::<T>();
let type_widget_ids = self
.type_widget_ids
.entry(type_id)
.or_insert_with(TypeWidgetIds::default);
let widget_id = type_widget_ids.next_id(generator);
widget_id
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Event<NI> {
Node(NodeEvent<NI>),
Edge(EdgeEvent<NI>),
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct NodeSocket<NI> {
pub id: NI,
pub socket_index: usize,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum NodeEvent<NI> {
Remove(NI),
Dragged {
node_id: NI,
from: Point,
to: Point,
},
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum EdgeEvent<NI> {
AddStart(NodeSocket<NI>),
Add {
start: NodeSocket<NI>,
end: NodeSocket<NI>,
},
Cancelled(NodeSocket<NI>),
Remove {
start: NodeSocket<NI>,
end: NodeSocket<NI>,
},
}
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct Camera {
point: Point,
zoom: Scalar,
}
pub struct Session<NI: NodeId> {
graph_id: widget::Id,
shared: Weak<Mutex<Shared<NI>>>,
}
pub struct SessionEvents<NI: NodeId> {
session: Session<NI>,
}
pub struct SessionNodes<NI: NodeId> {
session: Session<NI>,
}
pub struct SessionEdges<NI: NodeId> {
session: Session<NI>,
}
pub struct Events<'a, NI: NodeId> {
shared: Arc<Mutex<Shared<NI>>>,
lifetime: PhantomData<&'a ()>,
}
pub struct Nodes<'a, NI: 'a + NodeId> {
index: usize,
shared: Arc<Mutex<Shared<NI>>>,
graph_id: widget::Id,
lifetime: PhantomData<&'a NI>,
}
#[derive(Copy, Clone)]
struct NodeInner {
point: Point,
}
pub struct NodeContext<'a, NI: 'a + NodeId> {
node_id: NI,
point: Point,
graph_id: widget::Id,
shared: Arc<Mutex<Shared<NI>>>,
lifetime: PhantomData<&'a NI>,
}
pub struct NodeWidget<'a, NI: 'a + NodeId, W> {
node: NodeContext<'a, NI>,
widget: W,
widget_id: Cell<Option<widget::Id>>,
}
pub struct Edges<'a, NI: 'a + NodeId> {
index: usize,
shared: Arc<Mutex<Shared<NI>>>,
graph_id: widget::Id,
lifetime: PhantomData<&'a ()>,
}
pub struct Edge<'a, NI: NodeId> {
graph_id: widget::Id,
shared: Arc<Mutex<Shared<NI>>>,
start: NodeSocket<NI>,
end: NodeSocket<NI>,
lifetime: PhantomData<&'a ()>,
}
pub struct EdgeWidget<'a, NI: 'a + NodeId, W> {
edge: Edge<'a, NI>,
widget: W,
widget_id: Cell<Option<widget::Id>>,
}
impl<NI> From<HashMap<NI, Point>> for Layout<NI>
where
NI: NodeId,
{
fn from(map: HashMap<NI, Point>) -> Self {
Layout { map }
}
}
impl<NI> Into<HashMap<NI, Point>> for Layout<NI>
where
NI: NodeId,
{
fn into(self) -> HashMap<NI, Point> {
let Layout { map } = self;
map
}
}
impl<NI> SessionEvents<NI>
where
NI: NodeId,
{
pub fn events(&self) -> Events<NI> {
let shared = self
.session
.shared
.upgrade()
.expect("failed to access `Shared` state");
Events {
shared,
lifetime: PhantomData,
}
}
pub fn next(self) -> SessionNodes<NI> {
let SessionEvents { session } = self;
SessionNodes { session }
}
}
impl<'a, NI> Iterator for Events<'a, NI>
where
NI: NodeId,
{
type Item = Event<NI>;
fn next(&mut self) -> Option<Self::Item> {
self.shared
.lock()
.ok()
.and_then(|mut guard| guard.events.pop_front())
}
}
impl<NI> SessionNodes<NI>
where
NI: NodeId,
{
pub fn nodes(&mut self) -> Nodes<NI> {
let graph_id = self.session.graph_id;
let shared = self
.session
.shared
.upgrade()
.expect("failed to access `Shared` state");
Nodes {
index: 0,
shared,
graph_id,
lifetime: PhantomData,
}
}
pub fn next(self) -> SessionEdges<NI> {
let SessionNodes { session } = self;
SessionEdges { session }
}
}
impl<'a, NI> Iterator for Nodes<'a, NI>
where
NI: NodeId,
{
type Item = NodeContext<'a, NI>;
fn next(&mut self) -> Option<Self::Item> {
let index = self.index;
self.index += 1;
self.shared
.lock()
.ok()
.and_then(|guard| {
guard
.node_ids
.get(index)
.and_then(|&id| guard.nodes.get(&id).map(|&inner| (id, inner)))
})
.map(|(node_id, NodeInner { point })| NodeContext {
node_id,
point,
graph_id: self.graph_id,
shared: self.shared.clone(),
lifetime: PhantomData,
})
}
}
impl<NI> SessionEdges<NI>
where
NI: NodeId,
{
pub fn edges(&mut self) -> Edges<NI> {
let graph_id = self.session.graph_id;
let shared = self
.session
.shared
.upgrade()
.expect("failed to access `Shared` state");
Edges {
index: 0,
shared,
graph_id,
lifetime: PhantomData,
}
}
}
impl<'a, NI> Iterator for Edges<'a, NI>
where
NI: NodeId,
{
type Item = Edge<'a, NI>;
fn next(&mut self) -> Option<Self::Item> {
let index = self.index;
self.index += 1;
self.shared.lock().ok().and_then(|guard| {
guard.edges.get(index).map(|&(start, end)| Edge {
graph_id: self.graph_id,
shared: self.shared.clone(),
start: start,
end: end,
lifetime: PhantomData,
})
})
}
}
impl<'a, NI> NodeContext<'a, NI>
where
NI: NodeId,
{
pub fn node_id(&self) -> NI {
self.node_id
}
pub fn point(&self) -> Point {
self.point
}
pub fn widget<W>(self, widget: W) -> NodeWidget<'a, NI, W> {
NodeWidget {
node: self,
widget,
widget_id: Cell::new(None),
}
}
}
impl<'a, NI, W> NodeWidget<'a, NI, W>
where
NI: NodeId,
W: 'static + Widget,
{
pub fn widget_id(&self, ui: &mut UiCell) -> widget::Id {
match self.widget_id.get() {
Some(id) => id,
None => {
let mut shared = self.node.shared.lock().unwrap();
let id = shared
.widget_id_map
.next_id_for_node::<W>(self.node_id, &mut ui.widget_id_generator());
self.widget_id.set(Some(id));
id
}
}
}
pub fn map<M>(self, map: M) -> Self
where
M: FnOnce(W) -> W,
{
let NodeWidget {
node,
mut widget,
widget_id,
} = self;
widget = map(widget);
NodeWidget {
node,
widget,
widget_id,
}
}
pub fn set(self, ui: &mut UiCell) -> W::Event {
let widget_id = self.widget_id(ui);
let NodeWidget { node, widget, .. } = self;
widget
.xy_relative_to(node.graph_id, node.point)
.parent(node.graph_id)
.set(widget_id, ui)
}
}
impl<'a, NI, W> Deref for NodeWidget<'a, NI, W>
where
NI: NodeId,
{
type Target = NodeContext<'a, NI>;
fn deref(&self) -> &Self::Target {
&self.node
}
}
impl<'a, NI> Edge<'a, NI>
where
NI: NodeId,
{
pub fn start(&self) -> NodeSocket<NI> {
self.start
}
pub fn end(&self) -> NodeSocket<NI> {
self.end
}
pub fn sockets(&self) -> (NodeSocket<NI>, NodeSocket<NI>) {
(self.start, self.end)
}
pub fn widget<W>(self, widget: W) -> EdgeWidget<'a, NI, W> {
EdgeWidget {
edge: self,
widget,
widget_id: Cell::new(None),
}
}
}
pub fn node_widget_id<NI>(node_id: NI, graph_id: widget::Id, ui: &Ui) -> Option<widget::Id>
where
NI: NodeId,
{
ui.widget_graph()
.widget(graph_id)
.and_then(|container| container.state_and_style::<State<NI>, Style>())
.and_then(|unique| {
let shared = unique.state.shared.lock().unwrap();
shared
.widget_id_map
.node_widget_ids
.get(&node_id)
.map(|&id| id)
})
}
pub fn edge_node_widget_ids<NI>(edge: &Edge<NI>, ui: &Ui) -> (widget::Id, widget::Id)
where
NI: NodeId,
{
ui.widget_graph()
.widget(edge.graph_id)
.and_then(|container| container.state_and_style::<State<NI>, Style>())
.map(|unique| {
let shared = unique.state.shared.lock().unwrap();
let a = shared
.widget_id_map
.node_widget_ids
.get(&edge.start.id)
.map(|&id| id);
let b = shared
.widget_id_map
.node_widget_ids
.get(&edge.end.id)
.map(|&id| id);
(
a.expect("no `widget::Id` for start node"),
b.expect("no `widget::Id` for end node"),
)
})
.expect("no graph associated with edge's `graph_id` was found")
}
impl<'a, NI, W> EdgeWidget<'a, NI, W>
where
NI: NodeId,
W: 'static + Widget,
{
pub fn widget_id(&self, ui: &mut UiCell) -> widget::Id {
match self.widget_id.get() {
Some(id) => id,
None => {
let mut shared = self.edge.shared.lock().unwrap();
let id = shared
.widget_id_map
.next_id_for_edge::<W>(&mut ui.widget_id_generator());
self.widget_id.set(Some(id));
id
}
}
}
pub fn map<M>(self, map: M) -> Self
where
M: FnOnce(W) -> W,
{
let EdgeWidget {
edge,
mut widget,
widget_id,
} = self;
widget = map(widget);
EdgeWidget {
edge,
widget,
widget_id,
}
}
pub fn set(self, ui: &mut UiCell) -> W::Event {
let widget_id = self.widget_id(ui);
let EdgeWidget { edge, widget, .. } = self;
widget.parent(edge.graph_id).set(widget_id, ui)
}
}
impl<'a, N, E> Graph<'a, N, E>
where
N: Iterator,
N::Item: NodeId,
E: Iterator<Item = (NodeSocket<N::Item>, NodeSocket<N::Item>)>,
{
pub fn new<NI, EI>(nodes: NI, edges: EI, layout: &'a Layout<NI::Item>) -> Self
where
NI: IntoIterator<IntoIter = N, Item = N::Item>,
EI: IntoIterator<IntoIter = E, Item = (NodeSocket<N::Item>, NodeSocket<N::Item>)>,
{
Graph {
common: widget::CommonBuilder::default(),
style: Style::default(),
nodes: nodes.into_iter(),
edges: edges.into_iter(),
layout: layout,
}
}
pub fn background_color(mut self, color: Color) -> Self {
self.style.background_color = Some(color);
self
}
}
impl<'a, N, E> Widget for Graph<'a, N, E>
where
N: Iterator,
N::Item: NodeId,
E: Iterator<Item = (NodeSocket<N::Item>, NodeSocket<N::Item>)>,
{
type State = State<N::Item>;
type Style = Style;
type Event = SessionEvents<N::Item>;
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
let events = VecDeque::new();
let nodes = HashMap::new();
let node_ids = Vec::new();
let edges = Vec::new();
let type_widget_ids = HashMap::new();
let node_widget_ids = HashMap::new();
let widget_id_map = WidgetIdMap {
type_widget_ids,
node_widget_ids,
};
let shared = Shared {
events,
nodes,
node_ids,
edges,
widget_id_map,
};
State {
ids: Ids::new(id_gen),
shared: Arc::new(Mutex::new(shared)),
}
}
fn style(&self) -> Self::Style {
self.style.clone()
}
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
let widget::UpdateArgs {
id,
state,
style,
rect,
ui,
..
} = args;
let Graph {
nodes,
edges,
layout,
..
} = self;
let mut shared = state.shared.lock().unwrap();
shared.widget_id_map.reset_indices();
match iter_diff(&shared.node_ids, nodes) {
Some(diff) => match diff {
IterDiff::FirstMismatch(i, mismatch) => {
shared.node_ids.truncate(i);
shared.node_ids.extend(mismatch);
}
IterDiff::Longer(remaining) => {
shared.node_ids.extend(remaining);
}
IterDiff::Shorter(total) => {
shared.node_ids.truncate(total);
}
},
None => (),
}
match iter_diff(&shared.edges, edges) {
Some(diff) => match diff {
IterDiff::FirstMismatch(i, mismatch) => {
shared.edges.truncate(i);
shared.edges.extend(mismatch);
}
IterDiff::Longer(remaining) => {
shared.edges.extend(remaining);
}
IterDiff::Shorter(total) => {
shared.edges.truncate(total);
}
},
None => (),
}
shared.nodes.clear();
for i in 0..shared.node_ids.len() {
let node_id = shared.node_ids[i];
let point = layout.map.get(&node_id).map(|&p| p).unwrap_or([0.0; 2]);
let point = match shared
.widget_id_map
.node_widget_ids
.get(&node_id)
.map(|&w| w)
{
None => point,
Some(widget_id) => {
let (dragged_x, dragged_y) = ui
.widget_input(widget_id)
.drags()
.left()
.fold((0.0, 0.0), |(x, y), d| {
(x + d.delta_xy[0], y + d.delta_xy[1])
});
if dragged_x == 0.0 && dragged_y == 0.0 {
point
} else {
let to = [point[0] + dragged_x, point[1] + dragged_y];
let node_event = NodeEvent::Dragged {
node_id,
from: point,
to,
};
let event = Event::Node(node_event);
shared.events.push_back(event);
to
}
}
};
let node = NodeInner { point };
shared.nodes.insert(node_id, node);
}
let background_color = style.background_color(&ui.theme);
widget::Rectangle::fill(rect.dim())
.xy(rect.xy())
.color(background_color)
.parent(id)
.graphics_for(id)
.set(state.ids.background, ui);
shared.widget_id_map.clear_node_mappings();
let graph_id = id;
let shared = Arc::downgrade(&state.shared);
let session = Session { graph_id, shared };
SessionEvents { session }
}
}