From 0cc7a09227d1854f1d8c52f31fd0d874daf903e9 Mon Sep 17 00:00:00 2001 From: Timon Date: Sat, 29 Aug 2026 15:22:11 +0000 Subject: [PATCH] Add an Autoscale option to the Brush tool --- .../messages/tool/tool_messages/brush_tool.rs | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/brush_tool.rs b/editor/src/messages/tool/tool_messages/brush_tool.rs index dd32c50fb9..b454968a4b 100644 --- a/editor/src/messages/tool/tool_messages/brush_tool.rs +++ b/editor/src/messages/tool/tool_messages/brush_tool.rs @@ -6,6 +6,7 @@ use crate::messages::portfolio::document::node_graph::document_node_definitions: use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, InputConnector, OutputConnector}; use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, selection_changed_since_last_sync, solid}; +use crate::messages::tool::common_functionality::resize::viewport_zoom; use graph_craft::document::value::TaggedValue; use graph_craft::document::{NodeId, NodeInput}; use graphene_std::Color; @@ -29,6 +30,7 @@ pub struct BrushOptions { hardness: f64, flow: f64, color: ToolColorOptions, + autoscale: bool, last_synced_selection: Vec, } @@ -39,6 +41,7 @@ impl Default for BrushOptions { hardness: BRUSH_HARDNESS_DEFAULT, flow: BRUSH_FLOW_DEFAULT, color: ToolColorOptions::default(), + autoscale: false, last_synced_selection: Vec::new(), } } @@ -48,6 +51,10 @@ impl BrushOptions { fn active_color(&self) -> Color { self.color.active_color().unwrap_or_default() } + + fn stroke_diameter(&self, document: &DocumentMessageHandler) -> f64 { + if self.autoscale { self.diameter / viewport_zoom(document) } else { self.diameter } + } } #[impl_message(Message, ToolMessage, Brush)] @@ -74,6 +81,7 @@ pub enum BrushToolMessageOptionsUpdate { Diameter(f64), Hardness(f64), Flow(f64), + Autoscale(bool), WorkingColorsChanged, } @@ -98,6 +106,8 @@ impl ToolMetadata for BrushTool { impl LayoutHolder for BrushTool { fn layout(&self) -> Layout { + let autoscale_id = CheckboxId::new(); + let autoscale_description = "Automatically scale the brush with viewport zoom."; let widgets = vec![ ColorInput::new(FillChoice::::from(self.options.color.fill_choice.as_ref().unwrap_or(&FillChoice::None))) .mixed(self.options.color.fill_choice.is_none()) @@ -149,6 +159,24 @@ impl LayoutHolder for BrushTool { .into() }) .widget_instance(), + Separator::new(SeparatorStyle::Unrelated).widget_instance(), + CheckboxInput::new(self.options.autoscale) + .tooltip_label("Autoscale") + .tooltip_description(autoscale_description) + .for_label(autoscale_id) + .on_update(|checkbox_input: &CheckboxInput| { + BrushToolMessage::UpdateOptions { + options: BrushToolMessageOptionsUpdate::Autoscale(checkbox_input.checked), + } + .into() + }) + .widget_instance(), + Separator::new(SeparatorStyle::Related).widget_instance(), + TextLabel::new("Autoscale") + .tooltip_label("Autoscale") + .tooltip_description(autoscale_description) + .for_checkbox(autoscale_id) + .widget_instance(), ]; Layout(vec![LayoutGroup::row(widgets)]) @@ -190,6 +218,7 @@ impl<'a> MessageHandler> for Brus responses.add(ToolMessage::SelectWorkingColor { color, primary: true }); } } + BrushToolMessageOptionsUpdate::Autoscale(autoscale) => self.options.autoscale = autoscale, BrushToolMessageOptionsUpdate::WorkingColorsChanged => { self.options.color.fill_choice = Some(solid(context.global_tool_data.primary_color)); } @@ -234,7 +263,7 @@ impl BrushTool { }; let value = |index: usize| node.inputs.get(index).and_then(|input| input.as_value()); if let Some(TaggedValue::F64(diameter)) = value(STROKES_DIAMETER_INPUT) { - self.options.diameter = *diameter; + self.options.diameter = if self.options.autoscale { *diameter * viewport_zoom(document) } else { *diameter }; } if let Some(TaggedValue::F64(hardness)) = value(STROKES_HARDNESS_INPUT) { self.options.hardness = *hardness; @@ -355,7 +384,7 @@ impl BrushToolData { }; let value = |index: usize| node.inputs.get(index).and_then(|input| input.as_value()); matches!(value(STROKES_COLOR_INPUT), Some(TaggedValue::Color(color)) if *color == options.active_color()) - && matches!(value(STROKES_DIAMETER_INPUT), Some(TaggedValue::F64(diameter)) if *diameter == options.diameter) + && matches!(value(STROKES_DIAMETER_INPUT), Some(TaggedValue::F64(diameter)) if *diameter == options.stroke_diameter(document)) && matches!(value(STROKES_HARDNESS_INPUT), Some(TaggedValue::F64(hardness)) if *hardness == options.hardness) && matches!(value(STROKES_FLOW_INPUT), Some(TaggedValue::F64(flow)) if *flow == options.flow) } @@ -447,7 +476,7 @@ impl Fsm for BrushToolFsmState { parent, insert_index, color: tool_options.active_color(), - diameter: tool_options.diameter, + diameter: tool_options.stroke_diameter(document), hardness: tool_options.hardness, flow: tool_options.flow, }); @@ -461,7 +490,7 @@ impl Fsm for BrushToolFsmState { layer, strokes_node_id, color: tool_options.active_color(), - diameter: tool_options.diameter, + diameter: tool_options.stroke_diameter(document), hardness: tool_options.hardness, flow: tool_options.flow, });