-
-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add custom pin drawing functionality to PinInfo struct #48
base: main
Are you sure you want to change the base?
Conversation
This functionality is available with |
I'll give it a try. |
It is very difficult to use. show_input returns PinInfo, and draw_input_pin uses the pin information and PinInfo to render. These are simple enough if you only want to change the existing pin rendering method. However, you cannot pass information representing a new pin, and you need to use something like a HashMap in the structure implementing SnarlViewer to store pin information. This approach is neither intuitive nor direct. However, I don’t think my pull request is necessarily correct either. To pass information, PinInfo would need to hold some additional data. Another idea I came up with is: pub custom_data: Option<Box<dyn std::any::Any + Sync + Send>>, Add this to the structure, or instead of PinInfo, prepare a marker trait and make it possible to pass types that implement this trait. pub trait PinInfoMarker: Sync + Send;
impl PinInfoMarker for PinInfo {};
fn show_input(&mut self, pin: &InPin, ui: &mut Ui, scale: f32, snarl: &mut Snarl<T>)
-> impl PinInfoMarker + 'static;
fn check() {
core::any::type_name::<PinInfo>() == core::any::type_name_of_val(pin_info)
} |
The content that can be processed by draw_input_pin is the same as what can be processed by show_input, with the only difference being that it can render pins. Moreover, show_input and draw_input_pin have a 1:1 correspondence, and draw_input_pin operates based on the information passed from show_input. However, the information passed from show_input is very limited. Since similar processing should not be performed in both functions, the current structure does not seem to be a very good design. |
Aha, so the problem is that you need complex computations to figure out how you want to draw the pin in draw_input_pin, while you already done it in show_input? For example, if you only need to check some data in the node, e.g. match enum variant and compare some value in it, then it's cheaper than boxing a closure in show_input. But I guess, removing a feature like this was wrong move anyway, so I'll put it back. |
I think I would prefer Trait instead of Closure. |
Do you know how to avoid boxing with a trait? |
The content of the pull request has been updated. This is a disruptive change. Below is the code I used when I changed my code to be compilable. ※The associated types of traits and their related features are still largely unstable, so caution is advised. impl SnarlViewer<FlowNodes> for FlowNodesViewer {
type Drawer = MyDrawer;
fn inputs(&mut self, node: &FlowNodes) -> usize {
node.to_as_info().inputs()
}
fn outputs(&mut self, node: &FlowNodes) -> usize {
node.to_as_info().outputs()
}
fn show_input(
&mut self,
pin: &egui_snarl::InPin,
ui: &mut egui::Ui,
scale: f32,
snarl: &mut egui_snarl::Snarl<FlowNodes>,
) -> MyPinInfo {
self.show_input(pin, ui, scale, snarl)(snarl, ui)
} use egui_snarl::ui::{PinDrawer, PinShape};
use crate::prelude::{egui::*, snarl::*};
pub struct CustomPinInfo;
pub type MyPinInfo = PinInfo<MyDrawer>;
#[derive(Debug, Clone, Copy)]
pub enum MyDrawer {
Lock,
Setting { teeth: usize },
Preset(PinShape),
}
impl From<PinShape> for MyDrawer {
fn from(pin_shape: PinShape) -> Self {
MyDrawer::Preset(pin_shape)
}
}
impl PinDrawer for MyDrawer {
fn draw(
&self,
painter: &egui::Painter,
fill: egui::Color32,
stroke: egui::Stroke,
pos: Pos2,
size: f32,
) {
match self {
MyDrawer::Lock => {
let rect = Rect::from_center_size(pos, egui::vec2(size, size));
let key_width = rect.width();
let key_height = rect.height() * 0.7;
// 丸い頭部分
painter.circle_stroke(
Pos2::new(rect.center().x, rect.center().y - rect.height() / 4.),
rect.height() / 3.,
stroke,
);
// 鍵のシャフト部分(長方形)
painter.rect(
egui::Rect::from_center_size(
Pos2::new(rect.center().x, rect.center().y + rect.height() / 4.),
Vec2::new(key_width, key_height),
),
0.0,
fill,
stroke,
);
}
MyDrawer::Setting { teeth } => {
let teeth = *teeth;
let rect = Rect::from_center_size(pos, egui::vec2(size, size));
let inner_radius = rect.size().min_elem() * 0.6; // 中央の円のサイズ
let outer_radius = rect.size().min_elem() * 0.8;
let center = rect.center();
let mut pointers = Vec::with_capacity(teeth * 3);
for i in 0..8 {
let inner_angle = (i as f32 - 0.3) * std::f32::consts::PI * 2.0 / teeth as f32;
let inner_x = inner_radius * inner_angle.cos();
let inner_y = inner_radius * inner_angle.sin();
let inner_point = Pos2::new(center.x + inner_x, center.y + inner_y);
let angle = (i as f32 - 0.1) * (std::f32::consts::PI * 2.0 / teeth as f32);
let x = outer_radius * angle.cos();
let y = outer_radius * angle.sin();
let outer_point = Pos2::new(center.x + x, center.y + y);
let angle = (i as f32 + 0.1) * (std::f32::consts::PI * 2.0 / teeth as f32);
let x = outer_radius * angle.cos();
let y = outer_radius * angle.sin();
let outer_point2 = Pos2::new(center.x + x, center.y + y);
let angle = (i as f32 + 0.3) * (std::f32::consts::PI * 2.0 / teeth as f32);
let x = inner_radius * angle.cos();
let y = inner_radius * angle.sin();
let inner_point2 = Pos2::new(center.x + x, center.y + y);
pointers.push(inner_point);
pointers.push(outer_point);
pointers.push(outer_point2);
pointers.push(inner_point2);
}
let mut shape = PathShape::closed_line(pointers, stroke);
shape.fill = fill;
painter.add(Shape::Path(shape));
}
MyDrawer::Preset(pin_shape) => {
pin_shape.draw(painter, fill, stroke, pos, size);
}
}
}
}
impl CustomPinInfo {
pub fn lock() -> PinInfo<MyDrawer> {
PinInfo::shape(MyDrawer::Lock)
}
pub fn setting(teeth: usize) -> PinInfo<MyDrawer> {
PinInfo::shape(MyDrawer::Setting { teeth })
}
pub fn ok_status() -> PinInfo<MyDrawer> {
PinInfo::circle().with_fill(egui::Color32::from_rgb(0, 0, 255))
}
pub fn ng_status() -> PinInfo<MyDrawer> {
PinInfo::circle().with_fill(egui::Color32::from_rgb(255, 0, 0))
}
pub fn none_status() -> PinInfo<MyDrawer> {
PinInfo::circle().with_fill(egui::Color32::from_rgb(0, 0, 0))
}
} |
I used it in the previous version.
7128496
It is not a very good implementation, but we want to use it now, so it is implemented with compatibility in mind.