Add a "Use Tint" toggle to the 'Black & White' node and give its tint the Luminosity blend's clipping (#4540)

* Add a 'Use Tint' toggle to the 'Black & White' node and give its tint the Luminosity blend's clipping

* Fix the Black & White migration for a wired tint and gray out the tint when unused
This commit is contained in:
Keavon Chambers
2026-09-15 19:51:51 -07:00
committed by GitHub
parent 04a401c1b8
commit 358eb317d2
4 changed files with 129 additions and 22 deletions

View File

@@ -1075,6 +1075,40 @@ pub fn optional_f64_widget(parameter_widgets_info: ParameterWidgetsInfo, bool_in
widgets
}
/// `parameter_widgets_info` is for the color parameter. `bool_input_index` is the input index of the bool parameter, drawn as a checkbox in front of the color.
/// A color row gated by the bool input at `bool_input_index`, whose checkbox takes the assist slot after the label like the
/// Opacity node's toggles, so the caller passes `blank_assist = false`. An exposed color shows neither, as in that node.
pub fn optional_color_widget(parameter_widgets_info: ParameterWidgetsInfo, bool_input_index: usize, color_button: ColorInput) -> LayoutGroup {
let node_id = parameter_widgets_info.node_id;
let enabled = parameter_widgets_info
.document_node
.and_then(|document_node| document_node.inputs.get(bool_input_index))
.and_then(|input| input.as_non_exposed_value())
.and_then(|value| if let TaggedValue::Bool(enabled) = value { Some(*enabled) } else { None });
let label_count = start_widgets(&parameter_widgets_info).len();
let exposed = parameter_widgets_info.is_exposed();
let LayoutGroup::Row(mut row) = color_widget(parameter_widgets_info, color_button.disabled(enabled == Some(false))) else {
return LayoutGroup::row(Vec::new());
};
if let Some(enabled) = enabled
&& !exposed
{
let checkbox = [
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
Separator::new(SeparatorStyle::Related).widget_instance(),
CheckboxInput::new(enabled)
.on_update(update_value_at_index(|x: &CheckboxInput| TaggedValue::Bool(x.checked), node_id, bool_input_index))
.on_commit(commit_value)
.widget_instance(),
Separator::new(SeparatorStyle::Related).widget_instance(),
];
row.widgets.splice(label_count..label_count, checkbox);
}
LayoutGroup::Row(row)
}
pub fn number_widget(parameter_widgets_info: ParameterWidgetsInfo, number_props: NumberInput) -> Vec<WidgetInstance> {
let mut widgets = start_widgets(&parameter_widgets_info);
@@ -2157,7 +2191,8 @@ pub(crate) fn black_and_white_properties(node_id: NodeId, context: &mut NodeProp
let number_input = NumberInput::default().mode_increment().unit("%").min(-200.).max(300.);
let tint = color_widget(ParameterWidgetsInfo::new(node_id, TintInput, true, context), ColorInput::default());
let use_tint: ParameterRef = UseTintInput.into();
let tint = optional_color_widget(ParameterWidgetsInfo::new(node_id, TintInput, false, context), use_tint.input_index, ColorInput::default());
let mut layout = vec![tint];
let params: &[(ParameterRef, Color, f64)] = &[

View File

@@ -2266,6 +2266,22 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
inputs_count = 51;
}
// Black & White gained a Use Tint toggle ahead of its tint color; a non-black tint used to be the only way to tint
if reference == DefinitionIdentifier::ProtoNode(graphene_std::raster::black_and_white::IDENTIFIER) && inputs_count == 8 {
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
document.network_interface.set_input(&InputConnector::node_at_index(*node_id, 0), old_inputs[0].clone(), network_path);
for (index, input) in old_inputs.iter().enumerate().skip(1).take(7) {
document.network_interface.set_input(&InputConnector::node_at_index(*node_id, index + 1), input.clone(), network_path);
}
let use_tint = !matches!(old_inputs[1].as_value(), Some(TaggedValue::Color(color)) if *color == Color::BLACK);
document
.network_interface
.set_input(&InputConnector::node_at_index(*node_id, 1), NodeInput::value(TaggedValue::Bool(use_tint), false), network_path);
inputs_count = 9;
}
if reference == DefinitionIdentifier::ProtoNode(graphene_std::repeat::repeat_on_points::IDENTIFIER) && inputs_count == 2 {
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);