Improve device panel

This commit is contained in:
hodasemi 2022-01-30 20:57:12 +01:00
parent b4625849f1
commit 0c4e217fa7
7 changed files with 103 additions and 53 deletions

View file

@ -4,9 +4,15 @@ use crate::color_hex_utils::*;
use crate::device::Device; use crate::device::Device;
use crate::editor_state::GraphEditorState; use crate::editor_state::GraphEditorState;
use crate::graph_node_ui::*; use crate::graph_node_ui::*;
use crate::node_finder::NodeFinder; use crate::node_finder::{NodeFinder, SelectedDevice};
use crate::virtual_device::VirtualDevice;
pub fn draw_graph_editor(ctx: &CtxRef, state: &mut GraphEditorState, devices: &[Device]) { pub fn draw_graph_editor(
ctx: &CtxRef,
state: &mut GraphEditorState,
devices: &[Device],
virtual_device: &mut Option<VirtualDevice>,
) {
let mouse = &ctx.input().pointer; let mouse = &ctx.input().pointer;
let cursor_pos = mouse.hover_pos().unwrap_or(Pos2::ZERO); let cursor_pos = mouse.hover_pos().unwrap_or(Pos2::ZERO);
@ -49,12 +55,17 @@ pub fn draw_graph_editor(ctx: &CtxRef, state: &mut GraphEditorState, devices: &[
node_finder_area = node_finder_area.current_pos(pos); node_finder_area = node_finder_area.current_pos(pos);
} }
node_finder_area.show(ctx, |ui| { node_finder_area.show(ctx, |ui| {
if let Some(node_device) = node_finder.show(devices, ui) { if let Some(node_device) = node_finder.show(devices, virtual_device.is_none(), ui) {
let new_node = state.graph.add_node(node_device.to_descriptor()); let new_node = state.graph.add_node(node_device.to_descriptor());
state state
.node_positions .node_positions
.insert(new_node, cursor_pos - state.pan_zoom.pan); .insert(new_node, cursor_pos - state.pan_zoom.pan);
should_close_node_finder = true; should_close_node_finder = true;
if let SelectedDevice::Virtual(mut virt) = node_device {
virt.connect_id(new_node);
*virtual_device = Some(virt);
}
} }
}); });
} }
@ -115,6 +126,12 @@ pub fn draw_graph_editor(ctx: &CtxRef, state: &mut GraphEditorState, devices: &[
state.run_side_effect = Some(node_id); state.run_side_effect = Some(node_id);
} }
DrawGraphNodeResponse::DeleteNode(node_id) => { DrawGraphNodeResponse::DeleteNode(node_id) => {
if let Some(virt) = virtual_device {
if node_id == virt.node_id() {
*virtual_device = None;
}
}
state.graph.remove_node(node_id); state.graph.remove_node(node_id);
state.node_positions.remove(&node_id); state.node_positions.remove(&node_id);
// Make sure to not leave references to old nodes hanging // Make sure to not leave references to old nodes hanging

View file

@ -159,10 +159,4 @@ impl Node {
.map(|x| x.1) .map(|x| x.1)
.ok_or_else(|| anyhow!("Node {:?} has no parameter named {}", self.id, name)) .ok_or_else(|| anyhow!("Node {:?} has no parameter named {}", self.id, name))
} }
// Can this node be enabled on the UI? I.e. does it output a mesh?
// pub fn can_be_enabled(&self, graph: &Graph) -> bool {
// self.outputs(graph)
// .any(|output| output.typ == DataType::Mesh)
// }
} }

View file

@ -114,34 +114,12 @@ impl<'a> GraphNodeWidget<'a> {
} }
let outputs = graph[node_id].outputs.clone(); let outputs = graph[node_id].outputs.clone();
for (param_name, _param) in outputs { for (param_name, param) in outputs {
let height_before = ui.min_rect().bottom(); let height_before = ui.min_rect().bottom();
ui.label(&param_name); graph.output(param).value_widget(&param_name, ui);
let height_after = ui.min_rect().bottom(); let height_after = ui.min_rect().bottom();
output_port_heights.push((height_before + height_after) / 2.0); output_port_heights.push((height_before + height_after) / 2.0);
} }
// // Button row
// ui.horizontal(|ui| {
// // Show 'Enable' button for nodes that output a mesh
// if graph[node_id].can_be_enabled(graph) {
// ui.horizontal(|ui| {
// if !active {
// if ui.button("👁 Set active").clicked() {
// response = Some(DrawGraphNodeResponse::SetActiveNode(node_id));
// }
// } else {
// let button = egui::Button::new(
// RichText::new("👁 Active").color(egui::Color32::BLACK),
// )
// .fill(egui::Color32::GOLD);
// if ui.add(button).clicked() {
// response = Some(DrawGraphNodeResponse::ClearActiveNode);
// }
// }
// });
// }
// })
}); });
// Second pass, iterate again to draw the ports. This happens outside // Second pass, iterate again to draw the ports. This happens outside
@ -162,6 +140,7 @@ impl<'a> GraphNodeWidget<'a> {
port_locations: &mut PortLocations, port_locations: &mut PortLocations,
ongoing_drag: Option<(NodeId, ID)>, ongoing_drag: Option<(NodeId, ID)>,
is_connected_input: bool, is_connected_input: bool,
color: Color32,
) { ) {
let port_rect = Rect::from_center_size(port_pos, egui::vec2(10.0, 10.0)); let port_rect = Rect::from_center_size(port_pos, egui::vec2(10.0, 10.0));
@ -175,7 +154,7 @@ impl<'a> GraphNodeWidget<'a> {
let port_color = if resp.hovered() { let port_color = if resp.hovered() {
Color32::WHITE Color32::WHITE
} else { } else {
color_from_hex("#4b7f52").unwrap() color
}; };
ui.painter() ui.painter()
.circle(port_rect.center(), 5.0, port_color, Stroke::none()); .circle(port_rect.center(), 5.0, port_color, Stroke::none());
@ -222,6 +201,7 @@ impl<'a> GraphNodeWidget<'a> {
port_locations, port_locations,
ongoing_drag, ongoing_drag,
graph.connection(*param).is_some(), graph.connection(*param).is_some(),
color_from_hex("#4b7f52").unwrap(),
); );
} }
} }
@ -243,6 +223,7 @@ impl<'a> GraphNodeWidget<'a> {
port_locations, port_locations,
ongoing_drag, ongoing_drag,
false, false,
color_from_hex("#cd131f").unwrap(),
); );
} }

View file

@ -12,20 +12,24 @@ mod id_types;
mod index_impls; mod index_impls;
mod node_finder; mod node_finder;
mod param_ui; mod param_ui;
mod virtual_device;
use device::Device; use device::Device;
use virtual_device::VirtualDevice;
#[derive(Default)] #[derive(Default)]
struct App { struct App {
pub state: GraphEditorState, state: GraphEditorState,
pub devices: Vec<Device>, devices: Vec<Device>,
virtual_device: Option<VirtualDevice>,
} }
impl App { impl App {
fn new() -> Self { fn new() -> Self {
Self { Self {
state: GraphEditorState::default(), state: GraphEditorState::default(),
devices: dbg!(Device::query()), devices: Device::query(),
virtual_device: None,
} }
} }
} }
@ -33,7 +37,12 @@ impl App {
impl epi::App for App { impl epi::App for App {
fn update(&mut self, ctx: &egui::CtxRef, _frame: &epi::Frame) { fn update(&mut self, ctx: &egui::CtxRef, _frame: &epi::Frame) {
egui::CentralPanel::default().show(ctx, |_| { egui::CentralPanel::default().show(ctx, |_| {
graph_editor_egui::draw_graph_editor(&ctx, &mut self.state, &self.devices); graph_editor_egui::draw_graph_editor(
&ctx,
&mut self.state,
&self.devices,
&mut self.virtual_device,
);
}); });
} }

View file

@ -2,6 +2,22 @@ use egui::*;
use crate::color_hex_utils::*; use crate::color_hex_utils::*;
use crate::device::Device; use crate::device::Device;
use crate::graph_types::NodeDescriptor;
use crate::virtual_device::VirtualDevice;
pub enum SelectedDevice<'a> {
Virtual(VirtualDevice),
Physical(&'a Device),
}
impl<'a> SelectedDevice<'a> {
pub fn to_descriptor(&self) -> NodeDescriptor {
match self {
SelectedDevice::Virtual(dev) => dev.to_descriptor(),
SelectedDevice::Physical(dev) => dev.to_descriptor(),
}
}
}
#[derive(Default)] #[derive(Default)]
pub struct NodeFinder { pub struct NodeFinder {
@ -23,7 +39,12 @@ impl NodeFinder {
/// Shows the node selector panel with a search bar. Returns whether a node /// Shows the node selector panel with a search bar. Returns whether a node
/// archetype was selected and, in that case, the finder should be hidden on /// archetype was selected and, in that case, the finder should be hidden on
/// the next frame. /// the next frame.
pub fn show<'a>(&mut self, devices: &'a [Device], ui: &mut Ui) -> Option<&'a Device> { pub fn show<'a>(
&mut self,
devices: &'a [Device],
allow_virt_dev: bool,
ui: &mut Ui,
) -> Option<SelectedDevice<'a>> {
let background_color = color_from_hex("#3f3f3f").unwrap(); let background_color = color_from_hex("#3f3f3f").unwrap();
let _titlebar_color = background_color.linear_multiply(0.8); let _titlebar_color = background_color.linear_multiply(0.8);
let text_color = color_from_hex("#fefefe").unwrap(); let text_color = color_from_hex("#fefefe").unwrap();
@ -38,24 +59,20 @@ impl NodeFinder {
let mut submitted_device = None; let mut submitted_device = None;
frame.show(ui, |ui| { frame.show(ui, |ui| {
ui.vertical(|ui| { ui.vertical(|ui| {
let resp = ui.text_edit_singleline(&mut self.query);
if self.just_spawned {
resp.request_focus();
self.just_spawned = false;
}
let mut query_submit = resp.lost_focus() && ui.input().key_down(Key::Enter);
Frame::default().margin(vec2(10.0, 10.0)).show(ui, |ui| { Frame::default().margin(vec2(10.0, 10.0)).show(ui, |ui| {
if allow_virt_dev {
if ui.selectable_label(false, "New Virtual Device").clicked() {
submitted_device = Some(SelectedDevice::Virtual(VirtualDevice::new(
"New Virtual Device",
)));
}
}
for device in devices { for device in devices {
let device_name = device.name(); let device_name = device.name();
if device_name.contains(self.query.as_str()) { if device_name.contains(self.query.as_str()) {
if query_submit {
submitted_device = Some(device);
query_submit = false;
}
if ui.selectable_label(false, device_name).clicked() { if ui.selectable_label(false, device_name).clicked() {
submitted_device = Some(device); submitted_device = Some(SelectedDevice::Physical(device));
} }
} }
} }

View file

@ -9,7 +9,7 @@ impl Param {
ui.label(name); ui.label(name);
} }
Descriptor::Button => { Descriptor::Button => {
ui.label(name); ui.horizontal(|ui| ui.centered_and_justified(|ui| ui.label(name)));
} }
Descriptor::Slider { min, max } => { Descriptor::Slider { min, max } => {
ui.horizontal(|ui| { ui.horizontal(|ui| {
@ -20,6 +20,7 @@ impl Param {
.text(format!("{}", 0)), .text(format!("{}", 0)),
); );
ui.label(format!("{}", max)); ui.label(format!("{}", max));
ui.label(name);
}); });
} }
} }

31
src/virtual_device.rs Normal file
View file

@ -0,0 +1,31 @@
use crate::{graph_types::NodeDescriptor, id_types::NodeId};
pub struct VirtualDevice {
name: String,
node_id: Option<NodeId>,
}
impl VirtualDevice {
pub fn new(name: impl ToString) -> Self {
Self {
name: name.to_string(),
node_id: None,
}
}
pub fn connect_id(&mut self, node_id: NodeId) {
self.node_id = Some(node_id);
}
pub fn node_id(&self) -> NodeId {
self.node_id.unwrap()
}
pub fn to_descriptor(&self) -> NodeDescriptor {
NodeDescriptor {
op_name: self.name.clone(),
inputs: Vec::new(),
outputs: Vec::new(),
}
}
}