feat: add cyclic color and speed options for brush settings
This commit is contained in:
@@ -587,6 +587,10 @@ pub struct ToolState {
|
|||||||
pub brush_color_variant: bool,
|
pub brush_color_variant: bool,
|
||||||
/// Magnitude of the per-dab color variation (0.0..1.0).
|
/// Magnitude of the per-dab color variation (0.0..1.0).
|
||||||
pub brush_variant_amount: f32,
|
pub brush_variant_amount: f32,
|
||||||
|
/// True when the brush color should cycle through the hue over stroke distance.
|
||||||
|
pub brush_cyclic_color: bool,
|
||||||
|
/// Speed of the hue cycle along the stroke (0.01..5.0).
|
||||||
|
pub brush_cyclic_speed: f32,
|
||||||
/// Timestamp of the last update() call for frame timing.
|
/// Timestamp of the last update() call for frame timing.
|
||||||
pub last_update_instant: std::time::Instant,
|
pub last_update_instant: std::time::Instant,
|
||||||
/// Imported brush presets from ABR/KPP files.
|
/// Imported brush presets from ABR/KPP files.
|
||||||
@@ -621,6 +625,8 @@ impl Default for ToolState {
|
|||||||
brush_spacing: 1.0,
|
brush_spacing: 1.0,
|
||||||
brush_color_variant: false,
|
brush_color_variant: false,
|
||||||
brush_variant_amount: 0.0,
|
brush_variant_amount: 0.0,
|
||||||
|
brush_cyclic_color: false,
|
||||||
|
brush_cyclic_speed: 0.5,
|
||||||
last_update_instant: std::time::Instant::now(),
|
last_update_instant: std::time::Instant::now(),
|
||||||
imported_brushes: Vec::new(),
|
imported_brushes: Vec::new(),
|
||||||
active_brush_preset: None,
|
active_brush_preset: None,
|
||||||
@@ -778,6 +784,8 @@ pub enum Message {
|
|||||||
BrushSpacingChanged(f32),
|
BrushSpacingChanged(f32),
|
||||||
BrushColorVariantToggled(bool),
|
BrushColorVariantToggled(bool),
|
||||||
BrushVariantAmountChanged(f32),
|
BrushVariantAmountChanged(f32),
|
||||||
|
BrushCyclicColorToggled(bool),
|
||||||
|
BrushCyclicSpeedChanged(f32),
|
||||||
BrushImportAbr,
|
BrushImportAbr,
|
||||||
BrushImportAbrFile(Result<Vec<hcie_engine_api::BrushPreset>, String>),
|
BrushImportAbrFile(Result<Vec<hcie_engine_api::BrushPreset>, String>),
|
||||||
ResetToolDefaults,
|
ResetToolDefaults,
|
||||||
@@ -1319,6 +1327,7 @@ fn build_brush_tip(state: &ToolState) -> BrushTip {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Converts an imported/default brush-engine preset tip into the protocol tip used by `Engine`.
|
/// Converts an imported/default brush-engine preset tip into the protocol tip used by `Engine`.
|
||||||
///
|
///
|
||||||
/// **Arguments:** `source` is the preset-owned brush-engine tip. **Returns:** A protocol tip with
|
/// **Arguments:** `source` is the preset-owned brush-engine tip. **Returns:** A protocol tip with
|
||||||
@@ -2564,7 +2573,7 @@ impl HcieIcedApp {
|
|||||||
/// Apply brush parameters from tool state to the engine.
|
/// Apply brush parameters from tool state to the engine.
|
||||||
///
|
///
|
||||||
/// Called before starting a stroke to ensure the engine uses
|
/// Called before starting a stroke to ensure the engine uses
|
||||||
/// the current brush size, opacity, hardness, and style.
|
/// the current brush size, opacity, hardness, style, and cyclic color.
|
||||||
fn apply_brush_params(&mut self) {
|
fn apply_brush_params(&mut self) {
|
||||||
let mut tip = self
|
let mut tip = self
|
||||||
.tool_state
|
.tool_state
|
||||||
@@ -2577,6 +2586,15 @@ impl HcieIcedApp {
|
|||||||
tip.opacity = self.tool_state.brush_opacity;
|
tip.opacity = self.tool_state.brush_opacity;
|
||||||
tip.hardness = self.tool_state.brush_hardness;
|
tip.hardness = self.tool_state.brush_hardness;
|
||||||
tip.spacing = self.tool_state.brush_spacing;
|
tip.spacing = self.tool_state.brush_spacing;
|
||||||
|
// Cyclic color is handled by engine state, not the tip, but preview rendering
|
||||||
|
// also reads the tip's time dynamics. Synchronize both here.
|
||||||
|
tip.time_enabled = self.tool_state.brush_cyclic_color;
|
||||||
|
tip.time_size_start = 1.0;
|
||||||
|
tip.time_size_end = 1.0;
|
||||||
|
tip.time_opacity_start = 1.0;
|
||||||
|
tip.time_opacity_end = 1.0;
|
||||||
|
tip.time_angle_start = 0.0;
|
||||||
|
tip.time_angle_end = 0.0;
|
||||||
match self.tool_state.active_tool {
|
match self.tool_state.active_tool {
|
||||||
Tool::Pen => {
|
Tool::Pen => {
|
||||||
tip.style = BrushStyle::Round;
|
tip.style = BrushStyle::Round;
|
||||||
@@ -2592,7 +2610,10 @@ impl HcieIcedApp {
|
|||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
self.documents[self.active_doc].engine.set_brush_tip(tip);
|
let engine = &mut self.documents[self.active_doc].engine;
|
||||||
|
engine.set_brush_tip(tip);
|
||||||
|
engine.set_cyclic_color(self.tool_state.brush_cyclic_color);
|
||||||
|
engine.set_cyclic_speed(self.tool_state.brush_cyclic_speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push the current SVG editor model into the active vector shape so the
|
/// Push the current SVG editor model into the active vector shape so the
|
||||||
@@ -4955,6 +4976,22 @@ impl HcieIcedApp {
|
|||||||
self.settings.update_from_tool_state(&self.tool_state);
|
self.settings.update_from_tool_state(&self.tool_state);
|
||||||
let _ = self.settings.save();
|
let _ = self.settings.save();
|
||||||
}
|
}
|
||||||
|
Message::BrushCyclicColorToggled(enabled) => {
|
||||||
|
self.tool_state.brush_cyclic_color = enabled;
|
||||||
|
self.documents[self.active_doc]
|
||||||
|
.engine
|
||||||
|
.set_cyclic_color(enabled);
|
||||||
|
self.settings.update_from_tool_state(&self.tool_state);
|
||||||
|
let _ = self.settings.save();
|
||||||
|
}
|
||||||
|
Message::BrushCyclicSpeedChanged(speed) => {
|
||||||
|
self.tool_state.brush_cyclic_speed = speed;
|
||||||
|
self.documents[self.active_doc]
|
||||||
|
.engine
|
||||||
|
.set_cyclic_speed(speed);
|
||||||
|
self.settings.update_from_tool_state(&self.tool_state);
|
||||||
|
let _ = self.settings.save();
|
||||||
|
}
|
||||||
Message::SelectionToleranceChanged(tol) => {
|
Message::SelectionToleranceChanged(tol) => {
|
||||||
self.settings.tool_settings.magic_wand_tolerance = tol as f32;
|
self.settings.tool_settings.magic_wand_tolerance = tol as f32;
|
||||||
self.settings.tool_settings.flood_fill_tolerance = tol as f32;
|
self.settings.tool_settings.flood_fill_tolerance = tol as f32;
|
||||||
|
|||||||
@@ -184,6 +184,8 @@ pub fn panel_body<'a>(
|
|||||||
app.tool_state.brush_hardness,
|
app.tool_state.brush_hardness,
|
||||||
app.tool_state.brush_color_variant,
|
app.tool_state.brush_color_variant,
|
||||||
app.tool_state.brush_variant_amount,
|
app.tool_state.brush_variant_amount,
|
||||||
|
app.tool_state.brush_cyclic_color,
|
||||||
|
app.tool_state.brush_cyclic_speed,
|
||||||
app.brush_category,
|
app.brush_category,
|
||||||
&app.tool_state.imported_brushes,
|
&app.tool_state.imported_brushes,
|
||||||
app.tool_state.active_brush_preset.as_ref(),
|
app.tool_state.active_brush_preset.as_ref(),
|
||||||
@@ -236,6 +238,10 @@ pub fn panel_body<'a>(
|
|||||||
app.tool_state.brush_size,
|
app.tool_state.brush_size,
|
||||||
app.tool_state.brush_opacity,
|
app.tool_state.brush_opacity,
|
||||||
app.tool_state.brush_hardness,
|
app.tool_state.brush_hardness,
|
||||||
|
app.tool_state.brush_color_variant,
|
||||||
|
app.tool_state.brush_variant_amount,
|
||||||
|
app.tool_state.brush_cyclic_color,
|
||||||
|
app.tool_state.brush_cyclic_speed,
|
||||||
doc.selection_rect,
|
doc.selection_rect,
|
||||||
doc.vector_draw,
|
doc.vector_draw,
|
||||||
colors,
|
colors,
|
||||||
|
|||||||
@@ -290,6 +290,7 @@ struct PreviewKey {
|
|||||||
size: u8,
|
size: u8,
|
||||||
hardness: u8,
|
hardness: u8,
|
||||||
opacity: u8,
|
opacity: u8,
|
||||||
|
cyclic: bool,
|
||||||
r: u8,
|
r: u8,
|
||||||
g: u8,
|
g: u8,
|
||||||
b: u8,
|
b: u8,
|
||||||
@@ -508,12 +509,20 @@ fn build_tip_from_state(
|
|||||||
size: f32,
|
size: f32,
|
||||||
opacity: f32,
|
opacity: f32,
|
||||||
hardness: f32,
|
hardness: f32,
|
||||||
|
cyclic_color: bool,
|
||||||
) -> hcie_engine_api::BrushTip {
|
) -> hcie_engine_api::BrushTip {
|
||||||
hcie_engine_api::BrushTip {
|
hcie_engine_api::BrushTip {
|
||||||
style,
|
style,
|
||||||
size,
|
size,
|
||||||
opacity,
|
opacity,
|
||||||
hardness,
|
hardness,
|
||||||
|
time_enabled: cyclic_color,
|
||||||
|
time_size_start: 1.0,
|
||||||
|
time_size_end: 1.0,
|
||||||
|
time_opacity_start: 1.0,
|
||||||
|
time_opacity_end: 1.0,
|
||||||
|
time_angle_start: 0.0,
|
||||||
|
time_angle_end: 0.0,
|
||||||
..hcie_engine_api::BrushTip::default()
|
..hcie_engine_api::BrushTip::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -527,6 +536,7 @@ fn preview_key(
|
|||||||
size: f32,
|
size: f32,
|
||||||
opacity: f32,
|
opacity: f32,
|
||||||
hardness: f32,
|
hardness: f32,
|
||||||
|
cyclic: bool,
|
||||||
fg_color: [u8; 4],
|
fg_color: [u8; 4],
|
||||||
) -> PreviewKey {
|
) -> PreviewKey {
|
||||||
PreviewKey {
|
PreviewKey {
|
||||||
@@ -534,6 +544,7 @@ fn preview_key(
|
|||||||
size: size.clamp(1.0, 255.0) as u8,
|
size: size.clamp(1.0, 255.0) as u8,
|
||||||
hardness: (hardness * 100.0).clamp(0.0, 100.0) as u8,
|
hardness: (hardness * 100.0).clamp(0.0, 100.0) as u8,
|
||||||
opacity: (opacity * 100.0).clamp(0.0, 100.0) as u8,
|
opacity: (opacity * 100.0).clamp(0.0, 100.0) as u8,
|
||||||
|
cyclic,
|
||||||
r: fg_color[0],
|
r: fg_color[0],
|
||||||
g: fg_color[1],
|
g: fg_color[1],
|
||||||
b: fg_color[2],
|
b: fg_color[2],
|
||||||
@@ -562,13 +573,14 @@ fn get_live_stroke_preview(
|
|||||||
size: f32,
|
size: f32,
|
||||||
opacity: f32,
|
opacity: f32,
|
||||||
hardness: f32,
|
hardness: f32,
|
||||||
|
cyclic_color: bool,
|
||||||
fg_color: [u8; 4],
|
fg_color: [u8; 4],
|
||||||
) -> iced::widget::image::Handle {
|
) -> iced::widget::image::Handle {
|
||||||
// Clamp the rendered brush size so a 110 px soft brush does not fill the
|
// Clamp the rendered brush size so a 110 px soft brush does not fill the
|
||||||
// entire 40 px preview well with a solid blob. The preview shows texture and
|
// entire 40 px preview well with a solid blob. The preview shows texture and
|
||||||
// stroke character; the slider still reports the real painting size.
|
// stroke character; the slider still reports the real painting size.
|
||||||
let preview_size = size.clamp(4.0, LIVE_PREVIEW_BRUSH_SIZE);
|
let preview_size = size.clamp(4.0, LIVE_PREVIEW_BRUSH_SIZE);
|
||||||
let key = preview_key(style, preview_size, opacity, hardness, fg_color);
|
let key = preview_key(style, preview_size, opacity, hardness, cyclic_color, fg_color);
|
||||||
let cache = LIVE_PREVIEW_CACHE.get_or_init(|| Mutex::new(HashMap::new()));
|
let cache = LIVE_PREVIEW_CACHE.get_or_init(|| Mutex::new(HashMap::new()));
|
||||||
let mut cache = cache
|
let mut cache = cache
|
||||||
.lock()
|
.lock()
|
||||||
@@ -576,7 +588,7 @@ fn get_live_stroke_preview(
|
|||||||
if let Some(handle) = cache.get(&key) {
|
if let Some(handle) = cache.get(&key) {
|
||||||
return handle.clone();
|
return handle.clone();
|
||||||
}
|
}
|
||||||
let tip = build_tip_from_state(style, preview_size, opacity, hardness);
|
let tip = build_tip_from_state(style, preview_size, opacity, hardness, cyclic_color);
|
||||||
let pixels =
|
let pixels =
|
||||||
render_stroke_preview(LIVE_PREVIEW_IMG_SIZE, LIVE_PREVIEW_IMG_SIZE, &tip, fg_color);
|
render_stroke_preview(LIVE_PREVIEW_IMG_SIZE, LIVE_PREVIEW_IMG_SIZE, &tip, fg_color);
|
||||||
let handle = iced::widget::image::Handle::from_rgba(
|
let handle = iced::widget::image::Handle::from_rgba(
|
||||||
@@ -588,6 +600,11 @@ fn get_live_stroke_preview(
|
|||||||
handle
|
handle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clamp a cyclic speed value to the engine's valid range.
|
||||||
|
fn clamp_cyclic_speed(speed: f32) -> f32 {
|
||||||
|
speed.clamp(0.01, 5.0)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get or generate a realistic stroke preview for a built-in brush style.
|
/// Get or generate a realistic stroke preview for a built-in brush style.
|
||||||
///
|
///
|
||||||
/// **Purpose:** Provides the thumbnails shown in the built-in style grid. The
|
/// **Purpose:** Provides the thumbnails shown in the built-in style grid. The
|
||||||
@@ -637,6 +654,8 @@ pub fn view(
|
|||||||
current_hardness: f32,
|
current_hardness: f32,
|
||||||
brush_color_variant: bool,
|
brush_color_variant: bool,
|
||||||
brush_variant_amount: f32,
|
brush_variant_amount: f32,
|
||||||
|
brush_cyclic_color: bool,
|
||||||
|
brush_cyclic_speed: f32,
|
||||||
active_category: BrushCategory,
|
active_category: BrushCategory,
|
||||||
imported_presets: &[hcie_engine_api::BrushPreset],
|
imported_presets: &[hcie_engine_api::BrushPreset],
|
||||||
active_brush_preset: Option<&hcie_engine_api::BrushPreset>,
|
active_brush_preset: Option<&hcie_engine_api::BrushPreset>,
|
||||||
@@ -1021,6 +1040,16 @@ pub fn view(
|
|||||||
colors,
|
colors,
|
||||||
Message::BrushVariantAmountChanged,
|
Message::BrushVariantAmountChanged,
|
||||||
);
|
);
|
||||||
|
let cyclic_speed_slider = plain_slider(
|
||||||
|
"Cyclic Speed",
|
||||||
|
clamp_cyclic_speed(brush_cyclic_speed),
|
||||||
|
0.01..=5.0,
|
||||||
|
0.01,
|
||||||
|
"x",
|
||||||
|
2,
|
||||||
|
colors,
|
||||||
|
Message::BrushCyclicSpeedChanged,
|
||||||
|
);
|
||||||
|
|
||||||
// Compact color-variant toggle: an empty 12 px checkbox plus an 8 px label so
|
// Compact color-variant toggle: an empty 12 px checkbox plus an 8 px label so
|
||||||
// the control matches the rest of the compact panel typography.
|
// the control matches the rest of the compact panel typography.
|
||||||
@@ -1033,6 +1062,15 @@ pub fn view(
|
|||||||
.spacing(4)
|
.spacing(4)
|
||||||
.align_y(iced::Alignment::Center);
|
.align_y(iced::Alignment::Center);
|
||||||
|
|
||||||
|
let cyclic_color_check = row![
|
||||||
|
checkbox("", brush_cyclic_color)
|
||||||
|
.on_toggle(Message::BrushCyclicColorToggled)
|
||||||
|
.size(12),
|
||||||
|
text("Cyclic color").size(LABEL_SIZE),
|
||||||
|
]
|
||||||
|
.spacing(4)
|
||||||
|
.align_y(iced::Alignment::Center);
|
||||||
|
|
||||||
// Live preview — show a realistic engine-rendered stroke using the active
|
// Live preview — show a realistic engine-rendered stroke using the active
|
||||||
// size, opacity, hardness, and foreground color. The preview is
|
// size, opacity, hardness, and foreground color. The preview is
|
||||||
// parameter-keyed and cached so it updates in real time without
|
// parameter-keyed and cached so it updates in real time without
|
||||||
@@ -1042,6 +1080,7 @@ pub fn view(
|
|||||||
current_size,
|
current_size,
|
||||||
current_opacity,
|
current_opacity,
|
||||||
current_hardness,
|
current_hardness,
|
||||||
|
brush_cyclic_color,
|
||||||
fg_color,
|
fg_color,
|
||||||
);
|
);
|
||||||
let live_preview = container(
|
let live_preview = container(
|
||||||
@@ -1091,6 +1130,8 @@ pub fn view(
|
|||||||
hardness_slider,
|
hardness_slider,
|
||||||
color_variant_check,
|
color_variant_check,
|
||||||
variant_slider,
|
variant_slider,
|
||||||
|
cyclic_color_check,
|
||||||
|
cyclic_speed_slider,
|
||||||
]
|
]
|
||||||
.spacing(ITEM_SPACING)
|
.spacing(ITEM_SPACING)
|
||||||
.padding(3);
|
.padding(3);
|
||||||
|
|||||||
@@ -93,6 +93,10 @@ pub fn view<'a>(
|
|||||||
brush_size: f32,
|
brush_size: f32,
|
||||||
brush_opacity: f32,
|
brush_opacity: f32,
|
||||||
brush_hardness: f32,
|
brush_hardness: f32,
|
||||||
|
brush_color_variant: bool,
|
||||||
|
brush_variant_amount: f32,
|
||||||
|
brush_cyclic_color: bool,
|
||||||
|
brush_cyclic_speed: f32,
|
||||||
selection_rect: Option<(f32, f32, f32, f32)>,
|
selection_rect: Option<(f32, f32, f32, f32)>,
|
||||||
vector_draw: Option<((f32, f32), (f32, f32))>,
|
vector_draw: Option<((f32, f32), (f32, f32))>,
|
||||||
colors: ThemeColors,
|
colors: ThemeColors,
|
||||||
@@ -134,12 +138,25 @@ pub fn view<'a>(
|
|||||||
// Build tool/shape-specific section
|
// Build tool/shape-specific section
|
||||||
let tool_section: Element<'a, Message> = match active_tool {
|
let tool_section: Element<'a, Message> = match active_tool {
|
||||||
Tool::Pen | Tool::Brush | Tool::Eraser => {
|
Tool::Pen | Tool::Brush | Tool::Eraser => {
|
||||||
brush_properties(brush_size, brush_opacity, brush_hardness, colors)
|
brush_properties(
|
||||||
|
brush_size,
|
||||||
|
brush_opacity,
|
||||||
|
brush_hardness,
|
||||||
|
brush_color_variant,
|
||||||
|
brush_variant_amount,
|
||||||
|
brush_cyclic_color,
|
||||||
|
brush_cyclic_speed,
|
||||||
|
colors,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Tool::Spray => spray_properties(
|
Tool::Spray => spray_properties(
|
||||||
brush_size,
|
brush_size,
|
||||||
brush_opacity,
|
brush_opacity,
|
||||||
brush_hardness,
|
brush_hardness,
|
||||||
|
brush_color_variant,
|
||||||
|
brush_variant_amount,
|
||||||
|
brush_cyclic_color,
|
||||||
|
brush_cyclic_speed,
|
||||||
settings_spray_particle_size,
|
settings_spray_particle_size,
|
||||||
settings_spray_density,
|
settings_spray_density,
|
||||||
colors,
|
colors,
|
||||||
@@ -511,11 +528,20 @@ fn vector_tool_properties<'a>(
|
|||||||
col.into()
|
col.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shared cyclic speed clamp used by brush and spray property sections.
|
||||||
|
fn clamp_cyclic_speed(speed: f32) -> f32 {
|
||||||
|
speed.clamp(0.01, 5.0)
|
||||||
|
}
|
||||||
|
|
||||||
/// Brush tool properties (Pen, Brush, Eraser).
|
/// Brush tool properties (Pen, Brush, Eraser).
|
||||||
fn brush_properties<'a>(
|
fn brush_properties<'a>(
|
||||||
size: f32,
|
size: f32,
|
||||||
opacity: f32,
|
opacity: f32,
|
||||||
hardness: f32,
|
hardness: f32,
|
||||||
|
color_variant: bool,
|
||||||
|
variant_amount: f32,
|
||||||
|
cyclic_color: bool,
|
||||||
|
cyclic_speed: f32,
|
||||||
colors: ThemeColors,
|
colors: ThemeColors,
|
||||||
) -> Element<'a, Message> {
|
) -> Element<'a, Message> {
|
||||||
column![
|
column![
|
||||||
@@ -529,6 +555,40 @@ fn brush_properties<'a>(
|
|||||||
plain_slider("Hardness", hardness, 0.0..=1.0, 0.01, "%", 0, colors, |v| {
|
plain_slider("Hardness", hardness, 0.0..=1.0, 0.01, "%", 0, colors, |v| {
|
||||||
Message::BrushHardnessChanged(v)
|
Message::BrushHardnessChanged(v)
|
||||||
},),
|
},),
|
||||||
|
row![
|
||||||
|
checkbox("Color Variant", color_variant)
|
||||||
|
.on_toggle(Message::BrushColorVariantToggled)
|
||||||
|
.size(11),
|
||||||
|
]
|
||||||
|
.spacing(4)
|
||||||
|
.align_y(iced::Alignment::Center),
|
||||||
|
plain_slider(
|
||||||
|
"Variant Amount",
|
||||||
|
variant_amount,
|
||||||
|
0.0..=1.0,
|
||||||
|
0.01,
|
||||||
|
"%",
|
||||||
|
0,
|
||||||
|
colors,
|
||||||
|
Message::BrushVariantAmountChanged,
|
||||||
|
),
|
||||||
|
row![
|
||||||
|
checkbox("Cyclic Color", cyclic_color)
|
||||||
|
.on_toggle(Message::BrushCyclicColorToggled)
|
||||||
|
.size(11),
|
||||||
|
]
|
||||||
|
.spacing(4)
|
||||||
|
.align_y(iced::Alignment::Center),
|
||||||
|
plain_slider(
|
||||||
|
"Cyclic Speed",
|
||||||
|
clamp_cyclic_speed(cyclic_speed),
|
||||||
|
0.01..=5.0,
|
||||||
|
0.01,
|
||||||
|
"x",
|
||||||
|
2,
|
||||||
|
colors,
|
||||||
|
Message::BrushCyclicSpeedChanged,
|
||||||
|
),
|
||||||
]
|
]
|
||||||
.spacing(4)
|
.spacing(4)
|
||||||
.into()
|
.into()
|
||||||
@@ -539,6 +599,10 @@ fn spray_properties<'a>(
|
|||||||
size: f32,
|
size: f32,
|
||||||
opacity: f32,
|
opacity: f32,
|
||||||
hardness: f32,
|
hardness: f32,
|
||||||
|
color_variant: bool,
|
||||||
|
variant_amount: f32,
|
||||||
|
cyclic_color: bool,
|
||||||
|
cyclic_speed: f32,
|
||||||
particle_size: f32,
|
particle_size: f32,
|
||||||
density: u32,
|
density: u32,
|
||||||
colors: ThemeColors,
|
colors: ThemeColors,
|
||||||
@@ -574,6 +638,40 @@ fn spray_properties<'a>(
|
|||||||
plain_slider("Hardness", hardness, 0.0..=1.0, 0.01, "%", 0, colors, |v| {
|
plain_slider("Hardness", hardness, 0.0..=1.0, 0.01, "%", 0, colors, |v| {
|
||||||
Message::BrushHardnessChanged(v)
|
Message::BrushHardnessChanged(v)
|
||||||
},),
|
},),
|
||||||
|
row![
|
||||||
|
checkbox("Color Variant", color_variant)
|
||||||
|
.on_toggle(Message::BrushColorVariantToggled)
|
||||||
|
.size(11),
|
||||||
|
]
|
||||||
|
.spacing(4)
|
||||||
|
.align_y(iced::Alignment::Center),
|
||||||
|
plain_slider(
|
||||||
|
"Variant Amount",
|
||||||
|
variant_amount,
|
||||||
|
0.0..=1.0,
|
||||||
|
0.01,
|
||||||
|
"%",
|
||||||
|
0,
|
||||||
|
colors,
|
||||||
|
Message::BrushVariantAmountChanged,
|
||||||
|
),
|
||||||
|
row![
|
||||||
|
checkbox("Cyclic Color", cyclic_color)
|
||||||
|
.on_toggle(Message::BrushCyclicColorToggled)
|
||||||
|
.size(11),
|
||||||
|
]
|
||||||
|
.spacing(4)
|
||||||
|
.align_y(iced::Alignment::Center),
|
||||||
|
plain_slider(
|
||||||
|
"Cyclic Speed",
|
||||||
|
clamp_cyclic_speed(cyclic_speed),
|
||||||
|
0.01..=5.0,
|
||||||
|
0.01,
|
||||||
|
"x",
|
||||||
|
2,
|
||||||
|
colors,
|
||||||
|
Message::BrushCyclicSpeedChanged,
|
||||||
|
),
|
||||||
]
|
]
|
||||||
.spacing(4)
|
.spacing(4)
|
||||||
.into()
|
.into()
|
||||||
|
|||||||
@@ -134,6 +134,17 @@ fn brush_settings(
|
|||||||
|v| Message::BrushVariantAmountChanged(v / 100.0),
|
|v| Message::BrushVariantAmountChanged(v / 100.0),
|
||||||
c
|
c
|
||||||
),
|
),
|
||||||
|
checkbox("Cyclic Color", ts.brush_cyclic_color)
|
||||||
|
.on_toggle(Message::BrushCyclicColorToggled)
|
||||||
|
.size(11),
|
||||||
|
prop_slider(
|
||||||
|
"Cyclic Speed",
|
||||||
|
ts.brush_cyclic_speed.clamp(0.01, 5.0),
|
||||||
|
0.01,
|
||||||
|
5.0,
|
||||||
|
Message::BrushCyclicSpeedChanged,
|
||||||
|
c
|
||||||
|
),
|
||||||
]
|
]
|
||||||
.spacing(4)
|
.spacing(4)
|
||||||
}
|
}
|
||||||
@@ -186,6 +197,28 @@ fn spray_settings(
|
|||||||
|v| Message::BrushHardnessChanged(v / 100.0),
|
|v| Message::BrushHardnessChanged(v / 100.0),
|
||||||
c
|
c
|
||||||
),
|
),
|
||||||
|
checkbox("Color Variant", ts.brush_color_variant)
|
||||||
|
.on_toggle(Message::BrushColorVariantToggled)
|
||||||
|
.size(11),
|
||||||
|
prop_slider(
|
||||||
|
"Variant Amount",
|
||||||
|
ts.brush_variant_amount * 100.0,
|
||||||
|
0.0,
|
||||||
|
100.0,
|
||||||
|
|v| Message::BrushVariantAmountChanged(v / 100.0),
|
||||||
|
c
|
||||||
|
),
|
||||||
|
checkbox("Cyclic Color", ts.brush_cyclic_color)
|
||||||
|
.on_toggle(Message::BrushCyclicColorToggled)
|
||||||
|
.size(11),
|
||||||
|
prop_slider(
|
||||||
|
"Cyclic Speed",
|
||||||
|
ts.brush_cyclic_speed.clamp(0.01, 5.0),
|
||||||
|
0.01,
|
||||||
|
5.0,
|
||||||
|
Message::BrushCyclicSpeedChanged,
|
||||||
|
c
|
||||||
|
),
|
||||||
]
|
]
|
||||||
.spacing(4)
|
.spacing(4)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,12 @@ pub struct ToolSettings {
|
|||||||
/// Magnitude of the per-dab color variation (0.0..1.0).
|
/// Magnitude of the per-dab color variation (0.0..1.0).
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub brush_variant_amount: f32,
|
pub brush_variant_amount: f32,
|
||||||
|
/// True when the brush color should cycle through the hue over stroke distance.
|
||||||
|
#[serde(default)]
|
||||||
|
pub brush_cyclic_color: bool,
|
||||||
|
/// Speed of the hue cycle along the stroke (0.01..5.0).
|
||||||
|
#[serde(default)]
|
||||||
|
pub brush_cyclic_speed: f32,
|
||||||
pub eraser_size: f32,
|
pub eraser_size: f32,
|
||||||
pub eraser_opacity: f32,
|
pub eraser_opacity: f32,
|
||||||
pub pen_size: f32,
|
pub pen_size: f32,
|
||||||
@@ -192,6 +198,8 @@ impl Default for ToolSettings {
|
|||||||
brush_spacing: 1.0,
|
brush_spacing: 1.0,
|
||||||
brush_color_variant: false,
|
brush_color_variant: false,
|
||||||
brush_variant_amount: 0.0,
|
brush_variant_amount: 0.0,
|
||||||
|
brush_cyclic_color: false,
|
||||||
|
brush_cyclic_speed: 0.5,
|
||||||
eraser_size: 20.0,
|
eraser_size: 20.0,
|
||||||
eraser_opacity: 1.0,
|
eraser_opacity: 1.0,
|
||||||
pen_size: 2.0,
|
pen_size: 2.0,
|
||||||
@@ -344,6 +352,8 @@ impl AppSettings {
|
|||||||
self.tool_settings.brush_hardness = tool_state.brush_hardness;
|
self.tool_settings.brush_hardness = tool_state.brush_hardness;
|
||||||
self.tool_settings.brush_color_variant = tool_state.brush_color_variant;
|
self.tool_settings.brush_color_variant = tool_state.brush_color_variant;
|
||||||
self.tool_settings.brush_variant_amount = tool_state.brush_variant_amount;
|
self.tool_settings.brush_variant_amount = tool_state.brush_variant_amount;
|
||||||
|
self.tool_settings.brush_cyclic_color = tool_state.brush_cyclic_color;
|
||||||
|
self.tool_settings.brush_cyclic_speed = tool_state.brush_cyclic_speed;
|
||||||
self.tool_settings.last_active_tool = format!("{:?}", tool_state.active_tool);
|
self.tool_settings.last_active_tool = format!("{:?}", tool_state.active_tool);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,6 +364,8 @@ impl AppSettings {
|
|||||||
tool_state.brush_hardness = self.tool_settings.brush_hardness;
|
tool_state.brush_hardness = self.tool_settings.brush_hardness;
|
||||||
tool_state.brush_color_variant = self.tool_settings.brush_color_variant;
|
tool_state.brush_color_variant = self.tool_settings.brush_color_variant;
|
||||||
tool_state.brush_variant_amount = self.tool_settings.brush_variant_amount;
|
tool_state.brush_variant_amount = self.tool_settings.brush_variant_amount;
|
||||||
|
tool_state.brush_cyclic_color = self.tool_settings.brush_cyclic_color;
|
||||||
|
tool_state.brush_cyclic_speed = self.tool_settings.brush_cyclic_speed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user