Skip to main content

beamer_core/
parameter_groups.rs

1//! Parameter grouping system for hierarchical organization.
2//!
3//! This module provides types for organizing parameters into groups (folders)
4//! in the DAW's parameter list. Groups form a tree structure that DAWs display
5//! hierarchically.
6//!
7//! # Terminology
8//!
9//! - **Group**: A named container for parameters (VST3 calls these "Units", AU calls them "Groups")
10//! - **Root Group**: The implicit top-level group (ID 0) containing ungrouped parameters
11//! - **Nested Group**: A group inside another group
12//!
13//! # Example
14//!
15//! ```ignore
16//! // Parameter group hierarchy:
17//! // Root (id=0)
18//! // ├── Filter (id=1)
19//! // │   ├── cutoff
20//! // │   └── resonance
21//! // └── Envelope (id=2)
22//! //     ├── attack
23//! //     └── release
24//! ```
25
26/// Parameter group ID type.
27///
28/// Groups are used to organize parameters into hierarchical groups in the DAW UI.
29/// Each group has a unique ID and can have a parent group.
30pub type GroupId = i32;
31
32/// Root group ID constant (parameters with no group).
33///
34/// The root group (ID 0) always exists and contains ungrouped parameters.
35pub const ROOT_GROUP_ID: GroupId = 0;
36
37/// Information about a parameter group.
38///
39/// Groups form a tree structure via parent_id references:
40/// - Root group (id=0, parent=0) always exists implicitly
41/// - Top-level groups have parent_id=0
42/// - Nested groups reference their parent's group_id
43#[derive(Debug, Clone)]
44pub struct GroupInfo {
45    /// Unique group identifier.
46    pub id: GroupId,
47    /// Display name shown in DAW (e.g., "Filter", "Amp Envelope").
48    pub name: &'static str,
49    /// Parent group ID (ROOT_GROUP_ID for top-level groups).
50    pub parent_id: GroupId,
51}
52
53impl GroupInfo {
54    /// Create a new group info.
55    pub const fn new(id: GroupId, name: &'static str, parent_id: GroupId) -> Self {
56        Self { id, name, parent_id }
57    }
58
59    /// Create the root group.
60    pub const fn root() -> Self {
61        Self {
62            id: ROOT_GROUP_ID,
63            name: "",
64            parent_id: ROOT_GROUP_ID,
65        }
66    }
67}
68
69/// Trait for querying parameter group hierarchy.
70///
71/// Implemented automatically by `#[derive(Parameters)]` when nested groups are present.
72/// Provides information about parameter groups for DAW display.
73///
74/// Group IDs are assigned dynamically at runtime to support deeply nested groups
75/// where the same nested struct type can appear in multiple contexts with
76/// different parent groups.
77pub trait ParameterGroups {
78    /// Total number of groups (including root).
79    ///
80    /// Returns 1 if there are no groups (just the root group).
81    /// For nested groups, this returns 1 + total nested groups (including deeply nested).
82    fn group_count(&self) -> usize {
83        1 // Default: only root group
84    }
85
86    /// Get group info by index.
87    ///
88    /// Index 0 always returns the root group.
89    /// Returns `GroupInfo` by value to support dynamic construction for nested groups.
90    fn group_info(&self, index: usize) -> Option<GroupInfo> {
91        if index == 0 {
92            Some(GroupInfo::root())
93        } else {
94            None
95        }
96    }
97
98    /// Find group ID by name (linear search).
99    fn find_group_by_name(&self, name: &str) -> Option<GroupId> {
100        for i in 0..self.group_count() {
101            if let Some(info) = self.group_info(i) {
102                if info.name == name {
103                    return Some(info.id);
104                }
105            }
106        }
107        None
108    }
109}