Let the sidebar divider be dragged

This commit is contained in:
Georg Bauer
2026-07-26 00:12:04 +02:00
parent 9bd648d77b
commit b182e7007c
6 changed files with 82 additions and 5 deletions

View File

@@ -25,7 +25,7 @@ use crate::settings::{
StreamingCacheBudget,
};
use iced::widget::{markdown, scrollable, text_input};
use iced::{Size, Subscription, Task, keyboard, window};
use iced::{Size, Subscription, Task, keyboard, mouse, window};
use rfd::AsyncFileDialog;
use std::collections::{HashMap, HashSet, VecDeque};
use std::fs;
@@ -38,6 +38,8 @@ use std::time::{Duration, Instant};
const APP_ID: &str = "de.rfc1437.ds4server";
const METRICS_SAMPLE_INTERVAL: Duration = Duration::from_millis(200);
pub(super) const MIN_SIDEBAR_WIDTH: i32 = 180;
pub(super) const MAX_SIDEBAR_WIDTH: i32 = 520;
pub(crate) struct App {
main_window: window::Id,
@@ -64,6 +66,8 @@ pub(crate) struct App {
session_rename: Option<(i32, String)>,
/// Projects whose archived sessions are expanded in the sidebar.
expanded_archives: HashSet<i32>,
/// True while the sidebar divider is being dragged.
sidebar_drag: bool,
choosing_folder: bool,
pending_project_path: Option<PathBuf>,
project_name_input: String,
@@ -194,6 +198,9 @@ pub(crate) enum Message {
ShowChat,
ShowStats,
ToggleSidebar,
StartSidebarDrag,
DragSidebar(f32),
EndSidebarDrag,
MetricsTick,
}
@@ -242,6 +249,7 @@ impl App {
session_menu: None,
session_rename: None,
expanded_archives: HashSet::new(),
sidebar_drag: false,
choosing_folder: false,
pending_project_path: None,
project_name_input: String::new(),
@@ -323,6 +331,7 @@ impl App {
session_menu: None,
session_rename: None,
expanded_archives: HashSet::new(),
sidebar_drag: false,
choosing_folder: false,
pending_project_path: None,
project_name_input: String::new(),
@@ -414,6 +423,26 @@ impl App {
}
Message::ShowChat => self.detail_tab = DetailTab::Chat,
Message::ShowStats => self.detail_tab = DetailTab::Stats,
// The sidebar starts at the window's left edge, so the cursor's x is
// the width the user is asking for. Only the final width is stored.
Message::StartSidebarDrag => self.sidebar_drag = true,
Message::DragSidebar(x) => {
if self.sidebar_drag {
self.preferences.sidebar_width =
(x.round() as i32).clamp(MIN_SIDEBAR_WIDTH, MAX_SIDEBAR_WIDTH);
}
}
Message::EndSidebarDrag => {
if self.sidebar_drag {
self.sidebar_drag = false;
if let Some(database) = self.database.as_mut()
&& let Err(error) =
database.set_sidebar_width(self.preferences.sidebar_width)
{
self.error = Some(error);
}
}
}
Message::ToggleSidebar => {
let collapsed = !self.preferences.sidebar_collapsed;
self.preferences.sidebar_collapsed = collapsed;
@@ -969,6 +998,19 @@ impl App {
iced::time::every(Duration::from_millis(50)).map(|_| Message::GenerationTick),
);
}
// The cursor leaves the thin divider as soon as it moves, so the drag is
// followed through raw window events instead of the widget.
if self.sidebar_drag {
subscriptions.push(iced::event::listen_with(|event, _, _| match event {
iced::Event::Mouse(mouse::Event::CursorMoved { position }) => {
Some(Message::DragSidebar(position.x))
}
iced::Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) => {
Some(Message::EndSidebarDrag)
}
_ => None,
}));
}
Subscription::batch(subscriptions)
}