mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-21 16:18:12 +08:00
Add node for executing rhai scripts
This commit is contained in:
@@ -30,7 +30,7 @@ impl DialogLayoutHolder for CloseAllDocumentsDialog {
|
||||
|
||||
impl LayoutHolder for CloseAllDocumentsDialog {
|
||||
fn layout(&self) -> Layout {
|
||||
let unsaved_list = "• ".to_string() + &self.unsaved_document_names.join("\n• ");
|
||||
let unsaved_list = "• ".to_string() + self.unsaved_document_names.join("\n• ").as_str();
|
||||
|
||||
Layout::WidgetLayout(WidgetLayout::new(vec![
|
||||
LayoutGroup::Row {
|
||||
|
||||
@@ -130,6 +130,25 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
description: Cow::Borrowed("The identity node passes its data through. You can use this to organize your node graph."),
|
||||
properties: Some("identity_properties"),
|
||||
},
|
||||
DocumentNodeDefinition {
|
||||
identifier: "Script",
|
||||
category: "General",
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
implementation: DocumentNodeImplementation::proto("graphene_std::rhai::RhaiNode"),
|
||||
manual_composition: Some(concrete!(Context)),
|
||||
inputs: vec![NodeInput::value(TaggedValue::F64(0.), true), NodeInput::value(TaggedValue::String("input".into()), false)],
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
input_properties: vec!["In".into(), "String".into()],
|
||||
output_names: vec!["Out".to_string()],
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
description: Cow::Borrowed(""),
|
||||
properties: Some("script_properties"),
|
||||
},
|
||||
// TODO: Auto-generate this from its proto node macro
|
||||
DocumentNodeDefinition {
|
||||
identifier: "Monitor",
|
||||
@@ -2897,6 +2916,7 @@ fn static_node_properties() -> NodeProperties {
|
||||
"monitor_properties".to_string(),
|
||||
Box::new(|_node_id, _context| node_properties::string_properties("The Monitor node is used by the editor to access the data flowing through it.")),
|
||||
);
|
||||
map.insert("script_properties".to_string(), Box::new(node_properties::script_properties));
|
||||
map
|
||||
}
|
||||
|
||||
|
||||
@@ -266,6 +266,7 @@ pub(crate) fn property_from_type(
|
||||
}
|
||||
}
|
||||
Type::Generic(_) => vec![TextLabel::new("Generic type (not supported)").widget_holder()].into(),
|
||||
Type::Dynamic => vec![TextLabel::new("Dynamic type (not supported)").widget_holder()].into(),
|
||||
Type::Fn(_, out) => return property_from_type(node_id, index, out, number_options, context),
|
||||
Type::Future(out) => return property_from_type(node_id, index, out, number_options, context),
|
||||
};
|
||||
@@ -2555,3 +2556,16 @@ pub fn math_properties(node_id: NodeId, context: &mut NodePropertiesContext) ->
|
||||
LayoutGroup::Row { widgets: operand_a_hint }.with_tooltip(r#""A" is fed by the value from the previous node in the primary data flow, or it is 0 if disconnected"#),
|
||||
]
|
||||
}
|
||||
|
||||
pub(crate) fn script_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
let document_node = match get_document_node(node_id, context) {
|
||||
Ok(document_node) => document_node,
|
||||
Err(err) => {
|
||||
log::error!("Could not get document node in script_properties: {err}");
|
||||
return Vec::new();
|
||||
}
|
||||
};
|
||||
let source = text_area_widget(document_node, node_id, 1, "Code", false);
|
||||
|
||||
vec![LayoutGroup::Row { widgets: source }]
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use graphene_std::vector::style::FillChoice;
|
||||
|
||||
fn grid_overlay_rectangular(document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, spacing: DVec2) {
|
||||
let origin = document.snapping_state.grid.origin;
|
||||
let grid_color = "#".to_string() + &document.snapping_state.grid.grid_color.to_rgba_hex_srgb();
|
||||
let grid_color = "#".to_string() + document.snapping_state.grid.grid_color.to_rgba_hex_srgb().as_str();
|
||||
let Some(spacing) = GridSnapping::compute_rectangle_spacing(spacing, &document.document_ptz) else {
|
||||
return;
|
||||
};
|
||||
@@ -48,7 +48,7 @@ fn grid_overlay_rectangular(document: &DocumentMessageHandler, overlay_context:
|
||||
// TODO: Implement this with a dashed line (`set_line_dash`), with integer spacing which is continuously adjusted to correct the accumulated error.
|
||||
fn grid_overlay_rectangular_dot(document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, spacing: DVec2) {
|
||||
let origin = document.snapping_state.grid.origin;
|
||||
let grid_color = "#".to_string() + &document.snapping_state.grid.grid_color.to_rgba_hex_srgb();
|
||||
let grid_color = "#".to_string() + document.snapping_state.grid.grid_color.to_rgba_hex_srgb().as_str();
|
||||
let Some(spacing) = GridSnapping::compute_rectangle_spacing(spacing, &document.document_ptz) else {
|
||||
return;
|
||||
};
|
||||
@@ -82,7 +82,7 @@ fn grid_overlay_rectangular_dot(document: &DocumentMessageHandler, overlay_conte
|
||||
}
|
||||
|
||||
fn grid_overlay_isometric(document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, y_axis_spacing: f64, angle_a: f64, angle_b: f64) {
|
||||
let grid_color = "#".to_string() + &document.snapping_state.grid.grid_color.to_rgba_hex_srgb();
|
||||
let grid_color = "#".to_string() + document.snapping_state.grid.grid_color.to_rgba_hex_srgb().as_str();
|
||||
let cmp = |a: &f64, b: &f64| a.partial_cmp(b).unwrap();
|
||||
let origin = document.snapping_state.grid.origin;
|
||||
let document_to_viewport = document.navigation_handler.calculate_offset_transform(overlay_context.size / 2., &document.document_ptz);
|
||||
@@ -125,7 +125,7 @@ fn grid_overlay_isometric(document: &DocumentMessageHandler, overlay_context: &m
|
||||
}
|
||||
|
||||
fn grid_overlay_isometric_dot(document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, y_axis_spacing: f64, angle_a: f64, angle_b: f64) {
|
||||
let grid_color = "#".to_string() + &document.snapping_state.grid.grid_color.to_rgba_hex_srgb();
|
||||
let grid_color = "#".to_string() + document.snapping_state.grid.grid_color.to_rgba_hex_srgb().as_str();
|
||||
let cmp = |a: &f64, b: &f64| a.partial_cmp(b).unwrap();
|
||||
let origin = document.snapping_state.grid.origin;
|
||||
let document_to_viewport = document.navigation_handler.calculate_offset_transform(overlay_context.size / 2., &document.document_ptz);
|
||||
|
||||
@@ -473,7 +473,7 @@ impl Fsm for TextToolFsmState {
|
||||
if far.x != 0. && far.y != 0. {
|
||||
let quad = Quad::from_box([DVec2::ZERO, far]);
|
||||
let transformed_quad = document.metadata().transform_to_viewport(tool_data.layer) * quad;
|
||||
overlay_context.quad(transformed_quad, Some(&("#".to_string() + &fill_color)));
|
||||
overlay_context.quad(transformed_quad, Some(&("#".to_string() + fill_color.as_str())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,11 +488,11 @@ impl Fsm for TextToolFsmState {
|
||||
for layer in document.intersect_quad_no_artboards(quad, input) {
|
||||
overlay_context.quad(
|
||||
Quad::from_box(document.metadata().bounding_box_viewport(layer).unwrap_or([DVec2::ZERO; 2])),
|
||||
Some(&("#".to_string() + &fill_color)),
|
||||
Some(&("#".to_string() + fill_color.as_str())),
|
||||
);
|
||||
}
|
||||
|
||||
overlay_context.quad(quad, Some(&("#".to_string() + &fill_color)));
|
||||
overlay_context.quad(quad, Some(&("#".to_string() + fill_color.as_str())));
|
||||
}
|
||||
|
||||
// TODO: implement bounding box for multiple layers
|
||||
|
||||
@@ -668,10 +668,10 @@ impl NodeGraphExecutor {
|
||||
..
|
||||
} = export_config;
|
||||
|
||||
let file_suffix = &format!(".{file_type:?}").to_lowercase();
|
||||
let file_suffix = format!(".{file_type:?}").to_lowercase();
|
||||
let name = match file_name.ends_with(FILE_SAVE_SUFFIX) {
|
||||
true => file_name.replace(FILE_SAVE_SUFFIX, file_suffix),
|
||||
false => file_name + file_suffix,
|
||||
true => file_name.replace(FILE_SAVE_SUFFIX, &file_suffix),
|
||||
false => file_name + file_suffix.as_str(),
|
||||
};
|
||||
|
||||
if file_type == FileType::Svg {
|
||||
|
||||
Reference in New Issue
Block a user