T19: the main window lets the desktop through while Background opacity is under 1, blurred or clear as Background blur says, set at open and as the settings change; Ely's new ColumnShell::glass grounds every column and the title bar in the palette's glass, which the opacity sets, and the Ely pin moves to it past 27 of Ely's own commits; dialogs stay solid; the terminal paints no second ground; shot names the window's AppKit views
This commit is contained in:
11 files changed
+137
-28
No files matched your search
+11
-3
@@ -10,6 +10,7 @@ use gpui::{
|
||||
#[cfg(target_os = "macos")]
|
||||
use crate::term::mac;
|
||||
use crate::{
|
||||
blur,
|
||||
settings::{self, SettingsStore},
|
||||
term::{ICONS, Launch, MONO, config, input, shell::ShellIntegration, spawn},
|
||||
themes,
|
||||
@@ -60,8 +61,10 @@ pub fn start(cx: &mut App) -> anyhow::Result<()> {
|
||||
mac::deliver_command_key_ups()?;
|
||||
}
|
||||
themes::apply(cx);
|
||||
let chosen =
|
||||
|settings: &settings::Settings| (settings.theme.clone(), settings.dark_theme.clone());
|
||||
let chosen = |settings: &settings::Settings| {
|
||||
let theme = (settings.theme.clone(), settings.dark_theme.clone());
|
||||
(theme, settings.background_opacity)
|
||||
};
|
||||
let mut worn = chosen(SettingsStore::get(cx));
|
||||
cx.observe_global::<SettingsStore>(move |cx| {
|
||||
let now = chosen(SettingsStore::get(cx));
|
||||
@@ -77,6 +80,7 @@ pub fn start(cx: &mut App) -> anyhow::Result<()> {
|
||||
/// Opens the main window running `launch`.
|
||||
pub fn open(launch: Launch, cx: &mut App) -> anyhow::Result<WindowHandle<Workspace>> {
|
||||
let bounds = Bounds::centered(None, size(px(1200.0), px(760.0)), cx);
|
||||
let background = blur::appearance(SettingsStore::get(cx));
|
||||
let options = WindowOptions {
|
||||
window_bounds: Some(WindowBounds::Windowed(bounds)),
|
||||
titlebar: Some(TitlebarOptions {
|
||||
@@ -86,6 +90,7 @@ pub fn open(launch: Launch, cx: &mut App) -> anyhow::Result<WindowHandle<Workspa
|
||||
}),
|
||||
// Ely's columns draw the controls; only Linux reads this, and must not draw its own.
|
||||
window_decorations: Some(WindowDecorations::Client),
|
||||
window_background: background,
|
||||
..Default::default()
|
||||
};
|
||||
let (pty, events) = spawn(&launch, (80, 24), (8, 16), config(SettingsStore::get(cx)))?;
|
||||
@@ -95,6 +100,9 @@ pub fn open(launch: Launch, cx: &mut App) -> anyhow::Result<WindowHandle<Workspa
|
||||
.detach();
|
||||
cx.new(|cx| Workspace::new(pty, events, launch, window, cx))
|
||||
})?;
|
||||
log::info!("app: main window open");
|
||||
log::info!(
|
||||
"app: main window open, blur: {background:?} on {}",
|
||||
std::env::consts::OS
|
||||
);
|
||||
Ok(window)
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
use gpui::{Window, WindowBackgroundAppearance};
|
||||
|
||||
use crate::settings::Settings;
|
||||
|
||||
/// What the window shows of the desktop: blurred or clear while the background lets it through.
|
||||
pub fn appearance(settings: &Settings) -> WindowBackgroundAppearance {
|
||||
if settings.background_opacity >= 1.0 {
|
||||
WindowBackgroundAppearance::Opaque
|
||||
} else if settings.background_blur {
|
||||
WindowBackgroundAppearance::Blurred
|
||||
} else {
|
||||
WindowBackgroundAppearance::Transparent
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets `window` to what the settings ask when it differs from `shown`; logs the way taken.
|
||||
pub fn follow(window: &Window, shown: &mut WindowBackgroundAppearance, settings: &Settings) {
|
||||
let wanted = appearance(settings);
|
||||
if wanted != *shown {
|
||||
*shown = wanted;
|
||||
window.set_background_appearance(wanted);
|
||||
log::info!("blur: the window is {wanted:?} on {}", std::env::consts::OS);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use gpui::WindowBackgroundAppearance::{Blurred, Opaque, Transparent};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn the_desktop_shows_only_through_a_background_it_can_pass() {
|
||||
let at = |opacity, blur| {
|
||||
appearance(&Settings {
|
||||
background_opacity: opacity,
|
||||
background_blur: blur,
|
||||
..Settings::default()
|
||||
})
|
||||
};
|
||||
assert_eq!(at(1.0, true), Opaque);
|
||||
assert_eq!(at(1.0, false), Opaque);
|
||||
assert_eq!(at(0.88, true), Blurred);
|
||||
assert_eq!(at(0.3, false), Transparent);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod app;
|
||||
pub mod blur;
|
||||
pub mod files;
|
||||
pub mod git;
|
||||
pub mod sessions;
|
||||
|
||||
+4
-1
@@ -357,7 +357,10 @@ impl Render for TerminalView {
|
||||
.size_full()
|
||||
.px(px(settings.padding_x))
|
||||
.py(px(settings.padding_y))
|
||||
.bg(ink.bg.alpha(settings.background_opacity));
|
||||
// The window's glass grounds the theme's background; a program's own paints over it.
|
||||
.when(ink.bg != theme.background, |root| {
|
||||
root.bg(ink.bg.alpha(settings.background_opacity))
|
||||
});
|
||||
let root = [MouseButton::Left, MouseButton::Middle, MouseButton::Right]
|
||||
.into_iter()
|
||||
.fold(root, |root, button| {
|
||||
|
||||
+17
-12
@@ -4,20 +4,23 @@ use gpui::App;
|
||||
use super::{TerminalTheme, active};
|
||||
use crate::settings::SettingsStore;
|
||||
|
||||
/// The chrome's palette for a terminal theme; none for Ely's own, which Ely draws.
|
||||
pub fn palette(theme: &TerminalTheme) -> Option<Palette> {
|
||||
if theme.ely {
|
||||
return None;
|
||||
}
|
||||
let (bg, fg, ansi) = (theme.background, theme.foreground, theme.ansi);
|
||||
/// The chrome's palette for a terminal theme, its glass as see-through as the background; Ely's own keep Ely's colors.
|
||||
pub fn palette(theme: &TerminalTheme, opacity: f32) -> Palette {
|
||||
let base = if theme.is_dark() {
|
||||
Palette::dark(false)
|
||||
} else {
|
||||
Palette::light(false)
|
||||
};
|
||||
if theme.ely {
|
||||
return Palette {
|
||||
glass: base.bg.alpha(opacity),
|
||||
..base
|
||||
};
|
||||
}
|
||||
let (bg, fg, ansi) = (theme.background, theme.foreground, theme.ansi);
|
||||
let tint = |share: f32| bg.mix(&fg, share);
|
||||
let wash = |color: gpui::Hsla| bg.mix(&color, 0.18);
|
||||
Some(Palette {
|
||||
Palette {
|
||||
bg,
|
||||
surface: bg,
|
||||
sunken: tint(0.03),
|
||||
@@ -44,7 +47,7 @@ pub fn palette(theme: &TerminalTheme) -> Option<Palette> {
|
||||
warning_subtle: wash(ansi[3]),
|
||||
danger_subtle: wash(ansi[1]),
|
||||
info_subtle: wash(ansi[4]),
|
||||
glass: bg.alpha(base.glass.a),
|
||||
glass: bg.alpha(opacity),
|
||||
tooltip_bg: tint(0.2),
|
||||
tooltip_fg: fg,
|
||||
chart: [
|
||||
@@ -67,18 +70,20 @@ pub fn palette(theme: &TerminalTheme) -> Option<Palette> {
|
||||
variable: fg,
|
||||
},
|
||||
..base
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Dresses the app in the theme the settings choose for the system's appearance.
|
||||
pub fn apply(cx: &mut App) {
|
||||
let theme = active(SettingsStore::get(cx), cx.window_appearance());
|
||||
let settings = SettingsStore::get(cx);
|
||||
let theme = active(settings, cx.window_appearance());
|
||||
let opacity = settings.background_opacity;
|
||||
let mode = if theme.is_dark() {
|
||||
Mode::Dark
|
||||
} else {
|
||||
Mode::Light
|
||||
};
|
||||
Theme::set_palette(mode, palette(theme), cx);
|
||||
Theme::set_palette(mode, Some(palette(theme, opacity)), cx);
|
||||
Theme::set_mode_now(mode, cx);
|
||||
log::info!("theme: {} in {mode:?}", theme.id);
|
||||
log::info!("theme: {} in {mode:?}, glass at {opacity}", theme.id);
|
||||
}
|
||||
+17
-3
@@ -114,11 +114,25 @@ fn the_dark_theme_wins_only_in_dark_mode() {
|
||||
#[test]
|
||||
fn the_chrome_wears_the_theme() {
|
||||
let dracula = find("dracula").expect("dracula");
|
||||
let chrome = palette(dracula).expect("a mapped palette");
|
||||
let chrome = palette(dracula, 1.0);
|
||||
assert_eq!(chrome.bg, dracula.background);
|
||||
assert_eq!(chrome.fg, dracula.foreground);
|
||||
assert_eq!(chrome.ansi, dracula.ansi);
|
||||
assert_eq!(chrome.danger, dracula.ansi[1]);
|
||||
assert!(chrome.glass.a < 1.0);
|
||||
assert!(palette(find("ely-dark").expect("ely")).is_none());
|
||||
let ely = palette(find("ely-dark").expect("ely"), 1.0);
|
||||
assert_eq!(ely.bg, Palette::dark(false).bg, "Ely's own colors");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_glass_lets_through_what_the_opacity_leaves() {
|
||||
for id in ["dracula", "ely-light"] {
|
||||
let theme = find(id).expect("a theme");
|
||||
let chrome = palette(theme, 0.4);
|
||||
assert_eq!(chrome.glass, chrome.bg.alpha(0.4), "{id}");
|
||||
assert_eq!(
|
||||
chrome.bg.a, 1.0,
|
||||
"{id}: the ground under dialogs stays solid"
|
||||
);
|
||||
assert_eq!(palette(theme, 1.0).glass, chrome.bg, "{id}");
|
||||
}
|
||||
}
|
||||
+11
-3
@@ -9,10 +9,12 @@ use ely_gpui_component::{
|
||||
use gpui::{
|
||||
Action, App, AppContext, Context, Entity, EntityId, FocusHandle, Focusable, InteractiveElement,
|
||||
IntoElement, KeyBinding, ParentElement, Render, SharedString, StatefulInteractiveElement,
|
||||
StyleRefinement, Styled, Subscription, Window, actions, div, prelude::FluentBuilder,
|
||||
StyleRefinement, Styled, Subscription, Window, WindowBackgroundAppearance, actions, div,
|
||||
prelude::FluentBuilder,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
blur,
|
||||
files::Files,
|
||||
git::panel::{Acted, GitPanel},
|
||||
sessions::{self, Session},
|
||||
@@ -84,6 +86,8 @@ pub struct Workspace {
|
||||
active: usize,
|
||||
files: Entity<Files>,
|
||||
git: Entity<GitPanel>,
|
||||
/// What the window shows of the desktop, as last set.
|
||||
background: WindowBackgroundAppearance,
|
||||
_settings: Subscription,
|
||||
_acted: Subscription,
|
||||
}
|
||||
@@ -109,7 +113,11 @@ impl Workspace {
|
||||
active: 0,
|
||||
files: cx.new(|_| Files::new(launch.cwd.clone())),
|
||||
git,
|
||||
_settings: cx.observe_global::<SettingsStore>(|_, cx| cx.notify()),
|
||||
background: blur::appearance(SettingsStore::get(cx)),
|
||||
_settings: cx.observe_global_in::<SettingsStore>(window, |this, window, cx| {
|
||||
blur::follow(window, &mut this.background, SettingsStore::get(cx));
|
||||
cx.notify();
|
||||
}),
|
||||
_acted: acted,
|
||||
};
|
||||
workspace.add(pty, events, launch, window, cx);
|
||||
@@ -316,7 +324,7 @@ impl Render for Workspace {
|
||||
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let settings = SettingsStore::get(cx);
|
||||
let width = cx.theme().sidebar_width(false);
|
||||
let mut shell = ColumnShell::new("workspace");
|
||||
let mut shell = ColumnShell::new("workspace").glass();
|
||||
if settings.show_sessions {
|
||||
let (workspace, home) = (cx.entity(), dirs::home_dir());
|
||||
let rows = self.sessions.iter().enumerate().map(|(index, session)| {
|
||||
|
||||
Reference in new issue
Block a user