feat(ui): draggable, persisted dividers between room panels
Add a reusable Divider canvas widget and place two in the room screen: a vertical divider between the Participants and Controls panels (drag to resize the Participants width) and a horizontal divider between the main row and the Chat dock (drag to resize the dock height). The Participants panel and Chat dock size from persisted config values; the Controls panel and main row fill the rest. The widget reports drag motion as a pixel delta along its axis (mirroring the GateMeter drag handling, so a drag continues past the thin strip). update() applies the delta and clamps it: clamp_participants_width / clamp_chat_height keep both sides of each divider above a minimum. Sizes are re-clamped on window resize (window size tracked from window::Event::Resized) and clamped again on load (a size saved under a different window could be out of range). Persistence: participants_width / chat_height are new serde-default AppConfig fields; the divider publishes PersistConfig on drag release so the final position is written once (not per pixel). 3 clamp unit tests (incl. a tiny-window degenerate case) + config backward-compat assertions for the new fields. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -44,6 +44,14 @@ fn default_volume() -> f32 {
|
||||
1.0
|
||||
}
|
||||
|
||||
fn default_participants_width() -> f32 {
|
||||
540.0
|
||||
}
|
||||
|
||||
fn default_chat_height() -> f32 {
|
||||
180.0
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct AppConfig {
|
||||
pub input_device: String,
|
||||
@@ -63,6 +71,12 @@ pub struct AppConfig {
|
||||
pub echo_cancellation_enabled: bool,
|
||||
#[serde(default = "default_true")]
|
||||
pub notifications_enabled: bool,
|
||||
/// Persisted room-screen divider positions (px): Participants panel width and
|
||||
/// Chat dock height. Re-clamped to the window on load and on resize.
|
||||
#[serde(default = "default_participants_width")]
|
||||
pub participants_width: f32,
|
||||
#[serde(default = "default_chat_height")]
|
||||
pub chat_height: f32,
|
||||
#[serde(default)]
|
||||
pub custom_sound_self_join: Option<String>,
|
||||
#[serde(default)]
|
||||
@@ -92,6 +106,8 @@ impl Default for AppConfig {
|
||||
network_mode: NetworkMode::default(),
|
||||
echo_cancellation_enabled: false,
|
||||
notifications_enabled: true,
|
||||
participants_width: default_participants_width(),
|
||||
chat_height: default_chat_height(),
|
||||
custom_sound_self_join: None,
|
||||
custom_sound_peer_join: None,
|
||||
custom_sound_peer_leave: None,
|
||||
@@ -157,6 +173,9 @@ mod tests {
|
||||
// Configs predating the volume sliders must load at unity gain.
|
||||
assert_eq!(deserialized.input_volume, 1.0);
|
||||
assert_eq!(deserialized.output_volume, 1.0);
|
||||
// Configs predating the draggable dividers must load the default sizes.
|
||||
assert_eq!(deserialized.participants_width, 540.0);
|
||||
assert_eq!(deserialized.chat_height, 180.0);
|
||||
assert!(deserialized.custom_sound_self_join.is_none());
|
||||
assert!(deserialized.custom_sound_peer_join.is_none());
|
||||
assert!(deserialized.custom_sound_peer_leave.is_none());
|
||||
|
||||
Reference in New Issue
Block a user