Replace all hard-coded magic number node input indices with *Input::INDEX constants

This commit is contained in:
Keavon Chambers 2025-06-22 23:18:34 -07:00
parent 930278128d
commit ae88f4a3de
3 changed files with 157 additions and 134 deletions

View file

@ -567,7 +567,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(DocumentMessage::AddTransaction); responses.add(DocumentMessage::AddTransaction);
let new_ids: HashMap<_, _> = data.iter().map(|(id, _)| (*id, NodeId::new())).collect(); let new_ids: HashMap<_, _> = data.iter().map(|(id, _)| (*id, NodeId::new())).collect();
let nodes: Vec<_> = new_ids.iter().map(|(_, id)| *id).collect(); let nodes: Vec<_> = new_ids.values().copied().collect();
responses.add(NodeGraphMessage::AddNodes { responses.add(NodeGraphMessage::AddNodes {
nodes: data, nodes: data,
new_ids: new_ids.clone(), new_ids: new_ids.clone(),

View file

@ -22,7 +22,6 @@ use graphene_std::raster_types::{CPU, GPU, RasterDataTable};
use graphene_std::text::Font; use graphene_std::text::Font;
use graphene_std::transform::{Footprint, ReferencePoint}; use graphene_std::transform::{Footprint, ReferencePoint};
use graphene_std::vector::VectorDataTable; use graphene_std::vector::VectorDataTable;
use graphene_std::vector::generator_nodes::grid;
use graphene_std::vector::misc::CentroidType; use graphene_std::vector::misc::CentroidType;
use graphene_std::vector::misc::{ArcType, MergeByDistanceAlgorithm}; use graphene_std::vector::misc::{ArcType, MergeByDistanceAlgorithm};
use graphene_std::vector::misc::{BooleanOperation, GridType}; use graphene_std::vector::misc::{BooleanOperation, GridType};
@ -939,8 +938,7 @@ pub fn get_document_node<'a>(node_id: NodeId, context: &'a NodePropertiesContext
} }
pub fn query_node_and_input_info<'a>(node_id: NodeId, input_index: usize, context: &'a NodePropertiesContext<'a>) -> Result<(&'a DocumentNode, &'a str, &'a str), String> { pub fn query_node_and_input_info<'a>(node_id: NodeId, input_index: usize, context: &'a NodePropertiesContext<'a>) -> Result<(&'a DocumentNode, &'a str, &'a str), String> {
let node_id2 = node_id.clone(); let document_node = get_document_node(node_id, context)?;
let document_node = get_document_node(node_id2, context)?;
let input_name = context.network_interface.input_name(node_id, input_index, context.selection_network_path).unwrap_or_else(|| { let input_name = context.network_interface.input_name(node_id, input_index, context.selection_network_path).unwrap_or_else(|| {
log::warn!("input name not found in query_node_and_input_info"); log::warn!("input name not found in query_node_and_input_info");
"" ""
@ -982,16 +980,19 @@ pub fn query_noise_pattern_state(node_id: NodeId, context: &NodePropertiesContex
} }
pub fn query_assign_colors_randomize(node_id: NodeId, context: &NodePropertiesContext) -> Result<bool, String> { pub fn query_assign_colors_randomize(node_id: NodeId, context: &NodePropertiesContext) -> Result<bool, String> {
use graphene_std::vector::assign_colors::*;
let document_node = get_document_node(node_id, context)?; let document_node = get_document_node(node_id, context)?;
// This is safe since the node is a proto node and the implementation cannot be changed. // This is safe since the node is a proto node and the implementation cannot be changed.
let randomize_index = 5; Ok(match document_node.inputs.get(RandomizeInput::INDEX).and_then(|input| input.as_value()) {
Ok(match document_node.inputs.get(randomize_index).and_then(|input| input.as_value()) {
Some(TaggedValue::Bool(randomize_enabled)) => *randomize_enabled, Some(TaggedValue::Bool(randomize_enabled)) => *randomize_enabled,
_ => false, _ => false,
}) })
} }
pub(crate) fn brightness_contrast_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub(crate) fn brightness_contrast_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
use graphene_std::raster::brightness_contrast::*;
let document_node = match get_document_node(node_id, context) { let document_node = match get_document_node(node_id, context) {
Ok(document_node) => document_node, Ok(document_node) => document_node,
Err(err) => { Err(err) => {
@ -1001,17 +1002,18 @@ pub(crate) fn brightness_contrast_properties(node_id: NodeId, context: &mut Node
}; };
// Use Classic // Use Classic
let use_classic_index = 3; let use_classic = bool_widget(
let use_classic = bool_widget(ParameterWidgetsInfo::from_index(document_node, node_id, use_classic_index, true, context), CheckboxInput::default()); ParameterWidgetsInfo::from_index(document_node, node_id, UseClassicInput::INDEX, true, context),
let use_classic_value = match document_node.inputs[use_classic_index].as_value() { CheckboxInput::default(),
);
let use_classic_value = match document_node.inputs[UseClassicInput::INDEX].as_value() {
Some(TaggedValue::Bool(use_classic_choice)) => *use_classic_choice, Some(TaggedValue::Bool(use_classic_choice)) => *use_classic_choice,
_ => false, _ => false,
}; };
// Brightness // Brightness
let brightness_index = 1;
let brightness = number_widget( let brightness = number_widget(
ParameterWidgetsInfo::from_index(document_node, node_id, brightness_index, true, context), ParameterWidgetsInfo::from_index(document_node, node_id, BrightnessInput::INDEX, true, context),
NumberInput::default() NumberInput::default()
.unit("%") .unit("%")
.mode_range() .mode_range()
@ -1021,9 +1023,8 @@ pub(crate) fn brightness_contrast_properties(node_id: NodeId, context: &mut Node
); );
// Contrast // Contrast
let contrast_index = 2;
let contrast = number_widget( let contrast = number_widget(
ParameterWidgetsInfo::from_index(document_node, node_id, contrast_index, true, context), ParameterWidgetsInfo::from_index(document_node, node_id, ContrastInput::INDEX, true, context),
NumberInput::default() NumberInput::default()
.unit("%") .unit("%")
.mode_range() .mode_range()
@ -1042,6 +1043,8 @@ pub(crate) fn brightness_contrast_properties(node_id: NodeId, context: &mut Node
} }
pub(crate) fn channel_mixer_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub(crate) fn channel_mixer_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
use graphene_std::raster::channel_mixer::*;
let document_node = match get_document_node(node_id, context) { let document_node = match get_document_node(node_id, context) {
Ok(document_node) => document_node, Ok(document_node) => document_node,
Err(err) => { Err(err) => {
@ -1051,20 +1054,21 @@ pub(crate) fn channel_mixer_properties(node_id: NodeId, context: &mut NodeProper
}; };
// Monochrome // Monochrome
let monochrome_index = 1; let is_monochrome = bool_widget(
let is_monochrome = bool_widget(ParameterWidgetsInfo::from_index(document_node, node_id, monochrome_index, true, context), CheckboxInput::default()); ParameterWidgetsInfo::from_index(document_node, node_id, MonochromeInput::INDEX, true, context),
let is_monochrome_value = match document_node.inputs[monochrome_index].as_value() { CheckboxInput::default(),
);
let is_monochrome_value = match document_node.inputs[MonochromeInput::INDEX].as_value() {
Some(TaggedValue::Bool(monochrome_choice)) => *monochrome_choice, Some(TaggedValue::Bool(monochrome_choice)) => *monochrome_choice,
_ => false, _ => false,
}; };
// Output channel choice // Output channel choice
let output_channel_index = 18;
let output_channel = enum_choice::<RedGreenBlue>() let output_channel = enum_choice::<RedGreenBlue>()
.for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, output_channel_index, true, context)) .for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, OutputChannelInput::INDEX, true, context))
.exposable(false) .exposable(false)
.property_row(); .property_row();
let output_channel_value = match &document_node.inputs[output_channel_index].as_value() { let output_channel_value = match &document_node.inputs[OutputChannelInput::INDEX].as_value() {
Some(TaggedValue::RedGreenBlue(choice)) => choice, Some(TaggedValue::RedGreenBlue(choice)) => choice,
_ => { _ => {
warn!("Channel Mixer node properties panel could not be displayed."); warn!("Channel Mixer node properties panel could not be displayed.");
@ -1074,10 +1078,10 @@ pub(crate) fn channel_mixer_properties(node_id: NodeId, context: &mut NodeProper
// Output Channel modes // Output Channel modes
let (red_output_index, green_output_index, blue_output_index, constant_output_index) = match (is_monochrome_value, output_channel_value) { let (red_output_index, green_output_index, blue_output_index, constant_output_index) = match (is_monochrome_value, output_channel_value) {
(true, _) => (2, 3, 4, 5), (true, _) => (MonochromeRInput::INDEX, MonochromeGInput::INDEX, MonochromeBInput::INDEX, MonochromeCInput::INDEX),
(false, RedGreenBlue::Red) => (6, 7, 8, 9), (false, RedGreenBlue::Red) => (RedRInput::INDEX, RedGInput::INDEX, RedBInput::INDEX, RedCInput::INDEX),
(false, RedGreenBlue::Green) => (10, 11, 12, 13), (false, RedGreenBlue::Green) => (GreenRInput::INDEX, GreenGInput::INDEX, GreenBInput::INDEX, GreenCInput::INDEX),
(false, RedGreenBlue::Blue) => (14, 15, 16, 17), (false, RedGreenBlue::Blue) => (BlueRInput::INDEX, BlueGInput::INDEX, BlueBInput::INDEX, BlueCInput::INDEX),
}; };
let number_input = NumberInput::default().mode_range().min(-200.).max(200.).unit("%"); let number_input = NumberInput::default().mode_range().min(-200.).max(200.).unit("%");
let red = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, red_output_index, true, context), number_input.clone()); let red = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, red_output_index, true, context), number_input.clone());
@ -1102,6 +1106,8 @@ pub(crate) fn channel_mixer_properties(node_id: NodeId, context: &mut NodeProper
} }
pub(crate) fn selective_color_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub(crate) fn selective_color_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
use graphene_std::raster::selective_color::*;
let document_node = match get_document_node(node_id, context) { let document_node = match get_document_node(node_id, context) {
Ok(document_node) => document_node, Ok(document_node) => document_node,
Err(err) => { Err(err) => {
@ -1109,15 +1115,14 @@ pub(crate) fn selective_color_properties(node_id: NodeId, context: &mut NodeProp
return Vec::new(); return Vec::new();
} }
}; };
// Colors choice
let colors_index = 38;
// Colors choice
let colors = enum_choice::<SelectiveColorChoice>() let colors = enum_choice::<SelectiveColorChoice>()
.for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, colors_index, true, context)) .for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, ColorsInput::INDEX, true, context))
.exposable(false) .exposable(false)
.property_row(); .property_row();
let colors_choice_index = match &document_node.inputs[colors_index].as_value() { let colors_choice = match &document_node.inputs[ColorsInput::INDEX].as_value() {
Some(TaggedValue::SelectiveColorChoice(choice)) => choice, Some(TaggedValue::SelectiveColorChoice(choice)) => choice,
_ => { _ => {
warn!("Selective Color node properties panel could not be displayed."); warn!("Selective Color node properties panel could not be displayed.");
@ -1126,16 +1131,16 @@ pub(crate) fn selective_color_properties(node_id: NodeId, context: &mut NodeProp
}; };
// CMYK // CMYK
let (c_index, m_index, y_index, k_index) = match colors_choice_index { let (c_index, m_index, y_index, k_index) = match colors_choice {
SelectiveColorChoice::Reds => (2, 3, 4, 5), SelectiveColorChoice::Reds => (RCInput::INDEX, RMInput::INDEX, RYInput::INDEX, RKInput::INDEX),
SelectiveColorChoice::Yellows => (6, 7, 8, 9), SelectiveColorChoice::Yellows => (YCInput::INDEX, YMInput::INDEX, YYInput::INDEX, YKInput::INDEX),
SelectiveColorChoice::Greens => (10, 11, 12, 13), SelectiveColorChoice::Greens => (GCInput::INDEX, GMInput::INDEX, GYInput::INDEX, GKInput::INDEX),
SelectiveColorChoice::Cyans => (14, 15, 16, 17), SelectiveColorChoice::Cyans => (CCInput::INDEX, CMInput::INDEX, CYInput::INDEX, CKInput::INDEX),
SelectiveColorChoice::Blues => (18, 19, 20, 21), SelectiveColorChoice::Blues => (BCInput::INDEX, BMInput::INDEX, BYInput::INDEX, BKInput::INDEX),
SelectiveColorChoice::Magentas => (22, 23, 24, 25), SelectiveColorChoice::Magentas => (MCInput::INDEX, MMInput::INDEX, MYInput::INDEX, MKInput::INDEX),
SelectiveColorChoice::Whites => (26, 27, 28, 29), SelectiveColorChoice::Whites => (WCInput::INDEX, WMInput::INDEX, WYInput::INDEX, WKInput::INDEX),
SelectiveColorChoice::Neutrals => (30, 31, 32, 33), SelectiveColorChoice::Neutrals => (NCInput::INDEX, NMInput::INDEX, NYInput::INDEX, NKInput::INDEX),
SelectiveColorChoice::Blacks => (34, 35, 36, 37), SelectiveColorChoice::Blacks => (KCInput::INDEX, KMInput::INDEX, KYInput::INDEX, KKInput::INDEX),
}; };
let number_input = NumberInput::default().mode_range().min(-100.).max(100.).unit("%"); let number_input = NumberInput::default().mode_range().min(-100.).max(100.).unit("%");
let cyan = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, c_index, true, context), number_input.clone()); let cyan = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, c_index, true, context), number_input.clone());
@ -1144,9 +1149,8 @@ pub(crate) fn selective_color_properties(node_id: NodeId, context: &mut NodeProp
let black = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, k_index, true, context), number_input); let black = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, k_index, true, context), number_input);
// Mode // Mode
let mode_index = 1;
let mode = enum_choice::<RelativeAbsolute>() let mode = enum_choice::<RelativeAbsolute>()
.for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, mode_index, true, context)) .for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, ModeInput::INDEX, true, context))
.property_row(); .property_row();
vec![ vec![
@ -1163,11 +1167,7 @@ pub(crate) fn selective_color_properties(node_id: NodeId, context: &mut NodeProp
} }
pub(crate) fn grid_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub(crate) fn grid_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let grid_type_index = grid::GridTypeInput::INDEX; use graphene_std::vector::generator_nodes::grid::*;
let spacing_index = grid::SpacingInput::<f64>::INDEX;
let angles_index = grid::AnglesInput::INDEX;
let rows_index = grid::RowsInput::INDEX;
let columns_index = grid::ColumnsInput::INDEX;
let document_node = match get_document_node(node_id, context) { let document_node = match get_document_node(node_id, context) {
Ok(document_node) => document_node, Ok(document_node) => document_node,
@ -1177,36 +1177,48 @@ pub(crate) fn grid_properties(node_id: NodeId, context: &mut NodePropertiesConte
} }
}; };
let grid_type = enum_choice::<GridType>() let grid_type = enum_choice::<GridType>()
.for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, grid_type_index, true, context)) .for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, GridTypeInput::INDEX, true, context))
.property_row(); .property_row();
let mut widgets = vec![grid_type]; let mut widgets = vec![grid_type];
let Some(grid_type_input) = document_node.inputs.get(grid_type_index) else { let Some(grid_type_input) = document_node.inputs.get(GridTypeInput::INDEX) else {
log::warn!("A widget failed to be built because its node's input index is invalid."); log::warn!("A widget failed to be built because its node's input index is invalid.");
return vec![]; return vec![];
}; };
if let Some(&TaggedValue::GridType(grid_type)) = grid_type_input.as_non_exposed_value() { if let Some(&TaggedValue::GridType(grid_type)) = grid_type_input.as_non_exposed_value() {
match grid_type { match grid_type {
GridType::Rectangular => { GridType::Rectangular => {
let spacing = coordinate_widget(ParameterWidgetsInfo::from_index(document_node, node_id, spacing_index, true, context), "W", "H", " px", Some(0.)); let spacing = coordinate_widget(
ParameterWidgetsInfo::from_index(document_node, node_id, SpacingInput::<f64>::INDEX, true, context),
"W",
"H",
" px",
Some(0.),
);
widgets.push(spacing); widgets.push(spacing);
} }
GridType::Isometric => { GridType::Isometric => {
let spacing = LayoutGroup::Row { let spacing = LayoutGroup::Row {
widgets: number_widget( widgets: number_widget(
ParameterWidgetsInfo::from_index(document_node, node_id, spacing_index, true, context), ParameterWidgetsInfo::from_index(document_node, node_id, SpacingInput::<f64>::INDEX, true, context),
NumberInput::default().label("H").min(0.).unit(" px"), NumberInput::default().label("H").min(0.).unit(" px"),
), ),
}; };
let angles = coordinate_widget(ParameterWidgetsInfo::from_index(document_node, node_id, angles_index, true, context), "", "", "°", None); let angles = coordinate_widget(ParameterWidgetsInfo::from_index(document_node, node_id, AnglesInput::INDEX, true, context), "", "", "°", None);
widgets.extend([spacing, angles]); widgets.extend([spacing, angles]);
} }
} }
} }
let rows = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, rows_index, true, context), NumberInput::default().min(1.)); let rows = number_widget(
let columns = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, columns_index, true, context), NumberInput::default().min(1.)); ParameterWidgetsInfo::from_index(document_node, node_id, RowsInput::INDEX, true, context),
NumberInput::default().min(1.),
);
let columns = number_widget(
ParameterWidgetsInfo::from_index(document_node, node_id, ColumnsInput::INDEX, true, context),
NumberInput::default().min(1.),
);
widgets.extend([LayoutGroup::Row { widgets: rows }, LayoutGroup::Row { widgets: columns }]); widgets.extend([LayoutGroup::Row { widgets: rows }, LayoutGroup::Row { widgets: columns }]);
@ -1214,6 +1226,8 @@ pub(crate) fn grid_properties(node_id: NodeId, context: &mut NodePropertiesConte
} }
pub(crate) fn exposure_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub(crate) fn exposure_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
use graphene_std::raster::exposure::*;
let document_node = match get_document_node(node_id, context) { let document_node = match get_document_node(node_id, context) {
Ok(document_node) => document_node, Ok(document_node) => document_node,
Err(err) => { Err(err) => {
@ -1221,10 +1235,16 @@ pub(crate) fn exposure_properties(node_id: NodeId, context: &mut NodePropertiesC
return Vec::new(); return Vec::new();
} }
}; };
let exposure = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, 1, true, context), NumberInput::default().min(-20.).max(20.)); let exposure = number_widget(
let offset = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, 2, true, context), NumberInput::default().min(-0.5).max(0.5)); ParameterWidgetsInfo::from_index(document_node, node_id, ExposureInput::INDEX, true, context),
NumberInput::default().min(-20.).max(20.),
);
let offset = number_widget(
ParameterWidgetsInfo::from_index(document_node, node_id, OffsetInput::INDEX, true, context),
NumberInput::default().min(-0.5).max(0.5),
);
let gamma_correction = number_widget( let gamma_correction = number_widget(
ParameterWidgetsInfo::from_index(document_node, node_id, 3, true, context), ParameterWidgetsInfo::from_index(document_node, node_id, GammaCorrectionInput::INDEX, true, context),
NumberInput::default().min(0.01).max(9.99).increment_step(0.1), NumberInput::default().min(0.01).max(9.99).increment_step(0.1),
); );
@ -1236,6 +1256,8 @@ pub(crate) fn exposure_properties(node_id: NodeId, context: &mut NodePropertiesC
} }
pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
use graphene_std::vector::generator_nodes::rectangle::*;
let document_node = match get_document_node(node_id, context) { let document_node = match get_document_node(node_id, context) {
Ok(document_node) => document_node, Ok(document_node) => document_node,
Err(err) => { Err(err) => {
@ -1243,21 +1265,15 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
return Vec::new(); return Vec::new();
} }
}; };
let size_x_index = 1;
let size_y_index = 2;
let corner_rounding_type_index = 3;
let corner_radius_index = 4;
let clamped_index = 5;
// Size X // Size X
let size_x = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, size_x_index, true, context), NumberInput::default()); let size_x = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, WidthInput::INDEX, true, context), NumberInput::default());
// Size Y // Size Y
let size_y = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, size_y_index, true, context), NumberInput::default()); let size_y = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, HeightInput::INDEX, true, context), NumberInput::default());
// Corner Radius // Corner Radius
let mut corner_radius_row_1 = start_widgets( let mut corner_radius_row_1 = start_widgets(
ParameterWidgetsInfo::from_index(document_node, node_id, corner_radius_index, true, context), ParameterWidgetsInfo::from_index(document_node, node_id, CornerRadiusInput::<f64>::INDEX, true, context),
FrontendGraphDataType::Number, FrontendGraphDataType::Number,
); );
corner_radius_row_1.push(Separator::new(SeparatorType::Unrelated).widget_holder()); corner_radius_row_1.push(Separator::new(SeparatorType::Unrelated).widget_holder());
@ -1266,13 +1282,13 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
corner_radius_row_2.push(TextLabel::new("").widget_holder()); corner_radius_row_2.push(TextLabel::new("").widget_holder());
add_blank_assist(&mut corner_radius_row_2); add_blank_assist(&mut corner_radius_row_2);
let Some(input) = document_node.inputs.get(corner_rounding_type_index) else { let Some(input) = document_node.inputs.get(IndividualCornerRadiiInput::INDEX) else {
log::warn!("A widget failed to be built because its node's input index is invalid."); log::warn!("A widget failed to be built because its node's input index is invalid.");
return vec![]; return vec![];
}; };
if let Some(&TaggedValue::Bool(is_individual)) = input.as_non_exposed_value() { if let Some(&TaggedValue::Bool(is_individual)) = input.as_non_exposed_value() {
// Values // Values
let Some(input) = document_node.inputs.get(corner_radius_index) else { let Some(input) = document_node.inputs.get(CornerRadiusInput::<f64>::INDEX) else {
log::warn!("A widget failed to be built because its node's input index is invalid."); log::warn!("A widget failed to be built because its node's input index is invalid.");
return vec![]; return vec![];
}; };
@ -1294,13 +1310,13 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
Message::Batched(Box::new([ Message::Batched(Box::new([
NodeGraphMessage::SetInputValue { NodeGraphMessage::SetInputValue {
node_id, node_id,
input_index: corner_rounding_type_index, input_index: IndividualCornerRadiiInput::INDEX,
value: TaggedValue::Bool(false), value: TaggedValue::Bool(false),
} }
.into(), .into(),
NodeGraphMessage::SetInputValue { NodeGraphMessage::SetInputValue {
node_id, node_id,
input_index: corner_radius_index, input_index: CornerRadiusInput::<f64>::INDEX,
value: TaggedValue::F64(uniform_val), value: TaggedValue::F64(uniform_val),
} }
.into(), .into(),
@ -1313,13 +1329,13 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
Message::Batched(Box::new([ Message::Batched(Box::new([
NodeGraphMessage::SetInputValue { NodeGraphMessage::SetInputValue {
node_id, node_id,
input_index: corner_rounding_type_index, input_index: IndividualCornerRadiiInput::INDEX,
value: TaggedValue::Bool(true), value: TaggedValue::Bool(true),
} }
.into(), .into(),
NodeGraphMessage::SetInputValue { NodeGraphMessage::SetInputValue {
node_id, node_id,
input_index: corner_radius_index, input_index: CornerRadiusInput::<f64>::INDEX,
value: TaggedValue::F64Array4(individual_val), value: TaggedValue::F64Array4(individual_val),
} }
.into(), .into(),
@ -1346,12 +1362,12 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
}; };
TextInput::default() TextInput::default()
.value(individual_val.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", ")) .value(individual_val.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", "))
.on_update(optionally_update_value(move |x: &TextInput| from_string(&x.value), node_id, corner_radius_index)) .on_update(optionally_update_value(move |x: &TextInput| from_string(&x.value), node_id, CornerRadiusInput::<f64>::INDEX))
.widget_holder() .widget_holder()
} else { } else {
NumberInput::default() NumberInput::default()
.value(Some(uniform_val)) .value(Some(uniform_val))
.on_update(update_value(move |x: &NumberInput| TaggedValue::F64(x.value.unwrap()), node_id, corner_radius_index)) .on_update(update_value(move |x: &NumberInput| TaggedValue::F64(x.value.unwrap()), node_id, CornerRadiusInput::<f64>::INDEX))
.on_commit(commit_value) .on_commit(commit_value)
.widget_holder() .widget_holder()
}; };
@ -1359,7 +1375,7 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
} }
// Clamped // Clamped
let clamped = bool_widget(ParameterWidgetsInfo::from_index(document_node, node_id, clamped_index, true, context), CheckboxInput::default()); let clamped = bool_widget(ParameterWidgetsInfo::from_index(document_node, node_id, ClampedInput::INDEX, true, context), CheckboxInput::default());
vec![ vec![
LayoutGroup::Row { widgets: size_x }, LayoutGroup::Row { widgets: size_x },
@ -1486,6 +1502,8 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper
/// Fill Node Widgets LayoutGroup /// Fill Node Widgets LayoutGroup
pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
use graphene_std::vector::fill::*;
let document_node = match get_document_node(node_id, context) { let document_node = match get_document_node(node_id, context) {
Ok(document_node) => document_node, Ok(document_node) => document_node,
Err(err) => { Err(err) => {
@ -1493,16 +1511,16 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
return Vec::new(); return Vec::new();
} }
}; };
let fill_index = 1;
let backup_color_index = 2;
let backup_gradient_index = 3;
let mut widgets_first_row = start_widgets(ParameterWidgetsInfo::from_index(document_node, node_id, fill_index, true, context), FrontendGraphDataType::General); let mut widgets_first_row = start_widgets(
ParameterWidgetsInfo::from_index(document_node, node_id, FillInput::<Color>::INDEX, true, context),
FrontendGraphDataType::General,
);
let (fill, backup_color, backup_gradient) = if let (Some(TaggedValue::Fill(fill)), &Some(&TaggedValue::OptionalColor(backup_color)), Some(TaggedValue::Gradient(backup_gradient))) = ( let (fill, backup_color, backup_gradient) = if let (Some(TaggedValue::Fill(fill)), &Some(&TaggedValue::OptionalColor(backup_color)), Some(TaggedValue::Gradient(backup_gradient))) = (
&document_node.inputs[fill_index].as_value(), &document_node.inputs[FillInput::<Color>::INDEX].as_value(),
&document_node.inputs[backup_color_index].as_value(), &document_node.inputs[BackupColorInput::INDEX].as_value(),
&document_node.inputs[backup_gradient_index].as_value(), &document_node.inputs[BackupGradientInput::INDEX].as_value(),
) { ) {
(fill, backup_color, backup_gradient) (fill, backup_color, backup_gradient)
} else { } else {
@ -1521,26 +1539,26 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
match &fill2 { match &fill2 {
Fill::None => NodeGraphMessage::SetInputValue { Fill::None => NodeGraphMessage::SetInputValue {
node_id, node_id,
input_index: backup_color_index, input_index: BackupColorInput::INDEX,
value: TaggedValue::OptionalColor(None), value: TaggedValue::OptionalColor(None),
} }
.into(), .into(),
Fill::Solid(color) => NodeGraphMessage::SetInputValue { Fill::Solid(color) => NodeGraphMessage::SetInputValue {
node_id, node_id,
input_index: backup_color_index, input_index: BackupColorInput::INDEX,
value: TaggedValue::OptionalColor(Some(*color)), value: TaggedValue::OptionalColor(Some(*color)),
} }
.into(), .into(),
Fill::Gradient(gradient) => NodeGraphMessage::SetInputValue { Fill::Gradient(gradient) => NodeGraphMessage::SetInputValue {
node_id, node_id,
input_index: backup_gradient_index, input_index: BackupGradientInput::INDEX,
value: TaggedValue::Gradient(gradient.clone()), value: TaggedValue::Gradient(gradient.clone()),
} }
.into(), .into(),
}, },
NodeGraphMessage::SetInputValue { NodeGraphMessage::SetInputValue {
node_id, node_id,
input_index: fill_index, input_index: FillInput::<Color>::INDEX,
value: TaggedValue::Fill(x.value.to_fill(fill2.as_gradient())), value: TaggedValue::Fill(x.value.to_fill(fill2.as_gradient())),
} }
.into(), .into(),
@ -1568,7 +1586,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
} }
}, },
node_id, node_id,
fill_index, FillInput::<Color>::INDEX,
)) ))
.widget_holder(); .widget_holder();
row.push(Separator::new(SeparatorType::Unrelated).widget_holder()); row.push(Separator::new(SeparatorType::Unrelated).widget_holder());
@ -1579,11 +1597,11 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
let entries = vec![ let entries = vec![
RadioEntryData::new("solid") RadioEntryData::new("solid")
.label("Solid") .label("Solid")
.on_update(update_value(move |_| TaggedValue::Fill(backup_color_fill.clone()), node_id, fill_index)) .on_update(update_value(move |_| TaggedValue::Fill(backup_color_fill.clone()), node_id, FillInput::<Color>::INDEX))
.on_commit(commit_value), .on_commit(commit_value),
RadioEntryData::new("gradient") RadioEntryData::new("gradient")
.label("Gradient") .label("Gradient")
.on_update(update_value(move |_| TaggedValue::Fill(backup_gradient_fill.clone()), node_id, fill_index)) .on_update(update_value(move |_| TaggedValue::Fill(backup_gradient_fill.clone()), node_id, FillInput::<Color>::INDEX))
.on_commit(commit_value), .on_commit(commit_value),
]; ];
@ -1618,7 +1636,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
} }
}, },
node_id, node_id,
fill_index, FillInput::<Color>::INDEX,
)) ))
.widget_holder(); .widget_holder();
row.push(Separator::new(SeparatorType::Unrelated).widget_holder()); row.push(Separator::new(SeparatorType::Unrelated).widget_holder());
@ -1639,7 +1657,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
TaggedValue::Fill(Fill::Gradient(new_gradient)) TaggedValue::Fill(Fill::Gradient(new_gradient))
}, },
node_id, node_id,
fill_index, FillInput::<Color>::INDEX,
)) ))
.on_commit(commit_value), .on_commit(commit_value),
RadioEntryData::new("Radial") RadioEntryData::new("Radial")
@ -1651,7 +1669,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
TaggedValue::Fill(Fill::Gradient(new_gradient)) TaggedValue::Fill(Fill::Gradient(new_gradient))
}, },
node_id, node_id,
fill_index, FillInput::<Color>::INDEX,
)) ))
.on_commit(commit_value), .on_commit(commit_value),
]; ];
@ -1668,6 +1686,8 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
} }
pub fn stroke_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub fn stroke_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
use graphene_std::vector::stroke::*;
let document_node = match get_document_node(node_id, context) { let document_node = match get_document_node(node_id, context) {
Ok(document_node) => document_node, Ok(document_node) => document_node,
Err(err) => { Err(err) => {
@ -1675,34 +1695,28 @@ pub fn stroke_properties(node_id: NodeId, context: &mut NodePropertiesContext) -
return Vec::new(); return Vec::new();
} }
}; };
let color_index = graphene_std::vector::stroke::ColorInput::<Option<Color>>::INDEX;
let weight_index = graphene_std::vector::stroke::WeightInput::INDEX;
let align_index = graphene_std::vector::stroke::AlignInput::INDEX;
let cap_index = graphene_std::vector::stroke::CapInput::INDEX;
let join_index = graphene_std::vector::stroke::JoinInput::INDEX;
let miter_limit_index = graphene_std::vector::stroke::MiterLimitInput::INDEX;
let paint_order_index = graphene_std::vector::stroke::PaintOrderInput::INDEX;
let dash_lengths_index = graphene_std::vector::stroke::DashLengthsInput::INDEX;
let dash_offset_index = graphene_std::vector::stroke::DashOffsetInput::INDEX;
let color = color_widget(ParameterWidgetsInfo::from_index(document_node, node_id, color_index, true, context), ColorInput::default()); let color = color_widget(
ParameterWidgetsInfo::from_index(document_node, node_id, ColorInput::<Option<Color>>::INDEX, true, context),
crate::messages::layout::utility_types::widgets::button_widgets::ColorInput::default(),
);
let weight = number_widget( let weight = number_widget(
ParameterWidgetsInfo::from_index(document_node, node_id, weight_index, true, context), ParameterWidgetsInfo::from_index(document_node, node_id, WeightInput::INDEX, true, context),
NumberInput::default().unit(" px").min(0.), NumberInput::default().unit(" px").min(0.),
); );
let align = enum_choice::<StrokeAlign>() let align = enum_choice::<StrokeAlign>()
.for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, align_index, true, context)) .for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, AlignInput::INDEX, true, context))
.property_row(); .property_row();
let cap = enum_choice::<StrokeCap>() let cap = enum_choice::<StrokeCap>()
.for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, cap_index, true, context)) .for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, CapInput::INDEX, true, context))
.property_row(); .property_row();
let join = enum_choice::<StrokeJoin>() let join = enum_choice::<StrokeJoin>()
.for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, join_index, true, context)) .for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, JoinInput::INDEX, true, context))
.property_row(); .property_row();
let miter_limit = number_widget( let miter_limit = number_widget(
ParameterWidgetsInfo::from_index(document_node, node_id, miter_limit_index, true, context), ParameterWidgetsInfo::from_index(document_node, node_id, MiterLimitInput::INDEX, true, context),
NumberInput::default().min(0.).disabled({ NumberInput::default().min(0.).disabled({
let join_value = match &document_node.inputs[join_index].as_value() { let join_value = match &document_node.inputs[JoinInput::INDEX].as_value() {
Some(TaggedValue::StrokeJoin(x)) => x, Some(TaggedValue::StrokeJoin(x)) => x,
_ => &StrokeJoin::Miter, _ => &StrokeJoin::Miter,
}; };
@ -1710,18 +1724,18 @@ pub fn stroke_properties(node_id: NodeId, context: &mut NodePropertiesContext) -
}), }),
); );
let paint_order = enum_choice::<PaintOrder>() let paint_order = enum_choice::<PaintOrder>()
.for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, paint_order_index, true, context)) .for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, PaintOrderInput::INDEX, true, context))
.property_row(); .property_row();
let dash_lengths_val = match &document_node.inputs[dash_lengths_index].as_value() { let dash_lengths_val = match &document_node.inputs[DashLengthsInput::INDEX].as_value() {
Some(TaggedValue::VecF64(x)) => x, Some(TaggedValue::VecF64(x)) => x,
_ => &vec![], _ => &vec![],
}; };
let dash_lengths = array_of_number_widget( let dash_lengths = array_of_number_widget(
ParameterWidgetsInfo::from_index(document_node, node_id, dash_lengths_index, true, context), ParameterWidgetsInfo::from_index(document_node, node_id, DashLengthsInput::INDEX, true, context),
TextInput::default().centered(true), TextInput::default().centered(true),
); );
let number_input = NumberInput::default().unit(" px").disabled(dash_lengths_val.is_empty()); let number_input = NumberInput::default().unit(" px").disabled(dash_lengths_val.is_empty());
let dash_offset = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, dash_offset_index, true, context), number_input); let dash_offset = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, DashOffsetInput::INDEX, true, context), number_input);
vec![ vec![
color, color,
@ -1737,6 +1751,8 @@ pub fn stroke_properties(node_id: NodeId, context: &mut NodePropertiesContext) -
} }
pub fn offset_path_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub fn offset_path_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
use graphene_std::vector::offset_path::*;
let document_node = match get_document_node(node_id, context) { let document_node = match get_document_node(node_id, context) {
Ok(document_node) => document_node, Ok(document_node) => document_node,
Err(err) => { Err(err) => {
@ -1744,30 +1760,28 @@ pub fn offset_path_properties(node_id: NodeId, context: &mut NodePropertiesConte
return Vec::new(); return Vec::new();
} }
}; };
let distance_index = graphene_std::vector::offset_path::DistanceInput::INDEX;
let join_index = graphene_std::vector::offset_path::JoinInput::INDEX;
let miter_limit_index = graphene_std::vector::offset_path::MiterLimitInput::INDEX;
let number_input = NumberInput::default().unit(" px"); let number_input = NumberInput::default().unit(" px");
let distance = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, distance_index, true, context), number_input); let distance = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, DistanceInput::INDEX, true, context), number_input);
let join = enum_choice::<StrokeJoin>() let join = enum_choice::<StrokeJoin>()
.for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, join_index, true, context)) .for_socket(ParameterWidgetsInfo::from_index(document_node, node_id, JoinInput::INDEX, true, context))
.property_row(); .property_row();
let number_input = NumberInput::default().min(0.).disabled({ let number_input = NumberInput::default().min(0.).disabled({
let join_val = match &document_node.inputs[join_index].as_value() { let join_val = match &document_node.inputs[JoinInput::INDEX].as_value() {
Some(TaggedValue::StrokeJoin(x)) => x, Some(TaggedValue::StrokeJoin(x)) => x,
_ => &StrokeJoin::Miter, _ => &StrokeJoin::Miter,
}; };
join_val != &StrokeJoin::Miter join_val != &StrokeJoin::Miter
}); });
let miter_limit = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, miter_limit_index, true, context), number_input); let miter_limit = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, MiterLimitInput::INDEX, true, context), number_input);
vec![LayoutGroup::Row { widgets: distance }, join, LayoutGroup::Row { widgets: miter_limit }] vec![LayoutGroup::Row { widgets: distance }, join, LayoutGroup::Row { widgets: miter_limit }]
} }
pub fn math_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub fn math_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
use graphene_std::ops::math::*;
let document_node = match get_document_node(node_id, context) { let document_node = match get_document_node(node_id, context) {
Ok(document_node) => document_node, Ok(document_node) => document_node,
Err(err) => { Err(err) => {
@ -1776,16 +1790,13 @@ pub fn math_properties(node_id: NodeId, context: &mut NodePropertiesContext) ->
} }
}; };
let expression_index = 1;
let operation_b_index = 2;
let expression = (|| { let expression = (|| {
let mut widgets = start_widgets( let mut widgets = start_widgets(
ParameterWidgetsInfo::from_index(document_node, node_id, expression_index, true, context), ParameterWidgetsInfo::from_index(document_node, node_id, ExpressionInput::INDEX, true, context),
FrontendGraphDataType::General, FrontendGraphDataType::General,
); );
let Some(input) = document_node.inputs.get(expression_index) else { let Some(input) = document_node.inputs.get(ExpressionInput::INDEX) else {
log::warn!("A widget failed to be built because its node's input index is invalid."); log::warn!("A widget failed to be built because its node's input index is invalid.");
return vec![]; return vec![];
}; };
@ -1809,7 +1820,7 @@ pub fn math_properties(node_id: NodeId, context: &mut NodePropertiesContext) ->
}) })
}, },
node_id, node_id,
expression_index, ExpressionInput::INDEX,
)) ))
.on_commit(commit_value) .on_commit(commit_value)
.widget_holder(), .widget_holder(),
@ -1817,7 +1828,10 @@ pub fn math_properties(node_id: NodeId, context: &mut NodePropertiesContext) ->
} }
widgets widgets
})(); })();
let operand_b = number_widget(ParameterWidgetsInfo::from_index(document_node, node_id, operation_b_index, true, context), NumberInput::default()); let operand_b = number_widget(
ParameterWidgetsInfo::from_index(document_node, node_id, OperandBInput::<f64>::INDEX, true, context),
NumberInput::default(),
);
let operand_a_hint = vec![TextLabel::new("(Operand A is the primary input)").widget_holder()]; let operand_a_hint = vec![TextLabel::new("(Operand A is the primary input)").widget_holder()];
vec![ vec![
@ -1925,17 +1939,16 @@ pub mod choice {
C: Fn(&()) -> Message + 'static + Send + Sync, C: Fn(&()) -> Message + 'static + Send + Sync,
{ {
let items = E::list() let items = E::list()
.into_iter() .iter()
.map(|group| { .map(|group| {
group group
.into_iter() .iter()
.map(|(item, metadata)| { .map(|(item, metadata)| {
let item = item.clone();
let updater = updater_factory(); let updater = updater_factory();
let committer = committer_factory(); let committer = committer_factory();
MenuListEntry::new(metadata.name.as_ref()) MenuListEntry::new(metadata.name.as_ref())
.label(metadata.label.as_ref()) .label(metadata.label.as_ref())
.on_update(move |_| updater(&item)) .on_update(move |_| updater(item))
.on_commit(committer) .on_commit(committer)
}) })
.collect() .collect()
@ -1950,14 +1963,12 @@ pub mod choice {
C: Fn(&()) -> Message + 'static + Send + Sync, C: Fn(&()) -> Message + 'static + Send + Sync,
{ {
let items = E::list() let items = E::list()
.into_iter() .iter()
.map(|group| group.into_iter()) .flat_map(|group| group.iter())
.flatten()
.map(|(item, var_meta)| { .map(|(item, var_meta)| {
let item = item.clone();
let updater = updater_factory(); let updater = updater_factory();
let committer = committer_factory(); let committer = committer_factory();
let entry = RadioEntryData::new(var_meta.name.as_ref()).on_update(move |_| updater(&item)).on_commit(committer); let entry = RadioEntryData::new(var_meta.name.as_ref()).on_update(move |_| updater(item)).on_commit(committer);
match (var_meta.icon.as_deref(), var_meta.docstring.as_deref()) { match (var_meta.icon.as_deref(), var_meta.docstring.as_deref()) {
(None, None) => entry.label(var_meta.label.as_ref()), (None, None) => entry.label(var_meta.label.as_ref()),
(None, Some(doc)) => entry.label(var_meta.label.as_ref()).tooltip(doc), (None, Some(doc)) => entry.label(var_meta.label.as_ref()).tooltip(doc),
@ -2027,7 +2038,7 @@ pub mod choice {
return LayoutGroup::Row { widgets: vec![] }; return LayoutGroup::Row { widgets: vec![] };
}; };
let input: Option<W::Value> = input.as_non_exposed_value().and_then(|v| <&W::Value as TryFrom<&TaggedValue>>::try_from(v).ok()).map(Clone::clone); let input: Option<W::Value> = input.as_non_exposed_value().and_then(|v| <&W::Value as TryFrom<&TaggedValue>>::try_from(v).ok()).cloned();
if let Some(current) = input { if let Some(current) = input {
let committer = || super::commit_value; let committer = || super::commit_value;

View file

@ -1021,6 +1021,7 @@ async fn channel_mixer<T: Adjust<Color>>(
mut image: T, mut image: T,
monochrome: bool, monochrome: bool,
#[default(40.)] #[default(40.)]
#[name("Red")] #[name("Red")]
monochrome_r: f64, monochrome_r: f64,
@ -1144,43 +1145,54 @@ async fn selective_color<T: Adjust<Color>>(
GradientStops, GradientStops,
)] )]
mut image: T, mut image: T,
mode: RelativeAbsolute, mode: RelativeAbsolute,
#[name("(Reds) Cyan")] r_c: f64, #[name("(Reds) Cyan")] r_c: f64,
#[name("(Reds) Magenta")] r_m: f64, #[name("(Reds) Magenta")] r_m: f64,
#[name("(Reds) Yellow")] r_y: f64, #[name("(Reds) Yellow")] r_y: f64,
#[name("(Reds) Black")] r_k: f64, #[name("(Reds) Black")] r_k: f64,
#[name("(Yellows) Cyan")] y_c: f64, #[name("(Yellows) Cyan")] y_c: f64,
#[name("(Yellows) Magenta")] y_m: f64, #[name("(Yellows) Magenta")] y_m: f64,
#[name("(Yellows) Yellow")] y_y: f64, #[name("(Yellows) Yellow")] y_y: f64,
#[name("(Yellows) Black")] y_k: f64, #[name("(Yellows) Black")] y_k: f64,
#[name("(Greens) Cyan")] g_c: f64, #[name("(Greens) Cyan")] g_c: f64,
#[name("(Greens) Magenta")] g_m: f64, #[name("(Greens) Magenta")] g_m: f64,
#[name("(Greens) Yellow")] g_y: f64, #[name("(Greens) Yellow")] g_y: f64,
#[name("(Greens) Black")] g_k: f64, #[name("(Greens) Black")] g_k: f64,
#[name("(Cyans) Cyan")] c_c: f64, #[name("(Cyans) Cyan")] c_c: f64,
#[name("(Cyans) Magenta")] c_m: f64, #[name("(Cyans) Magenta")] c_m: f64,
#[name("(Cyans) Yellow")] c_y: f64, #[name("(Cyans) Yellow")] c_y: f64,
#[name("(Cyans) Black")] c_k: f64, #[name("(Cyans) Black")] c_k: f64,
#[name("(Blues) Cyan")] b_c: f64, #[name("(Blues) Cyan")] b_c: f64,
#[name("(Blues) Magenta")] b_m: f64, #[name("(Blues) Magenta")] b_m: f64,
#[name("(Blues) Yellow")] b_y: f64, #[name("(Blues) Yellow")] b_y: f64,
#[name("(Blues) Black")] b_k: f64, #[name("(Blues) Black")] b_k: f64,
#[name("(Magentas) Cyan")] m_c: f64, #[name("(Magentas) Cyan")] m_c: f64,
#[name("(Magentas) Magenta")] m_m: f64, #[name("(Magentas) Magenta")] m_m: f64,
#[name("(Magentas) Yellow")] m_y: f64, #[name("(Magentas) Yellow")] m_y: f64,
#[name("(Magentas) Black")] m_k: f64, #[name("(Magentas) Black")] m_k: f64,
#[name("(Whites) Cyan")] w_c: f64, #[name("(Whites) Cyan")] w_c: f64,
#[name("(Whites) Magenta")] w_m: f64, #[name("(Whites) Magenta")] w_m: f64,
#[name("(Whites) Yellow")] w_y: f64, #[name("(Whites) Yellow")] w_y: f64,
#[name("(Whites) Black")] w_k: f64, #[name("(Whites) Black")] w_k: f64,
#[name("(Neutrals) Cyan")] n_c: f64, #[name("(Neutrals) Cyan")] n_c: f64,
#[name("(Neutrals) Magenta")] n_m: f64, #[name("(Neutrals) Magenta")] n_m: f64,
#[name("(Neutrals) Yellow")] n_y: f64, #[name("(Neutrals) Yellow")] n_y: f64,
#[name("(Neutrals) Black")] n_k: f64, #[name("(Neutrals) Black")] n_k: f64,
#[name("(Blacks) Cyan")] k_c: f64, #[name("(Blacks) Cyan")] k_c: f64,
#[name("(Blacks) Magenta")] k_m: f64, #[name("(Blacks) Magenta")] k_m: f64,
#[name("(Blacks) Yellow")] k_y: f64, #[name("(Blacks) Yellow")] k_y: f64,
#[name("(Blacks) Black")] k_k: f64, #[name("(Blacks) Black")] k_k: f64,
_colors: SelectiveColorChoice, _colors: SelectiveColorChoice,
) -> T { ) -> T {
image.adjust(|color| { image.adjust(|color| {