T33: the sessions and right columns resize by a drag on their border toward the terminal, 160 to 960 pixels, kept in the settings once a drag rests; Ely 5c2822c's resizable ShellColumn, whose handle occludes the header so the drag moves no window, and Ely 005faef's handle line, a filled hairline, since gpui paints a border no wider than half its box
This commit is contained in:
8 files changed
+111
-11
No files matched your search
@@ -75,6 +75,9 @@ pub struct Settings {
|
||||
pub show_sessions: bool,
|
||||
pub show_panel: bool,
|
||||
pub panel: PanelTab,
|
||||
/// The sessions and right columns' widths, in pixels, as their borders were dragged.
|
||||
pub sessions_width: f32,
|
||||
pub panel_width: f32,
|
||||
/// The main window's size, unmaximized, in pixels.
|
||||
pub window_width: f32,
|
||||
pub window_height: f32,
|
||||
@@ -103,6 +106,8 @@ impl Default for Settings {
|
||||
show_sessions: true,
|
||||
show_panel: true,
|
||||
panel: PanelTab::Git,
|
||||
sessions_width: 240.0,
|
||||
panel_width: 240.0,
|
||||
window_width: 1200.0,
|
||||
window_height: 760.0,
|
||||
}
|
||||
@@ -114,6 +119,7 @@ pub const LINE_HEIGHT: RangeInclusive<f32> = 1.0..=2.0;
|
||||
pub const OPACITY: RangeInclusive<f32> = 0.3..=1.0;
|
||||
pub const PADDING: RangeInclusive<f32> = 0.0..=64.0;
|
||||
pub const SCROLLBACK: RangeInclusive<u32> = 0..=100_000;
|
||||
pub const COLUMN: RangeInclusive<f32> = 160.0..=960.0;
|
||||
pub const WINDOW: RangeInclusive<f32> = 100.0..=16384.0;
|
||||
|
||||
impl Settings {
|
||||
@@ -125,6 +131,8 @@ impl Settings {
|
||||
within("padding_x", self.padding_x, &PADDING)?;
|
||||
within("padding_y", self.padding_y, &PADDING)?;
|
||||
within("scrollback", self.scrollback, &SCROLLBACK)?;
|
||||
within("sessions_width", self.sessions_width, &COLUMN)?;
|
||||
within("panel_width", self.panel_width, &COLUMN)?;
|
||||
within("window_width", self.window_width, &WINDOW)?;
|
||||
within("window_height", self.window_height, &WINDOW)?;
|
||||
for (field, id) in [
|
||||
@@ -242,6 +250,12 @@ mod tests {
|
||||
error.to_string(),
|
||||
"window_width is 50, outside 100 to 16384"
|
||||
);
|
||||
let settings = Settings {
|
||||
panel_width: 1000.0,
|
||||
..Settings::default()
|
||||
};
|
||||
let error = settings.validate().expect_err("too wide");
|
||||
assert_eq!(error.to_string(), "panel_width is 1000, outside 160 to 960");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
+10
-6
@@ -3,7 +3,7 @@ use ely_gpui_component::{
|
||||
lists::List,
|
||||
primitives::{FocusScope, IconName},
|
||||
shell::{ColumnShell, ResizeBorder, ShellColumn},
|
||||
theme::{ActiveTheme, ControlSize},
|
||||
theme::ControlSize,
|
||||
typography::Caption,
|
||||
};
|
||||
use gpui::{
|
||||
@@ -26,6 +26,10 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
mod widths;
|
||||
|
||||
use widths::{Dragged, Side};
|
||||
|
||||
actions!(
|
||||
elyterminal,
|
||||
[
|
||||
@@ -88,6 +92,8 @@ pub struct Workspace {
|
||||
git: Entity<GitPanel>,
|
||||
/// What the window shows of the desktop, and the blur behind it.
|
||||
background: Blur,
|
||||
/// Column widths a drag shows before the settings hold them.
|
||||
dragged: Dragged,
|
||||
_settings: Subscription,
|
||||
_acted: Subscription,
|
||||
}
|
||||
@@ -114,6 +120,7 @@ impl Workspace {
|
||||
files: cx.new(|_| Files::new(launch.cwd.clone())),
|
||||
git,
|
||||
background: Blur::new(window, SettingsStore::get(cx)),
|
||||
dragged: Dragged::default(),
|
||||
_settings: cx.observe_global_in::<SettingsStore>(window, |this, window, cx| {
|
||||
this.background.follow(window, SettingsStore::get(cx));
|
||||
cx.notify();
|
||||
@@ -339,7 +346,6 @@ impl Render for Workspace {
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
self.background.fit(window);
|
||||
let settings = SettingsStore::get(cx);
|
||||
let width = cx.theme().sidebar_width(false);
|
||||
let workspace = cx.entity();
|
||||
let tip =
|
||||
|shown: bool, what: &str| format!("{} {what}", if shown { "Hide" } else { "Show" });
|
||||
@@ -393,8 +399,7 @@ impl Render for Workspace {
|
||||
workspace.update(cx, |this, cx| this.new_session(window, cx))
|
||||
});
|
||||
shell = shell.column(
|
||||
ShellColumn::new("sessions")
|
||||
.width(width)
|
||||
self.side_column(Side::Sessions, cx)
|
||||
.leading(left)
|
||||
.action(new)
|
||||
.child(
|
||||
@@ -436,8 +441,7 @@ impl Render for Workspace {
|
||||
// Git's list draws every row, so terminal output must not redraw it.
|
||||
let fill = || StyleRefinement::default().size_full();
|
||||
shell = shell.column(terminal).column(
|
||||
ShellColumn::new("panel")
|
||||
.width(width)
|
||||
self.side_column(Side::Panel, cx)
|
||||
.action(end)
|
||||
// Below the title bar, clear of Windows' caption buttons.
|
||||
.child(div().flex().justify_center().px_2().pt_2().child(switch))
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use ely_gpui_component::shell::ShellColumn;
|
||||
use gpui::{Context, Pixels, Task, px};
|
||||
|
||||
use super::Workspace;
|
||||
use crate::settings::{COLUMN, SettingsStore};
|
||||
|
||||
/// How long a dragged border rests before its width is saved.
|
||||
const SETTLE: Duration = Duration::from_millis(500);
|
||||
|
||||
/// A side column, whose border toward the terminal drags its width.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(super) enum Side {
|
||||
Sessions,
|
||||
Panel,
|
||||
}
|
||||
|
||||
/// Widths a drag shows that the settings do not hold yet.
|
||||
#[derive(Default)]
|
||||
pub(super) struct Dragged {
|
||||
sessions: Option<f32>,
|
||||
panel: Option<f32>,
|
||||
saving: Option<Task<()>>,
|
||||
}
|
||||
|
||||
impl Workspace {
|
||||
/// Column `side`, as wide as it was dragged or saved.
|
||||
pub(super) fn side_column(&self, side: Side, cx: &Context<Self>) -> ShellColumn {
|
||||
let settings = SettingsStore::get(cx);
|
||||
let (id, dragged, saved) = match side {
|
||||
Side::Sessions => ("sessions", self.dragged.sessions, settings.sessions_width),
|
||||
Side::Panel => ("panel", self.dragged.panel, settings.panel_width),
|
||||
};
|
||||
let workspace = cx.entity();
|
||||
ShellColumn::new(id).resizable(
|
||||
px(dragged.unwrap_or(saved)),
|
||||
px(*COLUMN.start()),
|
||||
px(*COLUMN.end()),
|
||||
move |width, _, cx| workspace.update(cx, |this, cx| this.drag(side, width, cx)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Shows `width` at once and saves it once the drag rests.
|
||||
fn drag(&mut self, side: Side, width: Pixels, cx: &mut Context<Self>) {
|
||||
let width = f32::from(width).round();
|
||||
match side {
|
||||
Side::Sessions => self.dragged.sessions = Some(width),
|
||||
Side::Panel => self.dragged.panel = Some(width),
|
||||
}
|
||||
self.dragged.saving = Some(cx.spawn(async move |this, cx| {
|
||||
cx.background_executor().timer(SETTLE).await;
|
||||
if let Err(error) = this.update(cx, |this, cx| this.save(cx)) {
|
||||
log::error!("app: the columns' widths were not saved: {error:#}");
|
||||
}
|
||||
}));
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn save(&mut self, cx: &mut Context<Self>) {
|
||||
let (sessions, panel) = (self.dragged.sessions.take(), self.dragged.panel.take());
|
||||
let saved = SettingsStore::update(cx, |settings| {
|
||||
settings.sessions_width = sessions.unwrap_or(settings.sessions_width);
|
||||
settings.panel_width = panel.unwrap_or(settings.panel_width);
|
||||
});
|
||||
match saved {
|
||||
Ok(()) => {
|
||||
let settings = SettingsStore::get(cx);
|
||||
log::info!(
|
||||
"app: the sessions column is {} px wide, the right column {} px",
|
||||
settings.sessions_width,
|
||||
settings.panel_width
|
||||
);
|
||||
}
|
||||
// The columns go back to the saved widths.
|
||||
Err(error) => log::error!("app: the columns' widths are not kept: {error:#}"),
|
||||
}
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user