use std::cell::RefCell;
use egui::Pos2;
use crate::{InPinId, Node, OutPinId, Treeize, wire_pins};
pub enum Effect<T> {
InsertNode { pos: Pos2, node: T },
RemoveNode { node: NodeId },
OpenNode { node: NodeId, open: bool },
Connect { from: OutPinId, to: InPinId },
Disconnect { from: OutPinId, to: InPinId },
DropOutputs { pin: OutPinId },
DropInputs { pin: InPinId },
Closure(Box<dyn FnOnce(&mut Treeize<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 is_empty(&self) -> bool {
self.effects.is_empty()
}
#[inline(always)]
pub fn insert_node(&mut self, pos: Pos2, node: T) {
self.effects.push(Effect::InsertNode { node, pos });
}
#[inline(always)]
pub fn remove_node(&mut self, node: NodeId) {
self.effects.push(Effect::RemoveNode { node });
}
#[inline(always)]
pub fn open_node(&mut self, node: NodeId, open: bool) {
self.effects.push(Effect::OpenNode { node, open });
}
#[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 });
}
}
impl<T> Treeize<T> {
pub fn apply_effects(&mut self, effects: Effects<T>) {
if effects.effects.is_empty() {
return;
}
for effect in effects.effects {
self.apply_effect(effect);
}
}
pub fn apply_effect(&mut self, effect: Effect<T>) {
match effect {
Effect::InsertNode { node, pos } => {
let idx = self.nodes.insert(Node { value: RefCell::new(node), pos, open: true });
self.draw_order.push(idx);
}
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::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::Closure(f) => f(self),
}
}
}