Make tools dependent on layer type

This commit is contained in:
Skyler Lehmkuhl 2026-03-01 11:21:49 -05:00
parent c60eef0c5a
commit 4b638b882f
5 changed files with 65 additions and 6 deletions

View File

@ -35,6 +35,8 @@ pub enum Tool {
Text, Text,
/// Region select tool - select sub-regions of shapes by clipping /// Region select tool - select sub-regions of shapes by clipping
RegionSelect, RegionSelect,
/// Split tool - split audio/video clips at a point
Split,
} }
/// Region select mode /// Region select mode
@ -210,6 +212,7 @@ impl Tool {
Tool::BezierEdit => "Bezier Edit", Tool::BezierEdit => "Bezier Edit",
Tool::Text => "Text", Tool::Text => "Text",
Tool::RegionSelect => "Region Select", Tool::RegionSelect => "Region Select",
Tool::Split => "Split",
} }
} }
@ -228,10 +231,11 @@ impl Tool {
Tool::BezierEdit => "bezier_edit.svg", Tool::BezierEdit => "bezier_edit.svg",
Tool::Text => "text.svg", Tool::Text => "text.svg",
Tool::RegionSelect => "region_select.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] { pub fn all() -> &'static [Tool] {
&[ &[
Tool::Select, 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<crate::layer::LayerType>) -> &'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 /// Get keyboard shortcut hint
pub fn shortcut_hint(self) -> &'static str { pub fn shortcut_hint(self) -> &'static str {
match self { match self {
@ -264,6 +278,7 @@ impl Tool {
Tool::BezierEdit => "A", Tool::BezierEdit => "A",
Tool::Text => "T", Tool::Text => "T",
Tool::RegionSelect => "S", Tool::RegionSelect => "S",
Tool::Split => "C",
} }
} }
} }

View File

@ -44,6 +44,7 @@ impl CustomCursor {
Tool::BezierEdit => CustomCursor::BezierEdit, Tool::BezierEdit => CustomCursor::BezierEdit,
Tool::Text => CustomCursor::Text, Tool::Text => CustomCursor::Text,
Tool::RegionSelect => CustomCursor::Select, // Reuse select cursor for now Tool::RegionSelect => CustomCursor::Select, // Reuse select cursor for now
Tool::Split => CustomCursor::Select, // Reuse select cursor for now
} }
} }

View File

@ -320,6 +320,7 @@ mod tool_icons {
pub static POLYGON: &[u8] = include_bytes!("../../../src/assets/polygon.svg"); pub static POLYGON: &[u8] = include_bytes!("../../../src/assets/polygon.svg");
pub static BEZIER_EDIT: &[u8] = include_bytes!("../../../src/assets/bezier_edit.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 TEXT: &[u8] = include_bytes!("../../../src/assets/text.svg");
pub static SPLIT: &[u8] = include_bytes!("../../../src/assets/split.svg");
} }
/// Embedded focus icon SVGs /// Embedded focus icon SVGs
@ -387,6 +388,7 @@ impl ToolIconCache {
Tool::BezierEdit => tool_icons::BEZIER_EDIT, Tool::BezierEdit => tool_icons::BEZIER_EDIT,
Tool::Text => tool_icons::TEXT, Tool::Text => tool_icons::TEXT,
Tool::RegionSelect => tool_icons::SELECT, // Reuse select icon for now 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) { if let Some(texture) = rasterize_svg(svg_data, tool.icon_file(), 180, ctx) {
self.icons.insert(tool, texture); self.icons.insert(tool, texture);
@ -6016,7 +6018,7 @@ fn render_pane(
} }
// Icon // 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(); let icon_texture_id = icon.id();
ui.painter().image( ui.painter().image(
icon_texture_id, icon_texture_id,

View File

@ -4,6 +4,7 @@
/// Users can click to select tools, which updates the global selected_tool state. /// Users can click to select tools, which updates the global selected_tool state.
use eframe::egui; use eframe::egui;
use lightningbeam_core::layer::{AnyLayer, LayerType};
use lightningbeam_core::tool::{Tool, RegionSelectMode}; use lightningbeam_core::tool::{Tool, RegionSelectMode};
use super::{NodePath, PaneRenderer, SharedPaneState}; use super::{NodePath, PaneRenderer, SharedPaneState};
@ -30,14 +31,28 @@ impl PaneRenderer for ToolbarPane {
let button_padding = 8.0; let button_padding = 8.0;
let button_spacing = 4.0; let button_spacing = 4.0;
// Determine which tools to show based on the active layer type
let active_layer_type: Option<LayerType> = 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 // Calculate how many columns we can fit
let available_width = rect.width() - (button_padding * 2.0); let available_width = rect.width() - (button_padding * 2.0);
let columns = let columns =
((available_width + button_spacing) / (button_size + button_spacing)).floor() as usize; ((available_width + button_spacing) / (button_size + button_spacing)).floor() as usize;
let columns = columns.max(1); // At least 1 column 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_tools = tools.len();
let total_rows = (total_tools + columns - 1) / columns; let total_rows = (total_tools + columns - 1) / columns;
@ -177,7 +192,8 @@ impl PaneRenderer for ToolbarPane {
y += button_size + button_spacing; 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 y += button_spacing * 2.0; // Extra spacing
// Fill Color // Fill Color
@ -247,6 +263,7 @@ impl PaneRenderer for ToolbarPane {
*shared.active_color_mode = super::ColorMode::Stroke; *shared.active_color_mode = super::ColorMode::Stroke;
} }
}); });
} // end color pickers (vector only)
} }
fn name(&self) -> &str { fn name(&self) -> &str {

24
src/assets/split.svg Normal file
View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="24"
height="24"
viewBox="0 0 24 24"
version="1.1"
xmlns="http://www.w3.org/2000/svg">
<g>
<rect
style="fill:none;stroke:none"
width="24"
height="24"
x="0"
y="0" />
<!-- Vertical split line -->
<line
style="fill:none;stroke:#bfbfbf;stroke-width:2;stroke-linecap:round;stroke-dasharray:2,2"
x1="12" y1="2" x2="12" y2="22" />
<!-- Blade pointing right -->
<polygon
style="fill:#bfbfbf;stroke:none"
points="8,10 14,12 8,14" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 604 B