mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-19 02:48:12 +08:00
Add a family of 14 new string processing nodes (#4010)
* Add new string processing nodes
* Remove the IntegerCount = u32 type alias
* Add the 'Format Number' node
* Add "Up To" parameter to the 'String Pad' node
* Fix 'String Capitalization' behavior
* Add 'Map String' and 'Read String' nodes
* Add separator_escaping to 'String Repeat'
* Add 'Regex Replace'
* Add 'Regex Match' node
* Regex Find and Regex Find All
* Code review
* Add the 'Escape String' node
* Improve implementations
* Move nodes from logic.rs to text/src/lib.rs
* Clean up migrations
* Fix #[{hard, soft}_{min, max}(...)] node macro attribute
* Improve Data panel number and text display
* Add the 'Query JSON' and 'Query JSON All' nodes
* Add the 'Lorem Ipsum' node and Ipsum library
* Add the 14 nodes back in their final state
* Add handling for fixed decimal places in number formatting
* Code review fixes
This commit is contained in:
@@ -2035,6 +2035,7 @@ fn static_node_properties() -> NodeProperties {
|
||||
map.insert("selective_color_properties".to_string(), Box::new(node_properties::selective_color_properties));
|
||||
map.insert("exposure_properties".to_string(), Box::new(node_properties::exposure_properties));
|
||||
map.insert("math_properties".to_string(), Box::new(node_properties::math_properties));
|
||||
map.insert("format_number_properties".to_string(), Box::new(node_properties::format_number_properties));
|
||||
map.insert("string_capitalization_properties".to_string(), Box::new(node_properties::string_capitalization_properties));
|
||||
map.insert("rectangle_properties".to_string(), Box::new(node_properties::rectangle_properties));
|
||||
map.insert("grid_properties".to_string(), Box::new(node_properties::grid_properties));
|
||||
|
||||
@@ -134,18 +134,13 @@ pub fn start_widgets(parameter_widgets_info: ParameterWidgetsInfo) -> Vec<Widget
|
||||
}
|
||||
widgets.push(TextLabel::new(name).tooltip_description(description).widget_instance());
|
||||
|
||||
let mut blank_assist = blank_assist;
|
||||
if input.is_exposed() {
|
||||
if blank_assist {
|
||||
add_blank_assist(&mut widgets);
|
||||
blank_assist = false;
|
||||
}
|
||||
widgets.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());
|
||||
widgets.push(jump_to_source_widget(input, network_interface, selection_network_path));
|
||||
if blank_assist || input.is_exposed() {
|
||||
add_blank_assist(&mut widgets);
|
||||
}
|
||||
|
||||
if blank_assist {
|
||||
add_blank_assist(&mut widgets);
|
||||
if input.is_exposed() {
|
||||
widgets.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());
|
||||
widgets.push(jump_to_source_widget(input, network_interface, selection_network_path));
|
||||
}
|
||||
|
||||
widgets
|
||||
@@ -1630,6 +1625,91 @@ pub(crate) fn exposure_properties(node_id: NodeId, context: &mut NodePropertiesC
|
||||
vec![LayoutGroup::row(exposure), LayoutGroup::row(offset), LayoutGroup::row(gamma_correction)]
|
||||
}
|
||||
|
||||
pub(crate) fn format_number_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
use graphene_std::text_nodes::format_number::{DecimalPlacesInput, DecimalSeparatorInput, FixedDecimalsInput, StartAt10000Input, ThousandsSeparatorInput, UseThousandsSeparatorInput};
|
||||
|
||||
// Read current values before borrowing context mutably for widgets
|
||||
let (no_decimals, decimal_sep_value, use_thousands, thousands_sep_value) = match get_document_node(node_id, context) {
|
||||
Ok(document_node) => {
|
||||
let decimal_places = match document_node.inputs.get(DecimalPlacesInput::INDEX).and_then(|input| input.as_value()) {
|
||||
Some(&TaggedValue::U32(x)) => x,
|
||||
_ => 2,
|
||||
};
|
||||
let decimal_sep = match document_node.inputs.get(DecimalSeparatorInput::INDEX).and_then(|input| input.as_non_exposed_value()) {
|
||||
Some(TaggedValue::String(x)) => Some(x.clone()),
|
||||
_ => None,
|
||||
};
|
||||
let use_thousands = match document_node.inputs.get(UseThousandsSeparatorInput::INDEX).and_then(|input| input.as_value()) {
|
||||
Some(&TaggedValue::Bool(x)) => x,
|
||||
_ => false,
|
||||
};
|
||||
let use_thousands = use_thousands || document_node.inputs.get(ThousandsSeparatorInput::INDEX).is_some_and(|input| input.is_exposed());
|
||||
let thousands_sep = match document_node.inputs.get(ThousandsSeparatorInput::INDEX).and_then(|input| input.as_non_exposed_value()) {
|
||||
Some(TaggedValue::String(x)) => Some(x.clone()),
|
||||
_ => None,
|
||||
};
|
||||
(decimal_places == 0, decimal_sep, use_thousands, thousands_sep)
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("Could not get document node in format_number_properties: {err}");
|
||||
return Vec::new();
|
||||
}
|
||||
};
|
||||
|
||||
let decimal_places = number_widget(ParameterWidgetsInfo::new(node_id, DecimalPlacesInput::INDEX, true, context), NumberInput::default().min(0.).int());
|
||||
|
||||
// Fixed decimals and decimal separator are disabled when decimal places is 0
|
||||
let fixed_decimals = bool_widget(
|
||||
ParameterWidgetsInfo::new(node_id, FixedDecimalsInput::INDEX, true, context),
|
||||
CheckboxInput::default().disabled(no_decimals),
|
||||
);
|
||||
let mut decimal_sep_widgets = start_widgets(ParameterWidgetsInfo::new(node_id, DecimalSeparatorInput::INDEX, true, context));
|
||||
if let Some(sep) = decimal_sep_value {
|
||||
decimal_sep_widgets.extend_from_slice(&[
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
TextInput::new(sep)
|
||||
.disabled(no_decimals)
|
||||
.on_update(update_value(|x: &TextInput| TaggedValue::String(x.value.clone()), node_id, DecimalSeparatorInput::INDEX))
|
||||
.on_commit(commit_value)
|
||||
.widget_instance(),
|
||||
]);
|
||||
}
|
||||
|
||||
// Thousands separator: checkbox in assist area
|
||||
let mut thousands_sep_widgets = start_widgets(ParameterWidgetsInfo::new(node_id, ThousandsSeparatorInput::INDEX, false, context));
|
||||
if let Some(sep) = thousands_sep_value {
|
||||
thousands_sep_widgets.extend_from_slice(&[
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
Separator::new(SeparatorStyle::Related).widget_instance(),
|
||||
CheckboxInput::new(use_thousands)
|
||||
.on_update(update_value(|x: &CheckboxInput| TaggedValue::Bool(x.checked), node_id, UseThousandsSeparatorInput::INDEX))
|
||||
.on_commit(commit_value)
|
||||
.widget_instance(),
|
||||
Separator::new(SeparatorStyle::Related).widget_instance(),
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
TextInput::new(sep)
|
||||
.disabled(!use_thousands)
|
||||
.on_update(update_value(|x: &TextInput| TaggedValue::String(x.value.clone()), node_id, ThousandsSeparatorInput::INDEX))
|
||||
.on_commit(commit_value)
|
||||
.widget_instance(),
|
||||
]);
|
||||
}
|
||||
|
||||
// Start at 10,000: disabled when thousands separator is off
|
||||
let start_at_10000 = bool_widget(
|
||||
ParameterWidgetsInfo::new(node_id, StartAt10000Input::INDEX, true, context),
|
||||
CheckboxInput::default().disabled(!use_thousands),
|
||||
);
|
||||
|
||||
vec![
|
||||
LayoutGroup::row(decimal_places),
|
||||
LayoutGroup::row(decimal_sep_widgets),
|
||||
LayoutGroup::row(fixed_decimals),
|
||||
LayoutGroup::row(thousands_sep_widgets),
|
||||
LayoutGroup::row(start_at_10000),
|
||||
]
|
||||
}
|
||||
|
||||
pub(crate) fn string_capitalization_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
use graphene_std::text_nodes::string_capitalization::*;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user