use std::cell::RefCell;
use egui::{Context, Pos2};
use crate::{wire_pins, InPinId, Node, OutPinId, Snarl};
pub struct Forbidden;
pub enum Effect<T> {
Insert { node: T, pos: Pos2 },
Connect { from: OutPinId, to: InPinId },
Disconnect { from: OutPinId, to: InPinId },
DropOutputs { pin: OutPinId },
DropInputs { pin: InPinId },
RemoveNode { node: usize },
OpenNode { node: usize, open: bool },
Closure(Box<dyn FnOnce(&mut Snarl<T>)>),
}
pub struct Effects<T> {
effects: Vec<Effect<T>>,
}
impl<T> Default for Effects<T> {
#[inline]
fn default() -> Self {
Effects {
effects: Default::default(),
}
}
}
impl<T> Effects<T> {
#[inline(always)]
#[doc(hidden)]
pub fn new() -> Self {
Effects {
effects: Vec::new(),
}
}
#[inline(always)]
pub fn insert(&mut self, node: T, pos: Pos2) {
self.effects.push(Effect::Insert { node, pos });
}
#[inline(always)]
pub fn connect(&mut self, from: OutPinId, to: InPinId) {
self.effects.push(Effect::Connect { from, to });
}
#[inline(always)]
pub fn disconnect(&mut self, from: OutPinId, to: InPinId) {
self.effects.push(Effect::Disconnect { from, to });
}
#[inline(always)]
pub fn drop_inputs(&mut self, pin: InPinId) {
self.effects.push(Effect::DropInputs { pin });
}
#[inline(always)]
pub fn drop_outputs(&mut self, pin: OutPinId) {
self.effects.push(Effect::DropOutputs { pin });
}
#[inline(always)]
pub fn remove_node(&mut self, node: usize) {
self.effects.push(Effect::RemoveNode { node });
}
#[inline(always)]
pub fn open_node(&mut self, node: usize, open: bool) {
self.effects.push(Effect::OpenNode { node, open });
}
}
impl<T> Snarl<T> {
pub(crate) fn apply_effects(&mut self, effects: Effects<T>, cx: &Context) {
if effects.effects.is_empty() {
return;
}
cx.request_repaint();
for effect in effects.effects {
self.apply_effect(effect);
}
}
fn apply_effect(&mut self, effect: Effect<T>) {
match effect {
Effect::Insert { node, pos } => {
let idx = self.nodes.insert(Node {
value: RefCell::new(node),
pos,
open: true,
});
self.draw_order.push(idx);
}
Effect::Connect { from, to } => {
if self.nodes.contains(from.node) && self.nodes.contains(to.node) {
self.wires.insert(wire_pins(from, to));
}
}
Effect::Disconnect { from, to } => {
if self.nodes.contains(from.node) && self.nodes.contains(to.node) {
self.wires.remove(&wire_pins(from, to));
}
}
Effect::DropOutputs { pin } => {
if self.nodes.contains(pin.node) {
self.wires.drop_outputs(pin);
}
}
Effect::DropInputs { pin } => {
if self.nodes.contains(pin.node) {
self.wires.drop_inputs(pin);
}
}
Effect::RemoveNode { node } => {
if self.nodes.contains(node) {
self.remove_node(node);
}
}
Effect::OpenNode { node, open } => {
if self.nodes.contains(node) {
self.nodes[node].open = open;
}
}
Effect::Closure(f) => f(self),
}
}
}