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}