Skip to content

Commit bdc029c

Browse files
authored
Add Table<Gradient> as a graphical type (#3051)
1 parent 1b351ac commit bdc029c

File tree

33 files changed

+684
-568
lines changed

33 files changed

+684
-568
lines changed

editor/src/messages/message.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ mod test {
6969

7070
fn print_tree_node(tree: &DebugMessageTree, prefix: &str, is_last: bool, file: &mut std::fs::File) {
7171
// Print the current node
72-
let (branch, child_prefix) = if tree.has_message_handler_data_fields() || tree.has_message_handler_fields() {
72+
let (branch, child_prefix) = if tree.message_handler_data_fields().is_some() || tree.message_handler_fields().is_some() {
7373
("├── ", format!("{}│ ", prefix))
7474
} else {
7575
if is_last {
@@ -97,7 +97,7 @@ mod test {
9797
// Print handler field if any
9898
if let Some(data) = tree.message_handler_fields() {
9999
let len = data.fields().len();
100-
let (branch, child_prefix) = if tree.has_message_handler_data_fields() {
100+
let (branch, child_prefix) = if tree.message_handler_data_fields().is_some() {
101101
("├── ", format!("{}│ ", prefix))
102102
} else {
103103
("└── ", format!("{} ", prefix))

editor/src/messages/portfolio/document/data_panel/data_panel_message_handler.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::messages::tool::tool_messages::tool_prelude::*;
77
use graph_craft::document::NodeId;
88
use graphene_std::Color;
99
use graphene_std::Context;
10+
use graphene_std::gradient::GradientStops;
1011
use graphene_std::memo::IORecord;
1112
use graphene_std::raster_types::{CPU, GPU, Raster};
1213
use graphene_std::table::Table;
@@ -153,7 +154,6 @@ macro_rules! generate_layout_downcast {
153154
else { None }
154155
}
155156
}
156-
157157
// TODO: We simply try all these types sequentially. Find a better strategy.
158158
fn generate_layout(introspected_data: &Arc<dyn std::any::Any + Send + Sync + 'static>, data: &mut LayoutData) -> Option<Vec<LayoutGroup>> {
159159
generate_layout_downcast!(introspected_data, data, [
@@ -163,6 +163,7 @@ fn generate_layout(introspected_data: &Arc<dyn std::any::Any + Send + Sync + 'st
163163
Table<Raster<CPU>>,
164164
Table<Raster<GPU>>,
165165
Table<Color>,
166+
Table<GradientStops>,
166167
f64,
167168
u32,
168169
u64,
@@ -263,6 +264,7 @@ impl TableRowLayout for Graphic {
263264
Self::RasterCPU(table) => table.identifier(),
264265
Self::RasterGPU(table) => table.identifier(),
265266
Self::Color(table) => table.identifier(),
267+
Self::Gradient(table) => table.identifier(),
266268
}
267269
}
268270
// Don't put a breadcrumb for Graphic
@@ -276,6 +278,7 @@ impl TableRowLayout for Graphic {
276278
Self::RasterCPU(table) => table.layout_with_breadcrumb(data),
277279
Self::RasterGPU(table) => table.layout_with_breadcrumb(data),
278280
Self::Color(table) => table.layout_with_breadcrumb(data),
281+
Self::Gradient(table) => table.layout_with_breadcrumb(data),
279282
}
280283
}
281284
}
@@ -335,10 +338,6 @@ impl TableRowLayout for Vector {
335338
TextLabel::new(format_dvec2(gradient.start)).widget_holder(),
336339
]);
337340
table_rows.push(vec![TextLabel::new("Fill Gradient End").widget_holder(), TextLabel::new(format_dvec2(gradient.end)).widget_holder()]);
338-
table_rows.push(vec![
339-
TextLabel::new("Fill Gradient Transform").widget_holder(),
340-
TextLabel::new(format_transform_matrix(&gradient.transform)).widget_holder(),
341-
]);
342341
}
343342
}
344343

@@ -485,6 +484,25 @@ impl TableRowLayout for Color {
485484
}
486485
}
487486

487+
impl TableRowLayout for GradientStops {
488+
fn type_name() -> &'static str {
489+
"Gradient"
490+
}
491+
fn identifier(&self) -> String {
492+
format!("Gradient ({} stops)", self.0.len())
493+
}
494+
fn element_widget(&self, _index: usize) -> WidgetHolder {
495+
ColorInput::new(FillChoice::Gradient(self.clone()))
496+
.disabled(true)
497+
.menu_direction(Some(MenuDirection::Top))
498+
.widget_holder()
499+
}
500+
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
501+
let widgets = vec![self.element_widget(0)];
502+
vec![LayoutGroup::Row { widgets }]
503+
}
504+
}
505+
488506
impl TableRowLayout for f64 {
489507
fn type_name() -> &'static str {
490508
"Number (f64)"
@@ -545,7 +563,7 @@ impl TableRowLayout for String {
545563
"String".to_string()
546564
}
547565
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
548-
let widgets = vec![TextLabel::new(self.to_string()).widget_holder()];
566+
let widgets = vec![TextAreaInput::new(self.to_string()).disabled(true).widget_holder()];
549567
vec![LayoutGroup::Row { widgets }]
550568
}
551569
}

editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,6 @@ fn apply_usvg_fill(fill: &usvg::Fill, modify_inputs: &mut ModifyInputsContext, t
426426
Fill::Gradient(Gradient {
427427
start,
428428
end,
429-
transform: DAffine2::IDENTITY,
430429
gradient_type: GradientType::Linear,
431430
stops,
432431
})
@@ -453,7 +452,6 @@ fn apply_usvg_fill(fill: &usvg::Fill, modify_inputs: &mut ModifyInputsContext, t
453452
Fill::Gradient(Gradient {
454453
start,
455454
end,
456-
transform: DAffine2::IDENTITY,
457455
gradient_type: GradientType::Radial,
458456
stops,
459457
})

editor/src/messages/portfolio/document/node_graph/node_properties.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ pub(crate) fn property_from_type(
182182
// STRUCT TYPES
183183
// ============
184184
Some(x) if x == TypeId::of::<Table<Color>>() => color_widget(default_info, ColorInput::default().allow_none(true)),
185+
Some(x) if x == TypeId::of::<Table<GradientStops>>() => color_widget(default_info, ColorInput::default().allow_none(false)),
185186
Some(x) if x == TypeId::of::<GradientStops>() => color_widget(default_info, ColorInput::default().allow_none(false)),
186187
Some(x) if x == TypeId::of::<Font>() => font_widget(default_info),
187188
Some(x) if x == TypeId::of::<Curve>() => curve_widget(default_info),
@@ -922,6 +923,20 @@ pub fn color_widget(parameter_widgets_info: ParameterWidgetsInfo, color_button:
922923
.on_commit(commit_value)
923924
.widget_holder(),
924925
),
926+
TaggedValue::GradientTable(gradient_table) => widgets.push(
927+
color_button
928+
.value(match gradient_table.iter().next() {
929+
Some(row) => FillChoice::Gradient(row.element.clone()),
930+
None => FillChoice::None,
931+
})
932+
.on_update(update_value(
933+
|input: &ColorInput| TaggedValue::GradientTable(input.value.as_gradient().iter().map(|&gradient| TableRow::new_from_element(gradient.clone())).collect()),
934+
node_id,
935+
index,
936+
))
937+
.on_commit(commit_value)
938+
.widget_holder(),
939+
),
925940
TaggedValue::GradientStops(gradient_stops) => widgets.push(
926941
color_button
927942
.value(FillChoice::Gradient(gradient_stops.clone()))

editor/src/messages/portfolio/document/node_graph/utility_types.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ pub enum FrontendGraphDataType {
1414
Raster,
1515
Vector,
1616
Color,
17+
Gradient,
18+
Typography,
1719
}
1820

1921
impl FrontendGraphDataType {
@@ -32,6 +34,8 @@ impl FrontendGraphDataType {
3234
TaggedValue::Raster(_) => Self::Raster,
3335
TaggedValue::Vector(_) => Self::Vector,
3436
TaggedValue::Color(_) => Self::Color,
37+
TaggedValue::Gradient(_) | TaggedValue::GradientStops(_) | TaggedValue::GradientTable(_) => Self::Gradient,
38+
TaggedValue::String(_) => Self::Typography,
3539
_ => Self::General,
3640
}
3741
}

editor/src/messages/tool/tool_messages/gradient_tool.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@ impl SelectedGradient {
204204

205205
/// Update the layer fill to the current gradient
206206
pub fn render_gradient(&mut self, responses: &mut VecDeque<Message>) {
207-
self.gradient.transform = self.transform;
208207
if let Some(layer) = self.layer {
209208
responses.add(GraphOperationMessage::FillSet {
210209
layer,
@@ -436,14 +435,7 @@ impl Fsm for GradientToolFsmState {
436435
gradient.clone()
437436
} else {
438437
// Generate a new gradient
439-
Gradient::new(
440-
DVec2::ZERO,
441-
global_tool_data.secondary_color,
442-
DVec2::ONE,
443-
global_tool_data.primary_color,
444-
DAffine2::IDENTITY,
445-
tool_options.gradient_type,
446-
)
438+
Gradient::new(DVec2::ZERO, global_tool_data.secondary_color, DVec2::ONE, global_tool_data.primary_color, tool_options.gradient_type)
447439
};
448440
let selected_gradient = SelectedGradient::new(gradient, layer, document).with_gradient_start(input.mouse.position);
449441

editor/src/node_graph_executor.rs

Lines changed: 27 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,10 @@ use graph_craft::proto::GraphErrors;
88
use graph_craft::wasm_application_io::EditorPreferences;
99
use graphene_std::application_io::TimingInformation;
1010
use graphene_std::application_io::{NodeGraphUpdateMessage, RenderConfig};
11-
use graphene_std::renderer::RenderSvgSegmentList;
12-
use graphene_std::renderer::{Render, RenderParams, SvgRender};
1311
use graphene_std::renderer::{RenderMetadata, format_transform_matrix};
1412
use graphene_std::text::FontCache;
1513
use graphene_std::transform::Footprint;
1614
use graphene_std::vector::Vector;
17-
use graphene_std::vector::style::ViewMode;
1815
use graphene_std::wasm_application_io::RenderOutputType;
1916
use interpreted_executor::dynamic_executor::ResolvedDocumentNodeTypesDelta;
2017

@@ -34,7 +31,6 @@ pub struct ExecutionResponse {
3431
execution_id: u64,
3532
result: Result<TaggedValue, String>,
3633
responses: VecDeque<FrontendMessage>,
37-
footprint: Footprint,
3834
vector_modify: HashMap<NodeId, Vector>,
3935
/// The resulting value from the temporary inspected during execution
4036
inspect_result: Option<InspectResult>,
@@ -131,6 +127,7 @@ impl NodeGraphExecutor {
131127
.send(GraphRuntimeRequest::GraphUpdate(GraphUpdate { network, node_to_inspect }))
132128
.map_err(|e| e.to_string())?;
133129
}
130+
134131
Ok(())
135132
}
136133

@@ -252,6 +249,7 @@ impl NodeGraphExecutor {
252249
let size = (size * scale_factor).into();
253250
responses.add(FrontendMessage::TriggerExportImage { svg, name, mime, size });
254251
}
252+
255253
Ok(())
256254
}
257255

@@ -264,7 +262,6 @@ impl NodeGraphExecutor {
264262
execution_id,
265263
result,
266264
responses: existing_responses,
267-
footprint,
268265
vector_modify,
269266
inspect_result,
270267
} = execution_response;
@@ -289,7 +286,7 @@ impl NodeGraphExecutor {
289286
// Special handling for exporting the artwork
290287
self.export(node_graph_output, export_config, responses)?;
291288
} else {
292-
self.process_node_graph_output(node_graph_output, footprint, responses)?;
289+
self.process_node_graph_output(node_graph_output, responses)?;
293290
}
294291
responses.add_front(DeferMessage::TriggerGraphRun(execution_id, execution_context.document_id));
295292

@@ -330,73 +327,41 @@ impl NodeGraphExecutor {
330327
}
331328
}
332329
}
330+
333331
Ok(())
334332
}
335333

336-
fn debug_render(render_object: impl Render, footprint: Footprint, responses: &mut VecDeque<Message>) {
337-
// Setup rendering
338-
let mut render = SvgRender::new();
339-
let render_params = RenderParams {
340-
view_mode: ViewMode::Normal,
341-
footprint,
342-
thumbnail: false,
343-
hide_artboards: false,
344-
for_export: false,
345-
for_mask: false,
346-
alignment_parent_transform: None,
334+
fn process_node_graph_output(&mut self, node_graph_output: TaggedValue, responses: &mut VecDeque<Message>) -> Result<(), String> {
335+
let TaggedValue::RenderOutput(render_output) = node_graph_output else {
336+
return Err(format!("Invalid node graph output type: {node_graph_output:#?}"));
347337
};
348338

349-
// Render SVG
350-
render_object.render_svg(&mut render, &render_params);
351-
352-
// Concatenate the defs and the SVG into one string
353-
render.wrap_with_transform(footprint.transform, None);
354-
let svg = render.svg.to_svg_string();
355-
356-
// Send to frontend
357-
responses.add(FrontendMessage::UpdateDocumentArtwork { svg });
358-
}
359-
360-
fn process_node_graph_output(&mut self, node_graph_output: TaggedValue, footprint: Footprint, responses: &mut VecDeque<Message>) -> Result<(), String> {
361-
let mut render_output_metadata = RenderMetadata::default();
362-
363-
match node_graph_output {
364-
TaggedValue::RenderOutput(render_output) => {
365-
match render_output.data {
366-
RenderOutputType::Svg { svg, image_data } => {
367-
// Send to frontend
368-
responses.add(FrontendMessage::UpdateImageData { image_data });
369-
responses.add(FrontendMessage::UpdateDocumentArtwork { svg });
370-
}
371-
RenderOutputType::CanvasFrame(frame) => {
372-
let matrix = format_transform_matrix(frame.transform);
373-
let transform = if matrix.is_empty() { String::new() } else { format!(" transform=\"{matrix}\"") };
374-
let svg = format!(
375-
r#"<svg><foreignObject width="{}" height="{}"{transform}><div data-canvas-placeholder="{}"></div></foreignObject></svg>"#,
376-
frame.resolution.x, frame.resolution.y, frame.surface_id.0
377-
);
378-
responses.add(FrontendMessage::UpdateDocumentArtwork { svg });
379-
}
380-
RenderOutputType::Texture { .. } => {}
381-
_ => return Err(format!("Invalid node graph output type: {:#?}", render_output.data)),
382-
}
383-
384-
render_output_metadata = render_output.metadata;
339+
match render_output.data {
340+
RenderOutputType::Svg { svg, image_data } => {
341+
// Send to frontend
342+
responses.add(FrontendMessage::UpdateImageData { image_data });
343+
responses.add(FrontendMessage::UpdateDocumentArtwork { svg });
385344
}
386-
TaggedValue::Bool(render_object) => Self::debug_render(render_object, footprint, responses),
387-
TaggedValue::F64(render_object) => Self::debug_render(render_object, footprint, responses),
388-
TaggedValue::DVec2(render_object) => Self::debug_render(render_object, footprint, responses),
389-
TaggedValue::String(render_object) => Self::debug_render(render_object, footprint, responses),
390-
_ => return Err(format!("Invalid node graph output type: {node_graph_output:#?}")),
391-
};
345+
RenderOutputType::CanvasFrame(frame) => {
346+
let matrix = format_transform_matrix(frame.transform);
347+
let transform = if matrix.is_empty() { String::new() } else { format!(" transform=\"{matrix}\"") };
348+
let svg = format!(
349+
r#"<svg><foreignObject width="{}" height="{}"{transform}><div data-canvas-placeholder="{}"></div></foreignObject></svg>"#,
350+
frame.resolution.x, frame.resolution.y, frame.surface_id.0
351+
);
352+
responses.add(FrontendMessage::UpdateDocumentArtwork { svg });
353+
}
354+
RenderOutputType::Texture { .. } => {}
355+
_ => return Err(format!("Invalid node graph output type: {:#?}", render_output.data)),
356+
}
392357

393-
let graphene_std::renderer::RenderMetadata {
358+
let RenderMetadata {
394359
upstream_footprints,
395360
local_transforms,
396361
first_element_source_id,
397362
click_targets,
398363
clip_targets,
399-
} = render_output_metadata;
364+
} = render_output.metadata;
400365

401366
// Run these update state messages immediately
402367
responses.add(DocumentMessage::UpdateUpstreamTransforms {
@@ -409,6 +374,7 @@ impl NodeGraphExecutor {
409374
responses.add(DocumentMessage::RenderScrollbars);
410375
responses.add(DocumentMessage::RenderRulers);
411376
responses.add(OverlaysMessage::Draw);
377+
412378
Ok(())
413379
}
414380
}

editor/src/node_graph_executor/runtime.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use graphene_std::table::{Table, TableRow};
1616
use graphene_std::text::FontCache;
1717
use graphene_std::transform::RenderQuality;
1818
use graphene_std::vector::Vector;
19-
use graphene_std::vector::style::ViewMode;
2019
use graphene_std::wasm_application_io::{RenderOutputType, WasmApplicationIo, WasmEditorApi};
2120
use graphene_std::{Artboard, Context, Graphic};
2221
use interpreted_executor::dynamic_executor::{DynamicExecutor, IntrospectError, ResolvedDocumentNodeTypesDelta};
@@ -228,7 +227,6 @@ impl NodeRuntime {
228227
execution_id,
229228
result,
230229
responses,
231-
footprint: render_config.viewport,
232230
vector_modify: self.vector_modify.clone(),
233231
inspect_result,
234232
});
@@ -361,13 +359,9 @@ impl NodeRuntime {
361359

362360
// Render the thumbnail from a `Graphic` into an SVG string
363361
let render_params = RenderParams {
364-
view_mode: ViewMode::Normal,
365362
footprint,
366363
thumbnail: true,
367-
hide_artboards: false,
368-
for_export: false,
369-
for_mask: false,
370-
alignment_parent_transform: None,
364+
..Default::default()
371365
};
372366
let mut render = SvgRender::new();
373367
graphic.render_svg(&mut render, &render_params);

0 commit comments

Comments
 (0)