Skip to content

Commit 15388c6

Browse files
committed
resolve merge conflicts
2 parents 68b30fa + 1090770 commit 15388c6

36 files changed

+1967
-587
lines changed

demo-artwork/parametric-dunescape.graphite

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

editor/src/consts.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ pub const MIN_LENGTH_FOR_RESIZE_TO_INCLUDE_INTERIOR: f64 = 40.;
8989
///
9090
/// The motion of the user's cursor by an `x` pixel offset results in `x * scale_factor` pixels of offset on the other side.
9191
pub const MAXIMUM_ALT_SCALE_FACTOR: f64 = 25.;
92+
/// The width or height that the transform cage needs before it is considered to have no width or height.
93+
pub const MAX_LENGTH_FOR_NO_WIDTH_OR_HEIGHT: f64 = 1e-4;
9294

9395
// SKEW TRIANGLES
9496
pub const SKEW_TRIANGLE_SIZE: f64 = 7.;
@@ -100,7 +102,7 @@ pub const MANIPULATOR_GROUP_MARKER_SIZE: f64 = 6.;
100102
pub const SELECTION_THRESHOLD: f64 = 10.;
101103
pub const HIDE_HANDLE_DISTANCE: f64 = 3.;
102104
pub const HANDLE_ROTATE_SNAP_ANGLE: f64 = 15.;
103-
pub const SEGMENT_INSERTION_DISTANCE: f64 = 7.5;
105+
pub const SEGMENT_INSERTION_DISTANCE: f64 = 8.;
104106
pub const SEGMENT_OVERLAY_SIZE: f64 = 10.;
105107
pub const HANDLE_LENGTH_FACTOR: f64 = 0.5;
106108

editor/src/messages/input_mapper/input_mappings.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ pub fn input_mappings() -> Mapping {
197197
entry!(KeyDown(KeyG); action_dispatch=PathToolMessage::GRS { key: KeyG }),
198198
entry!(KeyDown(KeyR); action_dispatch=PathToolMessage::GRS { key: KeyR }),
199199
entry!(KeyDown(KeyS); action_dispatch=PathToolMessage::GRS { key: KeyS }),
200-
entry!(PointerMove; refresh_keys=[KeyC, Space, Control, Shift, Alt], action_dispatch=PathToolMessage::PointerMove { toggle_colinear: KeyC, equidistant: Alt, move_anchor_with_handles: Space, snap_angle: Shift, lock_angle: Control, delete_segment: Alt }),
200+
entry!(PointerMove; refresh_keys=[KeyC, Space, Control, Shift, Alt], action_dispatch=PathToolMessage::PointerMove { toggle_colinear: KeyC, equidistant: Alt, move_anchor_with_handles: Space, snap_angle: Shift, lock_angle: Control, delete_segment: Alt, break_colinear_molding: Alt }),
201201
entry!(KeyDown(Delete); action_dispatch=PathToolMessage::Delete),
202202
entry!(KeyDown(KeyA); modifiers=[Accel], action_dispatch=PathToolMessage::SelectAllAnchors),
203203
entry!(KeyDown(KeyA); modifiers=[Accel, Shift], action_dispatch=PathToolMessage::DeselectAllPoints),

editor/src/messages/portfolio/document/document_message_handler.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork};
3232
use graphene_core::raster::BlendMode;
3333
use graphene_core::raster::image::RasterDataTable;
3434
use graphene_core::vector::style::ViewMode;
35-
use graphene_std::renderer::{ClickTarget, Quad};
35+
use graphene_std::renderer::{ClickTarget, ClickTargetType, Quad};
3636
use graphene_std::vector::{PointId, path_bool_lib};
3737
use std::time::Duration;
3838

@@ -1636,10 +1636,17 @@ impl DocumentMessageHandler {
16361636
let layer_transform = self.network_interface.document_metadata().transform_to_document(*layer);
16371637

16381638
layer_click_targets.is_some_and(|targets| {
1639-
targets.iter().all(|target| {
1640-
let mut subpath = target.subpath().clone();
1641-
subpath.apply_transform(layer_transform);
1642-
subpath.is_inside_subpath(&viewport_polygon, None, None)
1639+
targets.iter().all(|target| match target.target_type() {
1640+
ClickTargetType::Subpath(subpath) => {
1641+
let mut subpath = subpath.clone();
1642+
subpath.apply_transform(layer_transform);
1643+
subpath.is_inside_subpath(&viewport_polygon, None, None)
1644+
}
1645+
ClickTargetType::FreePoint(point) => {
1646+
let mut point = point.clone();
1647+
point.apply_transform(layer_transform);
1648+
viewport_polygon.contains_point(point.position)
1649+
}
16431650
})
16441651
})
16451652
}
@@ -2894,7 +2901,14 @@ fn click_targets_to_path_lib_segments<'a>(click_targets: impl Iterator<Item = &'
28942901
bezier_rs::BezierHandles::Cubic { handle_start, handle_end } => path_bool_lib::PathSegment::Cubic(bezier.start, handle_start, handle_end, bezier.end),
28952902
};
28962903
click_targets
2897-
.flat_map(|target| target.subpath().iter())
2904+
.filter_map(|target| {
2905+
if let ClickTargetType::Subpath(subpath) = target.target_type() {
2906+
Some(subpath.iter())
2907+
} else {
2908+
None
2909+
}
2910+
})
2911+
.flatten()
28982912
.map(|bezier| segment(bezier.apply_transformation(|x| transform.transform_point2(x))))
28992913
.collect()
29002914
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
951951
properties: None,
952952
},
953953
DocumentNodeDefinition {
954-
identifier: "Split Vector2",
954+
identifier: "Split Coordinate",
955955
category: "Math: Vector",
956956
node_template: NodeTemplate {
957957
document_node: DocumentNode {
@@ -982,7 +982,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
982982
..Default::default()
983983
},
984984
persistent_node_metadata: DocumentNodePersistentMetadata {
985-
input_properties: vec![("Vector2", "TODO").into()],
985+
input_properties: vec![("Coordinate", "TODO").into()],
986986
output_names: vec!["X".to_string(), "Y".to_string()],
987987
has_primary_output: false,
988988
network_metadata: Some(NodeNetworkMetadata {
@@ -2913,7 +2913,7 @@ fn static_input_properties() -> InputProperties {
29132913
.input_metadata(&node_id, index, "min", context.selection_network_path)
29142914
.and_then(|value| value.as_f64());
29152915

2916-
Ok(vec![node_properties::vector2_widget(
2916+
Ok(vec![node_properties::coordinate_widget(
29172917
ParameterWidgetsInfo::new(document_node, node_id, index, input_name, input_description, true),
29182918
x,
29192919
y,
@@ -3190,7 +3190,7 @@ fn static_input_properties() -> InputProperties {
31903190
Box::new(|node_id, index, context| {
31913191
let (document_node, input_name, input_description) = node_properties::query_node_and_input_info(node_id, index, context)?;
31923192
Ok(vec![LayoutGroup::Row {
3193-
widgets: node_properties::array_of_vector2_widget(
3193+
widgets: node_properties::array_of_coordinates_widget(
31943194
ParameterWidgetsInfo::new(document_node, node_id, index, input_name, input_description, true),
31953195
TextInput::default().centered(true),
31963196
),

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -566,10 +566,12 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
566566
responses.add(DocumentMessage::AddTransaction);
567567

568568
let new_ids: HashMap<_, _> = data.iter().map(|(id, _)| (*id, NodeId::new())).collect();
569+
let nodes: Vec<_> = new_ids.iter().map(|(_, id)| *id).collect();
569570
responses.add(NodeGraphMessage::AddNodes {
570571
nodes: data,
571572
new_ids: new_ids.clone(),
572573
});
574+
responses.add(NodeGraphMessage::SelectedNodesSet { nodes })
573575
}
574576
NodeGraphMessage::PointerDown {
575577
shift_click,
@@ -995,11 +997,13 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
995997
responses.add(NodeGraphMessage::TogglePreview { node_id: preview_node });
996998
self.preview_on_mouse_up = None;
997999
}
998-
if let Some(node_to_deselect) = self.deselect_on_pointer_up {
999-
let mut new_selected_nodes = selected_nodes.selected_nodes_ref().clone();
1000-
new_selected_nodes.remove(node_to_deselect);
1001-
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: new_selected_nodes });
1002-
self.deselect_on_pointer_up = None;
1000+
if let Some(node_to_deselect) = self.deselect_on_pointer_up.take() {
1001+
if !self.drag_start.as_ref().is_some_and(|t| t.1) {
1002+
let mut new_selected_nodes = selected_nodes.selected_nodes_ref().clone();
1003+
new_selected_nodes.remove(node_to_deselect);
1004+
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: new_selected_nodes });
1005+
return;
1006+
}
10031007
}
10041008
let point = network_metadata
10051009
.persistent_metadata

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

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ pub(crate) fn property_from_type(
121121
index: usize,
122122
ty: &Type,
123123
number_options: (Option<f64>, Option<f64>, Option<(f64, f64)>),
124+
unit: Option<&str>,
125+
display_decimal_places: Option<u32>,
126+
step: Option<f64>,
124127
context: &mut NodePropertiesContext,
125128
) -> Result<Vec<LayoutGroup>, Vec<LayoutGroup>> {
126129
let Some(network) = context.network_interface.nested_network(context.selection_network_path) else {
@@ -142,6 +145,15 @@ pub(crate) fn property_from_type(
142145
number_max = Some(range_end);
143146
number_input = number_input.mode_range().min(range_start).max(range_end);
144147
}
148+
if let Some(unit) = unit {
149+
number_input = number_input.unit(unit);
150+
}
151+
if let Some(display_decimal_places) = display_decimal_places {
152+
number_input = number_input.display_decimal_places(display_decimal_places);
153+
}
154+
if let Some(step) = step {
155+
number_input = number_input.step(step);
156+
}
145157

146158
let min = |x: f64| number_min.unwrap_or(x);
147159
let max = |x: f64| number_max.unwrap_or(x);
@@ -155,15 +167,15 @@ pub(crate) fn property_from_type(
155167
// Aliased types (ambiguous values)
156168
Some("Percentage") => number_widget(default_info, number_input.percentage().min(min(0.)).max(max(100.))).into(),
157169
Some("SignedPercentage") => number_widget(default_info, number_input.percentage().min(min(-100.)).max(max(100.))).into(),
158-
Some("Angle") => number_widget(default_info, number_input.mode_range().min(min(-180.)).max(max(180.)).unit("°")).into(),
159-
Some("Multiplier") => number_widget(default_info, number_input.unit("x")).into(),
160-
Some("PixelLength") => number_widget(default_info, number_input.min(min(0.)).unit(" px")).into(),
170+
Some("Angle") => number_widget(default_info, number_input.mode_range().min(min(-180.)).max(max(180.)).unit(unit.unwrap_or("°"))).into(),
171+
Some("Multiplier") => number_widget(default_info, number_input.unit(unit.unwrap_or("x"))).into(),
172+
Some("PixelLength") => number_widget(default_info, number_input.min(min(0.)).unit(unit.unwrap_or(" px"))).into(),
161173
Some("Length") => number_widget(default_info, number_input.min(min(0.))).into(),
162174
Some("Fraction") => number_widget(default_info, number_input.mode_range().min(min(0.)).max(max(1.))).into(),
163175
Some("IntegerCount") => number_widget(default_info, number_input.int().min(min(1.))).into(),
164176
Some("SeedValue") => number_widget(default_info, number_input.int().min(min(0.))).into(),
165-
Some("Resolution") => vector2_widget(default_info, "W", "H", " px", Some(64.)),
166-
Some("PixelSize") => vector2_widget(default_info, "X", "Y", " px", None),
177+
Some("Resolution") => coordinate_widget(default_info, "W", "H", unit.unwrap_or(" px"), Some(64.)),
178+
Some("PixelSize") => coordinate_widget(default_info, "X", "Y", unit.unwrap_or(" px"), None),
167179

168180
// For all other types, use TypeId-based matching
169181
_ => {
@@ -177,14 +189,14 @@ pub(crate) fn property_from_type(
177189
Some(x) if x == TypeId::of::<u64>() => number_widget(default_info, number_input.int().min(min(0.))).into(),
178190
Some(x) if x == TypeId::of::<bool>() => bool_widget(default_info, CheckboxInput::default()).into(),
179191
Some(x) if x == TypeId::of::<String>() => text_widget(default_info).into(),
180-
Some(x) if x == TypeId::of::<DVec2>() => vector2_widget(default_info, "X", "Y", "", None),
181-
Some(x) if x == TypeId::of::<UVec2>() => vector2_widget(default_info, "X", "Y", "", Some(0.)),
182-
Some(x) if x == TypeId::of::<IVec2>() => vector2_widget(default_info, "X", "Y", "", None),
192+
Some(x) if x == TypeId::of::<DVec2>() => coordinate_widget(default_info, "X", "Y", "", None),
193+
Some(x) if x == TypeId::of::<UVec2>() => coordinate_widget(default_info, "X", "Y", "", Some(0.)),
194+
Some(x) if x == TypeId::of::<IVec2>() => coordinate_widget(default_info, "X", "Y", "", None),
183195
// ==========================
184196
// PRIMITIVE COLLECTION TYPES
185197
// ==========================
186198
Some(x) if x == TypeId::of::<Vec<f64>>() => array_of_number_widget(default_info, TextInput::default()).into(),
187-
Some(x) if x == TypeId::of::<Vec<DVec2>>() => array_of_vector2_widget(default_info, TextInput::default()).into(),
199+
Some(x) if x == TypeId::of::<Vec<DVec2>>() => array_of_coordinates_widget(default_info, TextInput::default()).into(),
188200
// ====================
189201
// GRAPHICAL DATA TYPES
190202
// ====================
@@ -249,8 +261,8 @@ pub(crate) fn property_from_type(
249261
}
250262
}
251263
Type::Generic(_) => vec![TextLabel::new("Generic type (not supported)").widget_holder()].into(),
252-
Type::Fn(_, out) => return property_from_type(node_id, index, out, number_options, context),
253-
Type::Future(out) => return property_from_type(node_id, index, out, number_options, context),
264+
Type::Fn(_, out) => return property_from_type(node_id, index, out, number_options, unit, display_decimal_places, step, context),
265+
Type::Future(out) => return property_from_type(node_id, index, out, number_options, unit, display_decimal_places, step, context),
254266
};
255267

256268
extra_widgets.push(widgets);
@@ -334,6 +346,15 @@ pub fn reference_point_widget(parameter_widgets_info: ParameterWidgetsInfo, disa
334346
if let Some(&TaggedValue::ReferencePoint(reference_point)) = input.as_non_exposed_value() {
335347
widgets.extend_from_slice(&[
336348
Separator::new(SeparatorType::Unrelated).widget_holder(),
349+
CheckboxInput::new(reference_point != ReferencePoint::None)
350+
.on_update(update_value(
351+
move |x: &CheckboxInput| TaggedValue::ReferencePoint(if x.checked { ReferencePoint::Center } else { ReferencePoint::None }),
352+
node_id,
353+
index,
354+
))
355+
.disabled(disabled)
356+
.widget_holder(),
357+
Separator::new(SeparatorType::Related).widget_holder(),
337358
ReferencePointInput::new(reference_point)
338359
.on_update(update_value(move |x: &ReferencePointInput| TaggedValue::ReferencePoint(x.value), node_id, index))
339360
.disabled(disabled)
@@ -489,7 +510,7 @@ pub fn footprint_widget(parameter_widgets_info: ParameterWidgetsInfo, extra_widg
489510
last.clone()
490511
}
491512

492-
pub fn vector2_widget(parameter_widgets_info: ParameterWidgetsInfo, x: &str, y: &str, unit: &str, min: Option<f64>) -> LayoutGroup {
513+
pub fn coordinate_widget(parameter_widgets_info: ParameterWidgetsInfo, x: &str, y: &str, unit: &str, min: Option<f64>) -> LayoutGroup {
493514
let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info;
494515

495516
let mut widgets = start_widgets(parameter_widgets_info, FrontendGraphDataType::Number);
@@ -632,7 +653,7 @@ pub fn array_of_number_widget(parameter_widgets_info: ParameterWidgetsInfo, text
632653
widgets
633654
}
634655

635-
pub fn array_of_vector2_widget(parameter_widgets_info: ParameterWidgetsInfo, text_props: TextInput) -> Vec<WidgetHolder> {
656+
pub fn array_of_coordinates_widget(parameter_widgets_info: ParameterWidgetsInfo, text_props: TextInput) -> Vec<WidgetHolder> {
636657
let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info;
637658

638659
let mut widgets = start_widgets(parameter_widgets_info, FrontendGraphDataType::Number);
@@ -1172,7 +1193,7 @@ pub(crate) fn grid_properties(node_id: NodeId, context: &mut NodePropertiesConte
11721193
if let Some(&TaggedValue::GridType(grid_type)) = grid_type_input.as_non_exposed_value() {
11731194
match grid_type {
11741195
GridType::Rectangular => {
1175-
let spacing = vector2_widget(ParameterWidgetsInfo::from_index(document_node, node_id, spacing_index, true, context), "W", "H", " px", Some(0.));
1196+
let spacing = coordinate_widget(ParameterWidgetsInfo::from_index(document_node, node_id, spacing_index, true, context), "W", "H", " px", Some(0.));
11761197
widgets.push(spacing);
11771198
}
11781199
GridType::Isometric => {
@@ -1182,7 +1203,7 @@ pub(crate) fn grid_properties(node_id: NodeId, context: &mut NodePropertiesConte
11821203
NumberInput::default().label("H").min(0.).unit(" px"),
11831204
),
11841205
};
1185-
let angles = vector2_widget(ParameterWidgetsInfo::from_index(document_node, node_id, angles_index, true, context), "", "", "°", None);
1206+
let angles = coordinate_widget(ParameterWidgetsInfo::from_index(document_node, node_id, angles_index, true, context), "", "", "°", None);
11861207
widgets.extend([spacing, angles]);
11871208
}
11881209
}
@@ -1386,6 +1407,9 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper
13861407
};
13871408

13881409
let mut number_options = (None, None, None);
1410+
let mut display_decimal_places = None;
1411+
let mut step = None;
1412+
let mut unit_suffix = None;
13891413
let input_type = match implementation {
13901414
DocumentNodeImplementation::ProtoNode(proto_node_identifier) => 'early_return: {
13911415
if let Some(field) = graphene_core::registry::NODE_METADATA
@@ -1395,6 +1419,9 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper
13951419
.and_then(|metadata| metadata.fields.get(input_index))
13961420
{
13971421
number_options = (field.number_min, field.number_max, field.number_mode_range);
1422+
display_decimal_places = field.number_display_decimal_places;
1423+
unit_suffix = field.unit;
1424+
step = field.number_step;
13981425
if let Some(ref default) = field.default_type {
13991426
break 'early_return default.clone();
14001427
}
@@ -1408,7 +1435,7 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper
14081435
let mut input_types = implementations
14091436
.keys()
14101437
.filter_map(|item| item.inputs.get(input_index))
1411-
.filter(|ty| property_from_type(node_id, input_index, ty, number_options, context).is_ok())
1438+
.filter(|ty| property_from_type(node_id, input_index, ty, number_options, unit_suffix, display_decimal_places, step, context).is_ok())
14121439
.collect::<Vec<_>>();
14131440
input_types.sort_by_key(|ty| ty.type_name());
14141441
let input_type = input_types.first().cloned();
@@ -1422,7 +1449,7 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper
14221449
_ => context.network_interface.input_type(&InputConnector::node(node_id, input_index), context.selection_network_path).0,
14231450
};
14241451

1425-
property_from_type(node_id, input_index, &input_type, number_options, context).unwrap_or_else(|value| value)
1452+
property_from_type(node_id, input_index, &input_type, number_options, unit_suffix, display_decimal_places, step, context).unwrap_or_else(|value| value)
14261453
});
14271454

14281455
layout.extend(row);

editor/src/messages/portfolio/document/overlays/grid_overlays.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -236,12 +236,24 @@ pub fn overlay_options(grid: &GridSnapping) -> Vec<LayoutGroup> {
236236
TextLabel::new("Type").table_align(true).widget_holder(),
237237
Separator::new(SeparatorType::Unrelated).widget_holder(),
238238
RadioInput::new(vec![
239-
RadioEntryData::new("rectangular")
240-
.label("Rectangular")
241-
.on_update(update_val(grid, |grid, _| grid.grid_type = GridType::RECTANGULAR)),
242-
RadioEntryData::new("isometric")
243-
.label("Isometric")
244-
.on_update(update_val(grid, |grid, _| grid.grid_type = GridType::ISOMETRIC)),
239+
RadioEntryData::new("rectangular").label("Rectangular").on_update(update_val(grid, |grid, _| {
240+
if let GridType::Isometric { y_axis_spacing, angle_a, angle_b } = grid.grid_type {
241+
grid.isometric_y_spacing = y_axis_spacing;
242+
grid.isometric_angle_a = angle_a;
243+
grid.isometric_angle_b = angle_b;
244+
}
245+
grid.grid_type = GridType::Rectangular { spacing: grid.rectangular_spacing };
246+
})),
247+
RadioEntryData::new("isometric").label("Isometric").on_update(update_val(grid, |grid, _| {
248+
if let GridType::Rectangular { spacing } = grid.grid_type {
249+
grid.rectangular_spacing = spacing;
250+
}
251+
grid.grid_type = GridType::Isometric {
252+
y_axis_spacing: grid.isometric_y_spacing,
253+
angle_a: grid.isometric_angle_a,
254+
angle_b: grid.isometric_angle_b,
255+
};
256+
})),
245257
])
246258
.min_width(200)
247259
.selected_index(Some(match grid.grid_type {

0 commit comments

Comments
 (0)