diff --git a/lightningbeam-ui/lightningbeam-core/src/tool.rs b/lightningbeam-ui/lightningbeam-core/src/tool.rs index e59485a..67b77f5 100644 --- a/lightningbeam-ui/lightningbeam-core/src/tool.rs +++ b/lightningbeam-ui/lightningbeam-core/src/tool.rs @@ -35,6 +35,8 @@ pub enum Tool { Text, /// Region select tool - select sub-regions of shapes by clipping RegionSelect, + /// Split tool - split audio/video clips at a point + Split, } /// Region select mode @@ -210,6 +212,7 @@ impl Tool { Tool::BezierEdit => "Bezier Edit", Tool::Text => "Text", Tool::RegionSelect => "Region Select", + Tool::Split => "Split", } } @@ -228,10 +231,11 @@ impl Tool { Tool::BezierEdit => "bezier_edit.svg", Tool::Text => "text.svg", Tool::RegionSelect => "region_select.svg", + Tool::Split => "split.svg", } } - /// Get all available tools + /// Get all vector-layer tools (the full drawing toolset) pub fn all() -> &'static [Tool] { &[ Tool::Select, @@ -249,6 +253,16 @@ impl Tool { ] } + /// Get the tools available for a given layer type + pub fn for_layer_type(layer_type: Option) -> &'static [Tool] { + use crate::layer::LayerType; + match layer_type { + None | Some(LayerType::Vector) => Tool::all(), + Some(LayerType::Audio) | Some(LayerType::Video) => &[Tool::Select, Tool::Split], + _ => &[Tool::Select], + } + } + /// Get keyboard shortcut hint pub fn shortcut_hint(self) -> &'static str { match self { @@ -264,6 +278,7 @@ impl Tool { Tool::BezierEdit => "A", Tool::Text => "T", Tool::RegionSelect => "S", + Tool::Split => "C", } } } diff --git a/lightningbeam-ui/lightningbeam-editor/src/custom_cursor.rs b/lightningbeam-ui/lightningbeam-editor/src/custom_cursor.rs index 8d6acaa..19999e0 100644 --- a/lightningbeam-ui/lightningbeam-editor/src/custom_cursor.rs +++ b/lightningbeam-ui/lightningbeam-editor/src/custom_cursor.rs @@ -44,6 +44,7 @@ impl CustomCursor { 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 } } diff --git a/lightningbeam-ui/lightningbeam-editor/src/main.rs b/lightningbeam-ui/lightningbeam-editor/src/main.rs index 80819ac..33744cb 100644 --- a/lightningbeam-ui/lightningbeam-editor/src/main.rs +++ b/lightningbeam-ui/lightningbeam-editor/src/main.rs @@ -320,6 +320,7 @@ mod tool_icons { pub static POLYGON: &[u8] = include_bytes!("../../../src/assets/polygon.svg"); pub static BEZIER_EDIT: &[u8] = include_bytes!("../../../src/assets/bezier_edit.svg"); pub static TEXT: &[u8] = include_bytes!("../../../src/assets/text.svg"); + pub static SPLIT: &[u8] = include_bytes!("../../../src/assets/split.svg"); } /// Embedded focus icon SVGs @@ -387,6 +388,7 @@ impl ToolIconCache { Tool::BezierEdit => tool_icons::BEZIER_EDIT, Tool::Text => tool_icons::TEXT, Tool::RegionSelect => tool_icons::SELECT, // Reuse select icon for now + Tool::Split => tool_icons::SPLIT, }; if let Some(texture) = rasterize_svg(svg_data, tool.icon_file(), 180, ctx) { self.icons.insert(tool, texture); @@ -6016,7 +6018,7 @@ fn render_pane( } // Icon - if let Some(icon) = ctx.icon_cache.get_or_load(tab_type, ui.ctx()) { + if let Some(icon) = ctx.shared.icon_cache.get_or_load(tab_type, ui.ctx()) { let icon_texture_id = icon.id(); ui.painter().image( icon_texture_id, diff --git a/lightningbeam-ui/lightningbeam-editor/src/panes/toolbar.rs b/lightningbeam-ui/lightningbeam-editor/src/panes/toolbar.rs index 019970d..e652c63 100644 --- a/lightningbeam-ui/lightningbeam-editor/src/panes/toolbar.rs +++ b/lightningbeam-ui/lightningbeam-editor/src/panes/toolbar.rs @@ -4,6 +4,7 @@ /// Users can click to select tools, which updates the global selected_tool state. use eframe::egui; +use lightningbeam_core::layer::{AnyLayer, LayerType}; use lightningbeam_core::tool::{Tool, RegionSelectMode}; use super::{NodePath, PaneRenderer, SharedPaneState}; @@ -30,14 +31,28 @@ impl PaneRenderer for ToolbarPane { let button_padding = 8.0; let button_spacing = 4.0; + // Determine which tools to show based on the active layer type + let active_layer_type: Option = shared.active_layer_id + .and_then(|id| shared.action_executor.document().get_layer(&id)) + .map(|layer| match layer { + AnyLayer::Vector(_) => LayerType::Vector, + AnyLayer::Audio(_) => LayerType::Audio, + AnyLayer::Video(_) => LayerType::Video, + AnyLayer::Effect(_) => LayerType::Effect, + AnyLayer::Group(_) => LayerType::Group, + }); + + // Auto-switch to Select if the current tool isn't available for this layer type + let tools = Tool::for_layer_type(active_layer_type); + if !tools.contains(shared.selected_tool) { + *shared.selected_tool = Tool::Select; + } + // Calculate how many columns we can fit let available_width = rect.width() - (button_padding * 2.0); let columns = ((available_width + button_spacing) / (button_size + button_spacing)).floor() as usize; let columns = columns.max(1); // At least 1 column - - // Calculate total number of tools and rows - let tools = Tool::all(); let total_tools = tools.len(); let total_rows = (total_tools + columns - 1) / columns; @@ -177,7 +192,8 @@ impl PaneRenderer for ToolbarPane { y += button_size + button_spacing; } - // Add color pickers below the tool buttons + // Add color pickers below the tool buttons (vector layers only) + if matches!(active_layer_type, None | Some(LayerType::Vector)) { y += button_spacing * 2.0; // Extra spacing // Fill Color @@ -247,6 +263,7 @@ impl PaneRenderer for ToolbarPane { *shared.active_color_mode = super::ColorMode::Stroke; } }); + } // end color pickers (vector only) } fn name(&self) -> &str { diff --git a/src/assets/split.svg b/src/assets/split.svg new file mode 100644 index 0000000..cfd37e7 --- /dev/null +++ b/src/assets/split.svg @@ -0,0 +1,24 @@ + + + + + + + + + +