160 lines
5.8 KiB
Rust
160 lines
5.8 KiB
Rust
/// Pane system for the layout manager
|
|
///
|
|
/// Each pane has:
|
|
/// - An icon button (top-left) for pane type selection
|
|
/// - Optional header with controls (e.g., Timeline playback controls)
|
|
/// - Content area (main pane body)
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// Pane type enum matching the layout system
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub enum PaneType {
|
|
/// Main animation canvas
|
|
Stage,
|
|
/// Frame-based timeline (matches timelineV2 from JS, but just "timeline" in Rust)
|
|
#[serde(rename = "timelineV2")]
|
|
Timeline,
|
|
/// Tool selection bar
|
|
Toolbar,
|
|
/// Property/info panel
|
|
Infopanel,
|
|
/// Layer hierarchy
|
|
#[serde(rename = "outlineer")]
|
|
Outliner,
|
|
/// MIDI piano roll editor
|
|
PianoRoll,
|
|
/// Virtual piano keyboard for live MIDI input
|
|
VirtualPiano,
|
|
/// Node-based editor
|
|
NodeEditor,
|
|
/// Preset/asset browser
|
|
PresetBrowser,
|
|
/// Asset library for browsing clips
|
|
AssetLibrary,
|
|
/// Code editor for shaders and DSP scripts
|
|
#[serde(alias = "shaderEditor")]
|
|
ScriptEditor,
|
|
}
|
|
|
|
impl PaneType {
|
|
/// Get display name for the pane type
|
|
pub fn display_name(self) -> &'static str {
|
|
match self {
|
|
PaneType::Stage => "Stage",
|
|
PaneType::Timeline => "Timeline",
|
|
PaneType::Toolbar => "Toolbar",
|
|
PaneType::Infopanel => "Info Panel",
|
|
PaneType::Outliner => "Outliner",
|
|
PaneType::PianoRoll => "Piano Roll",
|
|
PaneType::VirtualPiano => "Virtual Piano",
|
|
PaneType::NodeEditor => "Node Editor",
|
|
PaneType::PresetBrowser => "Instrument Browser",
|
|
PaneType::AssetLibrary => "Asset Library",
|
|
PaneType::ScriptEditor => "Script Editor",
|
|
}
|
|
}
|
|
|
|
/// Get SVG icon file name for the pane type
|
|
/// Path is relative to ~/Dev/Lightningbeam-2/src/assets/
|
|
/// TODO: Move assets to lightningbeam-editor/assets/icons/ before release
|
|
pub fn icon_file(self) -> &'static str {
|
|
match self {
|
|
PaneType::Stage => "stage.svg",
|
|
PaneType::Timeline => "timeline.svg",
|
|
PaneType::Toolbar => "toolbar.svg",
|
|
PaneType::Infopanel => "infopanel.svg",
|
|
PaneType::Outliner => "stage.svg", // TODO: needs own icon
|
|
PaneType::PianoRoll => "piano-roll.svg",
|
|
PaneType::VirtualPiano => "piano.svg",
|
|
PaneType::NodeEditor => "node-editor.svg",
|
|
PaneType::PresetBrowser => "stage.svg", // TODO: needs own icon
|
|
PaneType::AssetLibrary => "stage.svg", // TODO: needs own icon
|
|
PaneType::ScriptEditor => "node-editor.svg", // TODO: needs own icon
|
|
}
|
|
}
|
|
|
|
/// Parse pane type from string name (case-insensitive)
|
|
/// Accepts both JS names (timelineV2) and Rust names (timeline)
|
|
pub fn from_name(name: &str) -> Option<Self> {
|
|
match name.to_lowercase().as_str() {
|
|
"stage" => Some(PaneType::Stage),
|
|
"timeline" | "timelinev2" => Some(PaneType::Timeline),
|
|
"toolbar" => Some(PaneType::Toolbar),
|
|
"infopanel" => Some(PaneType::Infopanel),
|
|
"outlineer" | "outliner" => Some(PaneType::Outliner),
|
|
"pianoroll" => Some(PaneType::PianoRoll),
|
|
"virtualpiano" => Some(PaneType::VirtualPiano),
|
|
"nodeeditor" => Some(PaneType::NodeEditor),
|
|
"presetbrowser" => Some(PaneType::PresetBrowser),
|
|
"assetlibrary" => Some(PaneType::AssetLibrary),
|
|
"shadereditor" | "scripteditor" => Some(PaneType::ScriptEditor),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
/// Get all available pane types
|
|
pub fn all() -> &'static [PaneType] {
|
|
&[
|
|
PaneType::Stage,
|
|
PaneType::Timeline,
|
|
PaneType::Toolbar,
|
|
PaneType::Infopanel,
|
|
PaneType::Outliner,
|
|
PaneType::NodeEditor,
|
|
PaneType::PianoRoll,
|
|
PaneType::VirtualPiano,
|
|
PaneType::PresetBrowser,
|
|
PaneType::AssetLibrary,
|
|
PaneType::ScriptEditor,
|
|
]
|
|
}
|
|
|
|
/// Get the string name for this pane type (used in JSON)
|
|
pub fn to_name(self) -> &'static str {
|
|
match self {
|
|
PaneType::Stage => "stage",
|
|
PaneType::Timeline => "timelineV2", // JSON uses timelineV2
|
|
PaneType::Toolbar => "toolbar",
|
|
PaneType::Infopanel => "infopanel",
|
|
PaneType::Outliner => "outlineer", // JSON uses outlineer
|
|
PaneType::PianoRoll => "pianoRoll",
|
|
PaneType::VirtualPiano => "virtualPiano",
|
|
PaneType::NodeEditor => "nodeEditor",
|
|
PaneType::PresetBrowser => "presetBrowser",
|
|
PaneType::AssetLibrary => "assetLibrary",
|
|
PaneType::ScriptEditor => "scriptEditor",
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_pane_type_from_name() {
|
|
assert_eq!(PaneType::from_name("stage"), Some(PaneType::Stage));
|
|
assert_eq!(PaneType::from_name("Stage"), Some(PaneType::Stage));
|
|
assert_eq!(PaneType::from_name("STAGE"), Some(PaneType::Stage));
|
|
// Accept both JS name (timelineV2) and Rust name (timeline)
|
|
assert_eq!(PaneType::from_name("timelineV2"), Some(PaneType::Timeline));
|
|
assert_eq!(PaneType::from_name("timeline"), Some(PaneType::Timeline));
|
|
assert_eq!(PaneType::from_name("invalid"), None);
|
|
}
|
|
|
|
#[test]
|
|
fn test_pane_type_display() {
|
|
assert_eq!(PaneType::Stage.display_name(), "Stage");
|
|
assert_eq!(PaneType::Timeline.display_name(), "Timeline");
|
|
}
|
|
|
|
#[test]
|
|
fn test_pane_type_icons() {
|
|
assert_eq!(PaneType::Stage.icon_file(), "stage.svg");
|
|
assert_eq!(PaneType::Timeline.icon_file(), "timeline.svg");
|
|
assert_eq!(PaneType::NodeEditor.icon_file(), "node-editor.svg");
|
|
}
|
|
}
|