Skip to content

Commit c60ddcf

Browse files
adamgerhantKeavon
andauthored
Fix the Text node's Max Width/Height parameters with OptionalF64 losing the value when unticked (#3643)
* WIP * Fix widget * Fix migration * Remove OptionalF64 * Custom attributes for optional f64 widget * Code review * Move comments to another PR --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
1 parent 73682b4 commit c60ddcf

12 files changed

Lines changed: 254 additions & 188 deletions

File tree

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,10 @@ impl<'a> ModifyInputsContext<'a> {
206206
Some(NodeInput::value(TaggedValue::F64(typesetting.font_size), false)),
207207
Some(NodeInput::value(TaggedValue::F64(typesetting.line_height_ratio), false)),
208208
Some(NodeInput::value(TaggedValue::F64(typesetting.character_spacing), false)),
209-
Some(NodeInput::value(TaggedValue::OptionalF64(typesetting.max_width), false)),
210-
Some(NodeInput::value(TaggedValue::OptionalF64(typesetting.max_height), false)),
209+
Some(NodeInput::value(TaggedValue::Bool(typesetting.max_width.is_some()), false)),
210+
Some(NodeInput::value(TaggedValue::F64(typesetting.max_width.unwrap_or(100.)), false)),
211+
Some(NodeInput::value(TaggedValue::Bool(typesetting.max_width.is_some()), false)),
212+
Some(NodeInput::value(TaggedValue::F64(typesetting.max_width.unwrap_or(100.)), false)),
211213
Some(NodeInput::value(TaggedValue::F64(typesetting.tilt), false)),
212214
Some(NodeInput::value(TaggedValue::TextAlign(typesetting.align), false)),
213215
]);

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

Lines changed: 37 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use graphene_std::extract_xy::XY;
2121
use graphene_std::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha};
2222
use graphene_std::raster_types::{CPU, Raster};
2323
use graphene_std::table::Table;
24-
use graphene_std::text::{Font, TypesettingConfig};
2524
#[allow(unused_imports)]
2625
use graphene_std::transform::Footprint;
2726
use graphene_std::vector::Vector;
@@ -1653,103 +1652,6 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
16531652
properties: None,
16541653
},
16551654
// TODO: Auto-generate this from its proto node macro
1656-
DocumentNodeDefinition {
1657-
identifier: "Text",
1658-
category: "Text",
1659-
node_template: NodeTemplate {
1660-
document_node: DocumentNode {
1661-
implementation: DocumentNodeImplementation::ProtoNode(text::text::IDENTIFIER),
1662-
inputs: vec![
1663-
NodeInput::scope("editor-api"),
1664-
NodeInput::value(TaggedValue::String("Lorem ipsum".to_string()), false),
1665-
NodeInput::value(
1666-
TaggedValue::Font(Font::new(graphene_std::consts::DEFAULT_FONT_FAMILY.into(), graphene_std::consts::DEFAULT_FONT_STYLE.into())),
1667-
false,
1668-
),
1669-
NodeInput::value(TaggedValue::F64(TypesettingConfig::default().font_size), false),
1670-
NodeInput::value(TaggedValue::F64(TypesettingConfig::default().line_height_ratio), false),
1671-
NodeInput::value(TaggedValue::F64(TypesettingConfig::default().character_spacing), false),
1672-
NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_width), false),
1673-
NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_height), false),
1674-
NodeInput::value(TaggedValue::F64(TypesettingConfig::default().tilt), false),
1675-
NodeInput::value(TaggedValue::TextAlign(text::TextAlign::default()), false),
1676-
NodeInput::value(TaggedValue::Bool(false), false),
1677-
],
1678-
..Default::default()
1679-
},
1680-
persistent_node_metadata: DocumentNodePersistentMetadata {
1681-
input_metadata: vec![
1682-
("Editor API", "TODO").into(),
1683-
InputMetadata::with_name_description_override("Text", "TODO", WidgetOverride::Custom("text_area".to_string())),
1684-
InputMetadata::with_name_description_override("Font", "TODO", WidgetOverride::Custom("text_font".to_string())),
1685-
InputMetadata::with_name_description_override(
1686-
"Size",
1687-
"TODO",
1688-
WidgetOverride::Number(NumberInputSettings {
1689-
unit: Some(" px".to_string()),
1690-
min: Some(1.),
1691-
..Default::default()
1692-
}),
1693-
),
1694-
InputMetadata::with_name_description_override(
1695-
"Line Height",
1696-
"TODO",
1697-
WidgetOverride::Number(NumberInputSettings {
1698-
unit: Some("x".to_string()),
1699-
min: Some(0.),
1700-
step: Some(0.1),
1701-
..Default::default()
1702-
}),
1703-
),
1704-
InputMetadata::with_name_description_override(
1705-
"Character Spacing",
1706-
"TODO",
1707-
WidgetOverride::Number(NumberInputSettings {
1708-
unit: Some(" px".to_string()),
1709-
step: Some(0.1),
1710-
..Default::default()
1711-
}),
1712-
),
1713-
InputMetadata::with_name_description_override(
1714-
"Max Width",
1715-
"TODO",
1716-
WidgetOverride::Number(NumberInputSettings {
1717-
unit: Some(" px".to_string()),
1718-
min: Some(1.),
1719-
blank_assist: false,
1720-
..Default::default()
1721-
}),
1722-
),
1723-
InputMetadata::with_name_description_override(
1724-
"Max Height",
1725-
"TODO",
1726-
WidgetOverride::Number(NumberInputSettings {
1727-
unit: Some(" px".to_string()),
1728-
min: Some(1.),
1729-
blank_assist: false,
1730-
..Default::default()
1731-
}),
1732-
),
1733-
InputMetadata::with_name_description_override(
1734-
"Tilt",
1735-
"Faux italic.",
1736-
WidgetOverride::Number(NumberInputSettings {
1737-
min: Some(-85.),
1738-
max: Some(85.),
1739-
unit: Some("°".to_string()),
1740-
..Default::default()
1741-
}),
1742-
),
1743-
InputMetadata::with_name_description_override("Align", "TODO", WidgetOverride::Custom("text_align".to_string())),
1744-
("Per-Glyph Instances", "Splits each text glyph into its own row in the table of vector geometry.").into(),
1745-
],
1746-
output_names: vec!["Vector".to_string()],
1747-
..Default::default()
1748-
},
1749-
},
1750-
description: Cow::Borrowed("TODO"),
1751-
properties: None,
1752-
},
17531655
DocumentNodeDefinition {
17541656
identifier: "Transform",
17551657
category: "Math: Transform",
@@ -2297,6 +2199,43 @@ fn static_input_properties() -> InputProperties {
22972199
}])
22982200
}),
22992201
);
2202+
map.insert(
2203+
// The custom number input settings are only available on proto nodes
2204+
"optional_f64".to_string(),
2205+
Box::new(|node_id, index, context| {
2206+
let node_metadata = registry::NODE_METADATA.lock().unwrap();
2207+
let mut number_input = NumberInput::default();
2208+
if let Some(field) = context
2209+
.network_interface
2210+
.implementation(&node_id, context.selection_network_path)
2211+
.and_then(|implementation| if let DocumentNodeImplementation::ProtoNode(id) = implementation { Some(id) } else { None })
2212+
.and_then(|proto_node_identifier| node_metadata.get(proto_node_identifier))
2213+
.and_then(|metadata| metadata.fields.get(index))
2214+
{
2215+
if let Some(unit) = field.unit {
2216+
number_input = number_input.unit(unit);
2217+
}
2218+
if let Some(number_min) = field.number_min {
2219+
number_input = number_input.min(number_min);
2220+
}
2221+
if let Some(number_max) = field.number_max {
2222+
number_input = number_input.max(number_max);
2223+
}
2224+
if let Some((range_min, range_max)) = field.number_mode_range {
2225+
number_input = number_input.range_min(Some(range_min));
2226+
number_input = number_input.range_max(Some(range_max));
2227+
}
2228+
number_input = number_input.is_integer(false);
2229+
if let Some(number_step) = field.number_step {
2230+
number_input = number_input.step(number_step);
2231+
}
2232+
};
2233+
Ok(vec![LayoutGroup::Row {
2234+
// NOTE: The bool input MUST be at the input index directly before the f64 input!
2235+
widgets: node_properties::optional_f64_widget(ParameterWidgetsInfo::new(node_id, index, false, context), index - 1, number_input),
2236+
}])
2237+
}),
2238+
);
23002239
map.insert(
23012240
"vec2".to_string(),
23022241
Box::new(|node_id, index, context| {

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

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,49 @@ pub fn progression_widget(parameter_widgets_info: ParameterWidgetsInfo, number_p
939939
widgets
940940
}
941941

942+
/// `parameter_widgets_info` is for the f64 parameter. `bool_input_index` is the input index of the bool parameter for the checkbox.
943+
pub fn optional_f64_widget(parameter_widgets_info: ParameterWidgetsInfo, bool_input_index: usize, number_props: NumberInput) -> Vec<WidgetInstance> {
944+
let ParameterWidgetsInfo {
945+
document_node,
946+
node_id,
947+
index: number_input_index,
948+
..
949+
} = parameter_widgets_info;
950+
951+
let mut widgets = start_widgets(parameter_widgets_info);
952+
953+
let Some(document_node) = document_node else { return Vec::new() };
954+
let Some(number_input) = document_node.inputs.get(number_input_index) else {
955+
log::warn!("A widget failed to be built because its node's input index is invalid.");
956+
return vec![];
957+
};
958+
let Some(bool_input) = document_node.inputs.get(bool_input_index) else {
959+
log::warn!("A widget failed to be built because its node's input index is invalid.");
960+
return vec![];
961+
};
962+
if let (Some(&TaggedValue::Bool(enabled)), Some(&TaggedValue::F64(number))) = (bool_input.as_non_exposed_value(), number_input.as_non_exposed_value()) {
963+
widgets.extend_from_slice(&[
964+
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
965+
Separator::new(SeparatorStyle::Related).widget_instance(),
966+
// The checkbox toggles if the value is Some or None
967+
CheckboxInput::new(enabled)
968+
.on_update(update_value(|x: &CheckboxInput| TaggedValue::Bool(x.checked), node_id, bool_input_index))
969+
.on_commit(commit_value)
970+
.widget_instance(),
971+
Separator::new(SeparatorStyle::Related).widget_instance(),
972+
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
973+
number_props
974+
.value(Some(number))
975+
.on_update(update_value(move |x: &NumberInput| TaggedValue::F64(x.value.unwrap_or_default()), node_id, number_input_index))
976+
.disabled(!enabled)
977+
.on_commit(commit_value)
978+
.widget_instance(),
979+
]);
980+
}
981+
982+
widgets
983+
}
984+
942985
pub fn number_widget(parameter_widgets_info: ParameterWidgetsInfo, number_props: NumberInput) -> Vec<WidgetInstance> {
943986
let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info;
944987

@@ -982,27 +1025,6 @@ pub fn number_widget(parameter_widgets_info: ParameterWidgetsInfo, number_props:
9821025
.on_commit(commit_value)
9831026
.widget_instance(),
9841027
]),
985-
Some(&TaggedValue::OptionalF64(x)) => {
986-
// TODO: Don't wipe out the previously set value (setting it back to the default of 100) when reenabling this checkbox back to Some from None
987-
let toggle_enabled = move |checkbox_input: &CheckboxInput| TaggedValue::OptionalF64(if checkbox_input.checked { Some(100.) } else { None });
988-
widgets.extend_from_slice(&[
989-
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
990-
Separator::new(SeparatorStyle::Related).widget_instance(),
991-
// The checkbox toggles if the value is Some or None
992-
CheckboxInput::new(x.is_some())
993-
.on_update(update_value(toggle_enabled, node_id, index))
994-
.on_commit(commit_value)
995-
.widget_instance(),
996-
Separator::new(SeparatorStyle::Related).widget_instance(),
997-
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
998-
number_props
999-
.value(x)
1000-
.on_update(update_value(move |x: &NumberInput| TaggedValue::OptionalF64(x.value), node_id, index))
1001-
.disabled(x.is_none())
1002-
.on_commit(commit_value)
1003-
.widget_instance(),
1004-
]);
1005-
}
10061028
Some(&TaggedValue::DVec2(dvec2)) => widgets.extend_from_slice(&[
10071029
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
10081030
number_props
@@ -1087,14 +1109,6 @@ pub fn color_widget(parameter_widgets_info: ParameterWidgetsInfo, color_button:
10871109
.on_commit(commit_value)
10881110
.widget_instance(),
10891111
),
1090-
TaggedValue::OptionalColorNotInTable(color) => widgets.push(
1091-
color_button
1092-
.value(color.map_or(FillChoice::None, FillChoice::Solid))
1093-
.allow_none(true)
1094-
.on_update(update_value(|input: &ColorInput| TaggedValue::OptionalColorNotInTable(input.value.as_solid()), node_id, index))
1095-
.on_commit(commit_value)
1096-
.widget_instance(),
1097-
),
10981112
TaggedValue::Color(color_table) => widgets.push(
10991113
color_button
11001114
.value(match color_table.iter().next() {

0 commit comments

Comments
 (0)