aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2025-12-27 10:52:42 +0000
committers-ol <s+removethis@s-ol.nu>2025-12-27 10:52:42 +0000
commit5fb707b4d872f3822dbb9a65c51408ca2ed0c39f (patch)
tree43a7edd02841c1474c30f57b5c31ec100f7952f8 /src
parentauto-recompile (diff)
downloadnodetoy-5fb707b4d872f3822dbb9a65c51408ca2ed0c39f.tar.gz
nodetoy-5fb707b4d872f3822dbb9a65c51408ca2ed0c39f.zip
NodeIndex type
Diffstat (limited to 'src')
-rw-r--r--src/library.rs71
-rw-r--r--src/main.rs60
2 files changed, 76 insertions, 55 deletions
diff --git a/src/library.rs b/src/library.rs
index 111f365..3402382 100644
--- a/src/library.rs
+++ b/src/library.rs
@@ -4,7 +4,8 @@ use serde::{Deserialize, Serialize};
use std::fmt;
use crate::{
- ConcreteNode, Dimension::*, FloatPrecision::*, ScalarType::*, Type, Type::*, TypeSignature,
+ ConcreteNode, Dimension, Dimension::*, FloatPrecision::*, ScalarType, ScalarType::*, Type,
+ Type::*, TypeSignature,
};
const GEN_F_TYPES: [Type; 4] = [
@@ -38,6 +39,26 @@ const _GEN_B_TYPES: [Type; 4] = [
Vector(Bool, D4),
];
+pub trait NodeIndex: Sized + fmt::Display {
+ const TITLE: &'static str;
+
+ fn all() -> impl Iterator<Item = Self>;
+
+ fn pick_node(ui: &mut egui::Ui) -> Option<Self> {
+ ui.menu_button(Self::TITLE, |ui| {
+ for node in Self::all() {
+ if ui.button(format!("{node}")).clicked() {
+ return Some(node);
+ }
+ }
+
+ None
+ })
+ .inner
+ .unwrap_or(None)
+ }
+}
+
/// Helper trait for Nodes with fixed number of inputs and outputs
trait FixedNode: fmt::Debug {
const NI: usize;
@@ -389,8 +410,10 @@ pub enum BuiltinFunction {
Mix(Mix),
}
-impl BuiltinFunction {
- pub fn all() -> impl Iterator<Item = Self> {
+impl NodeIndex for BuiltinFunction {
+ const TITLE: &'static str = "Builtin Functions";
+
+ fn all() -> impl Iterator<Item = Self> {
BinArithmetic::all()
.map(Self::from)
.chain(Thru1::all().map(Self::from))
@@ -451,10 +474,22 @@ impl FixedNode for Output {
}
}
}
-impl Output {
- pub fn all() -> impl Iterator<Item = Self> {
+impl NodeIndex for Output {
+ const TITLE: &'static str = "Output";
+
+ fn all() -> impl Iterator<Item = Self> {
std::iter::once(Output)
}
+
+ fn pick_node(ui: &mut egui::Ui) -> Option<Self> {
+ for node in Self::all() {
+ if ui.button(format!("{node}")).clicked() {
+ return Some(node);
+ }
+ }
+
+ None
+ }
}
impl fmt::Display for Output {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -468,7 +503,7 @@ trait Value: fmt::Display {
trait ScalarValue: fmt::Display {
type Raw;
- const SCALAR_TYPE: crate::ScalarType;
+ const SCALAR_TYPE: ScalarType;
fn make_widget(val: &mut Self::Raw) -> impl egui::Widget;
}
@@ -487,35 +522,35 @@ pub struct Constant<T>(T);
// scalar implementations
impl ScalarValue for Constant<f32> {
type Raw = f32;
- const SCALAR_TYPE: crate::ScalarType = Float(Single);
+ const SCALAR_TYPE: ScalarType = Float(Single);
fn make_widget(val: &mut Self::Raw) -> impl egui::Widget {
egui::DragValue::new(val).speed(0.1)
}
}
impl ScalarValue for Constant<f64> {
type Raw = f64;
- const SCALAR_TYPE: crate::ScalarType = Float(Double);
+ const SCALAR_TYPE: ScalarType = Float(Double);
fn make_widget(val: &mut Self::Raw) -> impl egui::Widget {
egui::DragValue::new(val).speed(0.1)
}
}
impl ScalarValue for Constant<i32> {
type Raw = i32;
- const SCALAR_TYPE: crate::ScalarType = Int;
+ const SCALAR_TYPE: ScalarType = Int;
fn make_widget(val: &mut Self::Raw) -> impl egui::Widget {
egui::DragValue::new(val)
}
}
impl ScalarValue for Constant<u32> {
type Raw = u32;
- const SCALAR_TYPE: crate::ScalarType = UInt;
+ const SCALAR_TYPE: ScalarType = UInt;
fn make_widget(val: &mut Self::Raw) -> impl egui::Widget {
egui::DragValue::new(val)
}
}
impl ScalarValue for Constant<bool> {
type Raw = bool;
- const SCALAR_TYPE: crate::ScalarType = Bool;
+ const SCALAR_TYPE: ScalarType = Bool;
fn make_widget(val: &mut Self::Raw) -> impl egui::Widget {
egui::Checkbox::without_text(val)
}
@@ -547,7 +582,7 @@ where
Constant<T>: ScalarValue,
T: fmt::Display,
{
- const TYPE: Type = Vector(Constant::<T>::SCALAR_TYPE, crate::Dimension::from(N));
+ const TYPE: Type = Vector(Constant::<T>::SCALAR_TYPE, Dimension::from(N));
}
impl<T, const N: usize> ValueEditor for Constant<[T; N]>
@@ -647,8 +682,10 @@ pub enum AnyConstant {
BVec4(Constant<[bool; 4]>),
}
-impl AnyConstant {
- pub fn all() -> impl Iterator<Item = Self> {
+impl NodeIndex for AnyConstant {
+ const TITLE: &'static str = "Constants";
+
+ fn all() -> impl Iterator<Item = Self> {
[
Self::Float(Default::default()),
Self::Vec2(Default::default()),
@@ -741,8 +778,10 @@ impl ConcreteNode for Input {
)
}
}
-impl Input {
- pub fn all() -> impl Iterator<Item = Input> {
+impl NodeIndex for Input {
+ const TITLE: &'static str = "Inputs";
+
+ fn all() -> impl Iterator<Item = Input> {
[
Input::UV,
// Input::Resolution,
diff --git a/src/main.rs b/src/main.rs
index 13096b2..a40fb21 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,6 +7,7 @@ use egui_snarl::{
ui::{NodeLayout, PinInfo, PinPlacement, SnarlStyle, SnarlViewer, SnarlWidget},
};
use enum_dispatch::enum_dispatch;
+use library::NodeIndex;
use log::*;
use std::fmt;
@@ -221,14 +222,30 @@ impl DemoNode {
let connected = self.get_input_types(node, snarl);
self.signature(&connected)
}
+}
+
+impl NodeIndex for DemoNode {
+ const TITLE: &'static str = "";
- pub fn all() -> impl Iterator<Item = Self> {
+ fn all() -> impl Iterator<Item = Self> {
(library::AnyConstant::all().map(DemoNode::from))
.chain(library::Input::all().map(DemoNode::from))
.chain(library::Output::all().map(DemoNode::from))
.chain(library::BuiltinFunction::all().map(DemoNode::from))
}
+
+ fn pick_node(ui: &mut egui::Ui) -> Option<Self> {
+ ui.label("Add node");
+
+ let a = library::AnyConstant::pick_node(ui).map(DemoNode::from);
+ let b = library::Input::pick_node(ui).map(DemoNode::from);
+ let c = library::Output::pick_node(ui).map(DemoNode::from);
+ let d = library::BuiltinFunction::pick_node(ui).map(DemoNode::from);
+
+ a.or(b).or(c).or(d)
+ }
}
+
impl fmt::Display for DemoNode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
@@ -377,38 +394,9 @@ impl SnarlViewer<DemoNode> for DemoViewer {
}
fn show_graph_menu(&mut self, pos: egui::Pos2, ui: &mut Ui, snarl: &mut Snarl<DemoNode>) {
- ui.label("Add node");
-
- ui.menu_button("Constants", |ui| {
- for node in library::AnyConstant::all() {
- if ui.button(format!("{node}")).clicked() {
- snarl.insert_node(pos, DemoNode::from(node));
- ui.close();
- }
- }
- });
- ui.menu_button("Inputs", |ui| {
- for node in library::Input::all() {
- if ui.button(format!("{node}")).clicked() {
- snarl.insert_node(pos, DemoNode::from(node));
- ui.close();
- }
- }
- });
- ui.menu_button("Builtins", |ui| {
- for node in library::BuiltinFunction::all() {
- if ui.button(format!("{node}")).clicked() {
- snarl.insert_node(pos, DemoNode::from(node));
- ui.close();
- }
- }
- });
-
- for node in library::Output::all() {
- if ui.button(format!("{node}")).clicked() {
- snarl.insert_node(pos, DemoNode::from(node));
- ui.close();
- }
+ if let Some(node) = DemoNode::pick_node(ui) {
+ snarl.insert_node(pos, node);
+ ui.close();
}
}
@@ -540,12 +528,6 @@ impl App for DemoApp {
egui::SidePanel::right("preview").show(ctx, |ui| {
egui::ScrollArea::vertical().show(ui, |ui| {
egui::Frame::canvas(ui.style()).show(ui, |ui| {
- // let shader = if self.viewer.dirty {
- // self.viewer.dirty = false;
- // } else {
- // None
- // };
-
self.preview.custom_painting(ui, shader);
});
});