Add tool skeletons
This commit is contained in:
parent
37ac9b6abe
commit
2c9d8c1589
|
|
@ -11,9 +11,10 @@ use vello::kurbo::Point;
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum Tool {
|
||||
// ── Vector / shared tools ──────────────────────────────────────────────
|
||||
/// Selection tool - select and move objects
|
||||
Select,
|
||||
/// Draw/Pen tool - freehand drawing
|
||||
/// Draw/Brush tool - freehand drawing (vector) / paintbrush (raster)
|
||||
Draw,
|
||||
/// Transform tool - scale, rotate, skew
|
||||
Transform,
|
||||
|
|
@ -37,12 +38,48 @@ pub enum Tool {
|
|||
RegionSelect,
|
||||
/// Split tool - split audio/video clips at a point
|
||||
Split,
|
||||
// ── Raster brush tools ────────────────────────────────────────────────
|
||||
/// Pencil tool - hard-edged raster brush
|
||||
Pencil,
|
||||
/// Pen tool - pressure-sensitive raster pen
|
||||
Pen,
|
||||
/// Airbrush tool - soft spray raster brush
|
||||
Airbrush,
|
||||
/// Erase tool - erase raster pixels
|
||||
Erase,
|
||||
/// Smudge tool - smudge/blend raster pixels
|
||||
Smudge,
|
||||
/// Lasso select tool - freehand selection on raster layers
|
||||
/// Clone Stamp - copy pixels from a source point
|
||||
CloneStamp,
|
||||
/// Healing Brush - content-aware pixel repair
|
||||
HealingBrush,
|
||||
/// Pattern Stamp - paint with a repeating pattern
|
||||
PatternStamp,
|
||||
/// Dodge/Burn - lighten or darken pixels
|
||||
DodgeBurn,
|
||||
/// Sponge - saturate or desaturate pixels
|
||||
Sponge,
|
||||
/// Blur/Sharpen - blur or sharpen pixel regions
|
||||
BlurSharpen,
|
||||
// ── Raster fill / shape ───────────────────────────────────────────────
|
||||
/// Gradient tool - fill with a gradient
|
||||
Gradient,
|
||||
/// Custom Shape tool - draw from a shape library
|
||||
CustomShape,
|
||||
// ── Raster selection tools ────────────────────────────────────────────
|
||||
/// Elliptical marquee selection
|
||||
SelectEllipse,
|
||||
/// Lasso select tool - freehand / polygonal / magnetic selection
|
||||
SelectLasso,
|
||||
/// Magic Wand - select by colour similarity
|
||||
MagicWand,
|
||||
/// Quick Select - brush-based smart selection
|
||||
QuickSelect,
|
||||
// ── Raster transform tools ────────────────────────────────────────────
|
||||
/// Warp / perspective transform
|
||||
Warp,
|
||||
/// Liquify - freeform pixel warping
|
||||
Liquify,
|
||||
}
|
||||
|
||||
/// Region select mode
|
||||
|
|
@ -60,6 +97,23 @@ impl Default for RegionSelectMode {
|
|||
}
|
||||
}
|
||||
|
||||
/// Lasso selection sub-mode
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum LassoMode {
|
||||
/// Freehand lasso (existing, implemented)
|
||||
Freehand,
|
||||
/// Click-to-place polygonal lasso
|
||||
Polygonal,
|
||||
/// Magnetically snaps to edges
|
||||
Magnetic,
|
||||
}
|
||||
|
||||
impl Default for LassoMode {
|
||||
fn default() -> Self {
|
||||
Self::Freehand
|
||||
}
|
||||
}
|
||||
|
||||
/// Tool state tracking for interactive operations
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ToolState {
|
||||
|
|
@ -229,44 +283,77 @@ impl Tool {
|
|||
/// Get display name for the tool
|
||||
pub fn display_name(self) -> &'static str {
|
||||
match self {
|
||||
Tool::Select => "Select",
|
||||
Tool::Draw => "Draw",
|
||||
Tool::Transform => "Transform",
|
||||
Tool::Rectangle => "Rectangle",
|
||||
Tool::Ellipse => "Ellipse",
|
||||
Tool::PaintBucket => "Paint Bucket",
|
||||
Tool::Eyedropper => "Eyedropper",
|
||||
Tool::Line => "Line",
|
||||
Tool::Polygon => "Polygon",
|
||||
Tool::BezierEdit => "Bezier Edit",
|
||||
Tool::Text => "Text",
|
||||
Tool::RegionSelect => "Region Select",
|
||||
Tool::Split => "Split",
|
||||
Tool::Erase => "Erase",
|
||||
Tool::Smudge => "Smudge",
|
||||
Tool::SelectLasso => "Lasso Select",
|
||||
Tool::Select => "Select",
|
||||
Tool::Draw => "Brush",
|
||||
Tool::Transform => "Transform",
|
||||
Tool::Rectangle => "Rectangle",
|
||||
Tool::Ellipse => "Ellipse",
|
||||
Tool::PaintBucket => "Paint Bucket",
|
||||
Tool::Eyedropper => "Eyedropper",
|
||||
Tool::Line => "Line",
|
||||
Tool::Polygon => "Polygon",
|
||||
Tool::BezierEdit => "Bezier Edit",
|
||||
Tool::Text => "Text",
|
||||
Tool::RegionSelect => "Region Select",
|
||||
Tool::Split => "Split",
|
||||
Tool::Pencil => "Pencil",
|
||||
Tool::Pen => "Pen",
|
||||
Tool::Airbrush => "Airbrush",
|
||||
Tool::Erase => "Eraser",
|
||||
Tool::Smudge => "Smudge",
|
||||
Tool::CloneStamp => "Clone Stamp",
|
||||
Tool::HealingBrush => "Healing Brush",
|
||||
Tool::PatternStamp => "Pattern Stamp",
|
||||
Tool::DodgeBurn => "Dodge / Burn",
|
||||
Tool::Sponge => "Sponge",
|
||||
Tool::BlurSharpen => "Blur / Sharpen",
|
||||
Tool::Gradient => "Gradient",
|
||||
Tool::CustomShape => "Custom Shape",
|
||||
Tool::SelectEllipse => "Elliptical Select",
|
||||
Tool::SelectLasso => "Lasso Select",
|
||||
Tool::MagicWand => "Magic Wand",
|
||||
Tool::QuickSelect => "Quick Select",
|
||||
Tool::Warp => "Warp",
|
||||
Tool::Liquify => "Liquify",
|
||||
}
|
||||
}
|
||||
|
||||
/// Get SVG icon file name for the tool
|
||||
pub fn icon_file(self) -> &'static str {
|
||||
match self {
|
||||
Tool::Select => "select.svg",
|
||||
Tool::Draw => "draw.svg",
|
||||
Tool::Transform => "transform.svg",
|
||||
Tool::Rectangle => "rectangle.svg",
|
||||
Tool::Ellipse => "ellipse.svg",
|
||||
Tool::PaintBucket => "paint_bucket.svg",
|
||||
Tool::Eyedropper => "eyedropper.svg",
|
||||
Tool::Line => "line.svg",
|
||||
Tool::Polygon => "polygon.svg",
|
||||
Tool::BezierEdit => "bezier_edit.svg",
|
||||
Tool::Text => "text.svg",
|
||||
Tool::RegionSelect => "region_select.svg",
|
||||
Tool::Split => "split.svg",
|
||||
Tool::Erase => "erase.svg",
|
||||
Tool::Smudge => "smudge.svg",
|
||||
Tool::SelectLasso => "lasso.svg",
|
||||
Tool::Select => "select.svg",
|
||||
Tool::Draw => "draw.svg",
|
||||
Tool::Transform => "transform.svg",
|
||||
Tool::Rectangle => "rectangle.svg",
|
||||
Tool::Ellipse => "ellipse.svg",
|
||||
Tool::PaintBucket => "paint_bucket.svg",
|
||||
Tool::Eyedropper => "eyedropper.svg",
|
||||
Tool::Line => "line.svg",
|
||||
Tool::Polygon => "polygon.svg",
|
||||
Tool::BezierEdit => "bezier_edit.svg",
|
||||
Tool::Text => "text.svg",
|
||||
Tool::RegionSelect => "region_select.svg",
|
||||
Tool::Split => "split.svg",
|
||||
Tool::Erase => "erase.svg",
|
||||
Tool::Smudge => "smudge.svg",
|
||||
Tool::SelectLasso => "lasso.svg",
|
||||
// Not yet implemented — use the placeholder icon
|
||||
Tool::Pencil
|
||||
| Tool::Pen
|
||||
| Tool::Airbrush
|
||||
| Tool::CloneStamp
|
||||
| Tool::HealingBrush
|
||||
| Tool::PatternStamp
|
||||
| Tool::DodgeBurn
|
||||
| Tool::Sponge
|
||||
| Tool::BlurSharpen
|
||||
| Tool::Gradient
|
||||
| Tool::CustomShape
|
||||
| Tool::SelectEllipse
|
||||
| Tool::MagicWand
|
||||
| Tool::QuickSelect
|
||||
| Tool::Warp
|
||||
| Tool::Liquify => "todo.svg",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -294,7 +381,23 @@ impl Tool {
|
|||
match layer_type {
|
||||
None | Some(LayerType::Vector) => Tool::all(),
|
||||
Some(LayerType::Audio) | Some(LayerType::Video) => &[Tool::Select, Tool::Split],
|
||||
Some(LayerType::Raster) => &[Tool::Select, Tool::SelectLasso, Tool::Draw, Tool::Erase, Tool::Smudge, Tool::Eyedropper],
|
||||
Some(LayerType::Raster) => &[
|
||||
// Brush tools
|
||||
Tool::Draw, Tool::Pencil, Tool::Pen, Tool::Airbrush,
|
||||
Tool::Erase, Tool::Smudge,
|
||||
Tool::CloneStamp, Tool::HealingBrush, Tool::PatternStamp,
|
||||
Tool::DodgeBurn, Tool::Sponge, Tool::BlurSharpen,
|
||||
// Fill / shape
|
||||
Tool::PaintBucket, Tool::Gradient,
|
||||
Tool::Rectangle, Tool::Ellipse, Tool::Polygon, Tool::Line, Tool::CustomShape,
|
||||
// Selection
|
||||
Tool::Select, Tool::SelectEllipse, Tool::SelectLasso,
|
||||
Tool::MagicWand, Tool::QuickSelect,
|
||||
// Transform
|
||||
Tool::Transform, Tool::Warp, Tool::Liquify,
|
||||
// Utility
|
||||
Tool::Eyedropper,
|
||||
],
|
||||
_ => &[Tool::Select],
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@
|
|||
"children": [
|
||||
{
|
||||
"type": "vertical-grid",
|
||||
"percent": 30,
|
||||
"percent": 67,
|
||||
"children": [
|
||||
{ "type": "pane", "name": "toolbar" },
|
||||
{ "type": "pane", "name": "infopanel" }
|
||||
|
|
|
|||
|
|
@ -32,22 +32,41 @@ impl CustomCursor {
|
|||
/// Convert a Tool enum to the corresponding custom cursor
|
||||
pub fn from_tool(tool: Tool) -> Self {
|
||||
match tool {
|
||||
Tool::Select => CustomCursor::Select,
|
||||
Tool::Draw => CustomCursor::Draw,
|
||||
Tool::Transform => CustomCursor::Transform,
|
||||
Tool::Rectangle => CustomCursor::Rectangle,
|
||||
Tool::Ellipse => CustomCursor::Ellipse,
|
||||
Tool::PaintBucket => CustomCursor::PaintBucket,
|
||||
Tool::Eyedropper => CustomCursor::Eyedropper,
|
||||
Tool::Line => CustomCursor::Line,
|
||||
Tool::Polygon => CustomCursor::Polygon,
|
||||
Tool::BezierEdit => CustomCursor::BezierEdit,
|
||||
Tool::Text => CustomCursor::Text,
|
||||
Tool::RegionSelect => CustomCursor::Select, // Reuse select cursor for now
|
||||
Tool::Split => CustomCursor::Select, // Reuse select cursor for now
|
||||
Tool::Erase => CustomCursor::Draw, // Reuse draw cursor for raster erase
|
||||
Tool::Smudge => CustomCursor::Draw, // Reuse draw cursor for raster smudge
|
||||
Tool::SelectLasso => CustomCursor::Select, // Reuse select cursor for lasso
|
||||
Tool::Select => CustomCursor::Select,
|
||||
Tool::Draw => CustomCursor::Draw,
|
||||
Tool::Transform => CustomCursor::Transform,
|
||||
Tool::Rectangle => CustomCursor::Rectangle,
|
||||
Tool::Ellipse => CustomCursor::Ellipse,
|
||||
Tool::PaintBucket => CustomCursor::PaintBucket,
|
||||
Tool::Eyedropper => CustomCursor::Eyedropper,
|
||||
Tool::Line => CustomCursor::Line,
|
||||
Tool::Polygon => CustomCursor::Polygon,
|
||||
Tool::BezierEdit => CustomCursor::BezierEdit,
|
||||
Tool::Text => CustomCursor::Text,
|
||||
Tool::RegionSelect => CustomCursor::Select,
|
||||
Tool::Split => CustomCursor::Select,
|
||||
Tool::Erase => CustomCursor::Draw,
|
||||
Tool::Smudge => CustomCursor::Draw,
|
||||
Tool::SelectLasso => CustomCursor::Select,
|
||||
// Raster brush tools — use draw cursor until implemented
|
||||
Tool::Pencil
|
||||
| Tool::Pen
|
||||
| Tool::Airbrush
|
||||
| Tool::CloneStamp
|
||||
| Tool::HealingBrush
|
||||
| Tool::PatternStamp
|
||||
| Tool::DodgeBurn
|
||||
| Tool::Sponge
|
||||
| Tool::BlurSharpen => CustomCursor::Draw,
|
||||
// Selection tools — use select cursor until implemented
|
||||
Tool::SelectEllipse
|
||||
| Tool::MagicWand
|
||||
| Tool::QuickSelect => CustomCursor::Select,
|
||||
// Other tools — use select cursor until implemented
|
||||
Tool::Gradient
|
||||
| Tool::CustomShape
|
||||
| Tool::Warp
|
||||
| Tool::Liquify => CustomCursor::Select,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -429,24 +429,26 @@ impl AppAction {
|
|||
/// `Tool::Split` has no tool-shortcut action (it's triggered via the menu).
|
||||
pub fn tool_app_action(tool: lightningbeam_core::tool::Tool) -> Option<AppAction> {
|
||||
use lightningbeam_core::tool::Tool;
|
||||
Some(match tool {
|
||||
Tool::Select => AppAction::ToolSelect,
|
||||
Tool::Draw => AppAction::ToolDraw,
|
||||
Tool::Transform => AppAction::ToolTransform,
|
||||
Tool::Rectangle => AppAction::ToolRectangle,
|
||||
Tool::Ellipse => AppAction::ToolEllipse,
|
||||
Tool::PaintBucket => AppAction::ToolPaintBucket,
|
||||
Tool::Eyedropper => AppAction::ToolEyedropper,
|
||||
Tool::Line => AppAction::ToolLine,
|
||||
Tool::Polygon => AppAction::ToolPolygon,
|
||||
Tool::BezierEdit => AppAction::ToolBezierEdit,
|
||||
Tool::Text => AppAction::ToolText,
|
||||
Tool::RegionSelect => AppAction::ToolRegionSelect,
|
||||
Tool::Erase => AppAction::ToolErase,
|
||||
Tool::Smudge => AppAction::ToolSmudge,
|
||||
Tool::SelectLasso => AppAction::ToolSelectLasso,
|
||||
Tool::Split => AppAction::ToolSplit,
|
||||
})
|
||||
match tool {
|
||||
Tool::Select => Some(AppAction::ToolSelect),
|
||||
Tool::Draw => Some(AppAction::ToolDraw),
|
||||
Tool::Transform => Some(AppAction::ToolTransform),
|
||||
Tool::Rectangle => Some(AppAction::ToolRectangle),
|
||||
Tool::Ellipse => Some(AppAction::ToolEllipse),
|
||||
Tool::PaintBucket => Some(AppAction::ToolPaintBucket),
|
||||
Tool::Eyedropper => Some(AppAction::ToolEyedropper),
|
||||
Tool::Line => Some(AppAction::ToolLine),
|
||||
Tool::Polygon => Some(AppAction::ToolPolygon),
|
||||
Tool::BezierEdit => Some(AppAction::ToolBezierEdit),
|
||||
Tool::Text => Some(AppAction::ToolText),
|
||||
Tool::RegionSelect => Some(AppAction::ToolRegionSelect),
|
||||
Tool::Erase => Some(AppAction::ToolErase),
|
||||
Tool::Smudge => Some(AppAction::ToolSmudge),
|
||||
Tool::SelectLasso => Some(AppAction::ToolSelectLasso),
|
||||
Tool::Split => Some(AppAction::ToolSplit),
|
||||
// New tools have no keybinding yet
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// === Default bindings ===
|
||||
|
|
|
|||
|
|
@ -332,6 +332,7 @@ mod tool_icons {
|
|||
pub static ERASE: &[u8] = include_bytes!("../../../src/assets/erase.svg");
|
||||
pub static SMUDGE: &[u8] = include_bytes!("../../../src/assets/smudge.svg");
|
||||
pub static LASSO: &[u8] = include_bytes!("../../../src/assets/lasso.svg");
|
||||
pub static TODO: &[u8] = include_bytes!("../../../src/assets/todo.svg");
|
||||
}
|
||||
|
||||
/// Embedded focus icon SVGs
|
||||
|
|
@ -399,11 +400,28 @@ impl ToolIconCache {
|
|||
Tool::Polygon => tool_icons::POLYGON,
|
||||
Tool::BezierEdit => tool_icons::BEZIER_EDIT,
|
||||
Tool::Text => tool_icons::TEXT,
|
||||
Tool::RegionSelect => tool_icons::SELECT, // Reuse select icon for now
|
||||
Tool::RegionSelect => tool_icons::SELECT,
|
||||
Tool::Split => tool_icons::SPLIT,
|
||||
Tool::Erase => tool_icons::ERASE,
|
||||
Tool::Smudge => tool_icons::SMUDGE,
|
||||
Tool::SelectLasso => tool_icons::LASSO,
|
||||
// Not yet implemented — use placeholder icon
|
||||
Tool::Pencil
|
||||
| Tool::Pen
|
||||
| Tool::Airbrush
|
||||
| Tool::CloneStamp
|
||||
| Tool::HealingBrush
|
||||
| Tool::PatternStamp
|
||||
| Tool::DodgeBurn
|
||||
| Tool::Sponge
|
||||
| Tool::BlurSharpen
|
||||
| Tool::Gradient
|
||||
| Tool::CustomShape
|
||||
| Tool::SelectEllipse
|
||||
| Tool::MagicWand
|
||||
| Tool::QuickSelect
|
||||
| Tool::Warp
|
||||
| Tool::Liquify => tool_icons::TODO,
|
||||
};
|
||||
if let Some(texture) = rasterize_svg(svg_data, tool.icon_file(), 180, ctx) {
|
||||
self.icons.insert(tool, texture);
|
||||
|
|
@ -856,6 +874,7 @@ struct EditorApp {
|
|||
// Region select state
|
||||
region_selection: Option<lightningbeam_core::selection::RegionSelection>,
|
||||
region_select_mode: lightningbeam_core::tool::RegionSelectMode,
|
||||
lasso_mode: lightningbeam_core::tool::LassoMode,
|
||||
|
||||
// VU meter levels
|
||||
input_level: f32,
|
||||
|
|
@ -1127,6 +1146,7 @@ impl EditorApp {
|
|||
polygon_sides: 5, // Default to pentagon
|
||||
region_selection: None,
|
||||
region_select_mode: lightningbeam_core::tool::RegionSelectMode::default(),
|
||||
lasso_mode: lightningbeam_core::tool::LassoMode::default(),
|
||||
input_level: 0.0,
|
||||
output_level: (0.0, 0.0),
|
||||
track_levels: HashMap::new(),
|
||||
|
|
@ -5590,6 +5610,7 @@ impl eframe::App for EditorApp {
|
|||
script_saved: &mut self.script_saved,
|
||||
region_selection: &mut self.region_selection,
|
||||
region_select_mode: &mut self.region_select_mode,
|
||||
lasso_mode: &mut self.lasso_mode,
|
||||
pending_graph_loads: &self.pending_graph_loads,
|
||||
clipboard_consumed: &mut clipboard_consumed,
|
||||
keymap: &self.keymap,
|
||||
|
|
|
|||
|
|
@ -169,7 +169,10 @@ impl InfopanelPane {
|
|||
.and_then(|id| shared.action_executor.document().get_layer(&id))
|
||||
.map_or(false, |l| matches!(l, AnyLayer::Raster(_)));
|
||||
|
||||
let is_raster_paint_tool = active_is_raster && matches!(tool, Tool::Draw | Tool::Erase | Tool::Smudge);
|
||||
let is_raster_paint_tool = active_is_raster && matches!(
|
||||
tool,
|
||||
Tool::Draw | Tool::Pencil | Tool::Pen | Tool::Airbrush | Tool::Erase | Tool::Smudge
|
||||
);
|
||||
|
||||
// Only show tool options for tools that have options
|
||||
let is_vector_tool = !active_is_raster && matches!(
|
||||
|
|
@ -319,7 +322,7 @@ impl InfopanelPane {
|
|||
}
|
||||
|
||||
// Raster paint tools
|
||||
Tool::Draw | Tool::Erase if is_raster_paint_tool => {
|
||||
Tool::Draw | Tool::Pencil | Tool::Pen | Tool::Airbrush | Tool::Erase if is_raster_paint_tool => {
|
||||
self.render_raster_tool_options(ui, shared, matches!(tool, Tool::Erase));
|
||||
}
|
||||
|
||||
|
|
@ -513,6 +516,11 @@ impl InfopanelPane {
|
|||
*shared.brush_hardness = s.hardness.clamp(0.0, 1.0);
|
||||
*shared.brush_spacing = s.dabs_per_radius;
|
||||
*shared.active_brush_settings = s.clone();
|
||||
// If the user was on a preset-backed tool (Pencil/Pen/Airbrush)
|
||||
// and manually picked a different brush, revert to the generic tool.
|
||||
if matches!(*shared.selected_tool, Tool::Pencil | Tool::Pen | Tool::Airbrush) {
|
||||
*shared.selected_tool = Tool::Draw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -283,6 +283,8 @@ pub struct SharedPaneState<'a> {
|
|||
pub region_selection: &'a mut Option<lightningbeam_core::selection::RegionSelection>,
|
||||
/// Region select mode (Rectangle or Lasso)
|
||||
pub region_select_mode: &'a mut lightningbeam_core::tool::RegionSelectMode,
|
||||
/// Lasso select sub-mode (Freehand / Polygonal / Magnetic)
|
||||
pub lasso_mode: &'a mut lightningbeam_core::tool::LassoMode,
|
||||
/// Counter for in-flight graph preset loads — increment when sending a
|
||||
/// GraphLoadPreset command so the repaint loop stays alive until the
|
||||
/// audio thread sends GraphPresetLoaded back
|
||||
|
|
|
|||
|
|
@ -7518,6 +7518,9 @@ impl StagePane {
|
|||
self.handle_draw_tool(ui, &response, world_pos, shared);
|
||||
}
|
||||
}
|
||||
Tool::Pencil | Tool::Pen | Tool::Airbrush => {
|
||||
self.handle_raster_stroke_tool(ui, &response, world_pos, lightningbeam_core::raster_layer::RasterBlendMode::Normal, shared);
|
||||
}
|
||||
Tool::Erase => {
|
||||
self.handle_raster_stroke_tool(ui, &response, world_pos, lightningbeam_core::raster_layer::RasterBlendMode::Erase, shared);
|
||||
}
|
||||
|
|
@ -8001,8 +8004,11 @@ impl StagePane {
|
|||
|
||||
// Compute semi-axes (world pixels) and dab rotation angle.
|
||||
let (a_world, b_world, dab_angle_rad) = match *shared.selected_tool {
|
||||
Tool::Erase => (*shared.eraser_radius, *shared.eraser_radius, 0.0_f32),
|
||||
Tool::Smudge => (*shared.smudge_radius, *shared.smudge_radius, 0.0_f32),
|
||||
Tool::Erase => (*shared.eraser_radius, *shared.eraser_radius, 0.0_f32),
|
||||
Tool::Smudge
|
||||
| Tool::BlurSharpen
|
||||
| Tool::DodgeBurn
|
||||
| Tool::Sponge => (*shared.smudge_radius, *shared.smudge_radius, 0.0_f32),
|
||||
_ => {
|
||||
let bs = &shared.active_brush_settings;
|
||||
let r = *shared.brush_radius;
|
||||
|
|
@ -8637,7 +8643,10 @@ impl PaneRenderer for StagePane {
|
|||
use lightningbeam_core::tool::Tool;
|
||||
let is_raster_paint = matches!(
|
||||
*shared.selected_tool,
|
||||
Tool::Draw | Tool::Erase | Tool::Smudge
|
||||
Tool::Draw | Tool::Pencil | Tool::Pen | Tool::Airbrush
|
||||
| Tool::Erase | Tool::Smudge
|
||||
| Tool::CloneStamp | Tool::HealingBrush | Tool::PatternStamp
|
||||
| Tool::DodgeBurn | Tool::Sponge | Tool::BlurSharpen
|
||||
) && shared.active_layer_id.and_then(|id| {
|
||||
shared.action_executor.document().get_layer(&id)
|
||||
}).map_or(false, |l| matches!(l, lightningbeam_core::layer::AnyLayer::Raster(_)));
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
|
||||
use eframe::egui;
|
||||
use lightningbeam_core::layer::{AnyLayer, LayerType};
|
||||
use lightningbeam_core::tool::{Tool, RegionSelectMode};
|
||||
use lightningbeam_core::tool::{Tool, RegionSelectMode, LassoMode};
|
||||
use lightningbeam_core::brush_settings::bundled_brushes;
|
||||
use crate::keymap::tool_app_action;
|
||||
use super::{NodePath, PaneRenderer, SharedPaneState};
|
||||
|
||||
|
|
@ -101,7 +102,7 @@ impl PaneRenderer for ToolbarPane {
|
|||
}
|
||||
|
||||
// Draw sub-tool arrow indicator for tools with modes
|
||||
let has_sub_tools = matches!(tool, Tool::RegionSelect);
|
||||
let has_sub_tools = matches!(tool, Tool::RegionSelect | Tool::SelectLasso);
|
||||
if has_sub_tools {
|
||||
let arrow_size = 6.0;
|
||||
let margin = 4.0;
|
||||
|
|
@ -125,6 +126,22 @@ impl PaneRenderer for ToolbarPane {
|
|||
// Check for click first
|
||||
if response.clicked() {
|
||||
*shared.selected_tool = *tool;
|
||||
// Preset-backed tools: auto-select the matching bundled brush.
|
||||
let preset_name = match tool {
|
||||
Tool::Pencil => Some("Pencil"),
|
||||
Tool::Pen => Some("Pen"),
|
||||
Tool::Airbrush => Some("Airbrush"),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(name) = preset_name {
|
||||
if let Some(preset) = bundled_brushes().iter().find(|p| p.name == name) {
|
||||
let s = &preset.settings;
|
||||
*shared.brush_opacity = s.opaque.clamp(0.0, 1.0);
|
||||
*shared.brush_hardness = s.hardness.clamp(0.0, 1.0);
|
||||
*shared.brush_spacing = s.dabs_per_radius;
|
||||
*shared.active_brush_settings = s.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Right-click context menu for tools with sub-options
|
||||
|
|
@ -150,6 +167,33 @@ impl PaneRenderer for ToolbarPane {
|
|||
ui.close();
|
||||
}
|
||||
}
|
||||
Tool::SelectLasso => {
|
||||
ui.set_min_width(130.0);
|
||||
if ui.selectable_label(
|
||||
*shared.lasso_mode == LassoMode::Freehand,
|
||||
"Freehand",
|
||||
).clicked() {
|
||||
*shared.lasso_mode = LassoMode::Freehand;
|
||||
*shared.selected_tool = Tool::SelectLasso;
|
||||
ui.close();
|
||||
}
|
||||
if ui.selectable_label(
|
||||
*shared.lasso_mode == LassoMode::Polygonal,
|
||||
"Polygonal",
|
||||
).clicked() {
|
||||
*shared.lasso_mode = LassoMode::Polygonal;
|
||||
*shared.selected_tool = Tool::SelectLasso;
|
||||
ui.close();
|
||||
}
|
||||
if ui.selectable_label(
|
||||
*shared.lasso_mode == LassoMode::Magnetic,
|
||||
"Magnetic",
|
||||
).clicked() {
|
||||
*shared.lasso_mode = LassoMode::Magnetic;
|
||||
*shared.selected_tool = Tool::SelectLasso;
|
||||
ui.close();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
|
|
@ -176,6 +220,13 @@ impl PaneRenderer for ToolbarPane {
|
|||
RegionSelectMode::Lasso => "Lasso",
|
||||
};
|
||||
format!("{} - {}{}\nRight-click for options", tool.display_name(), mode, hint)
|
||||
} else if *tool == Tool::SelectLasso {
|
||||
let mode = match *shared.lasso_mode {
|
||||
LassoMode::Freehand => "Freehand",
|
||||
LassoMode::Polygonal => "Polygonal",
|
||||
LassoMode::Magnetic => "Magnetic",
|
||||
};
|
||||
format!("{} - {}{}\nRight-click for options", tool.display_name(), mode, hint)
|
||||
} else {
|
||||
format!("{}{}", tool.display_name(), hint)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/>
|
||||
<line x1="12" y1="17" x2="12.01" y2="17"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 297 B |
Loading…
Reference in New Issue