diff --git a/assets/settings/default.json b/assets/settings/default.json index f88a8aa9c4..b377292ad6 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -604,11 +604,10 @@ "path": null, // How the image is fitted into the workspace bounds: "cover", "fill" or "contain". "fit": "cover", - // The opacity of the background image, between 0.0 (fully transparent) and 1.0 (fully opaque). - "opacity": 0.6, - // The opacity of the UI drawn on top of the image, between 0.0 (UI fully - // transparent, image fully visible) and 1.0 (opaque UI). - "ui_opacity": 1.0, + // The opacity of the editor and terminal surfaces drawn on top of the image, + // between 0.0 (surfaces fully transparent, image fully visible) and 1.0 + // (surfaces fully opaque, image hidden). + "opacity": 0.15, }, // Scrollbar related settings "scrollbar": { diff --git a/crates/settings_content/src/background_image.rs b/crates/settings_content/src/background_image.rs index 6109b5d021..10a116045f 100644 --- a/crates/settings_content/src/background_image.rs +++ b/crates/settings_content/src/background_image.rs @@ -34,17 +34,11 @@ pub struct BackgroundImageSettingsContent { /// Default: cover pub fit: Option, - /// The opacity of the background image, between 0.0 (fully transparent) - /// and 1.0 (fully opaque). + /// The opacity of the editor and terminal surfaces drawn on top of the + /// image, between 0.0 (surfaces fully transparent, image fully visible) + /// and 1.0 (surfaces fully opaque, image hidden). Lower values let the + /// image show through the code area; text and chrome stay unaffected. /// - /// Default: 0.6 + /// Default: 0.15 pub opacity: Option, - - /// The opacity applied to the UI elements drawn on top of the image, - /// between 0.0 (fully transparent UI, image fully visible) and 1.0 - /// (opaque UI, the default). Lower this to make the image show through - /// panels and editors. - /// - /// Default: 1.0 - pub ui_opacity: Option, } diff --git a/crates/settings_ui/src/page_data.rs b/crates/settings_ui/src/page_data.rs index afb56f052e..979cc6c9eb 100644 --- a/crates/settings_ui/src/page_data.rs +++ b/crates/settings_ui/src/page_data.rs @@ -1530,7 +1530,7 @@ fn appearance_page() -> SettingsPage { ] } - fn background_image_section() -> [SettingsPageItem; 5] { + fn background_image_section() -> [SettingsPageItem; 4] { [ SettingsPageItem::SectionHeader("Background Image"), SettingsPageItem::SettingItem(SettingItem { @@ -1573,7 +1573,7 @@ fn appearance_page() -> SettingsPage { }), SettingsPageItem::SettingItem(SettingItem { title: "Opacity", - description: "Opacity of the background image, between 0.0 (fully transparent) and 1.0 (fully opaque).", + description: "Opacity of the editor and terminal surfaces, between 0.0 (image fully visible) and 1.0 (image hidden).", field: Box::new(SettingField { organization_override: None, json_path: Some("background.opacity"), @@ -1590,25 +1590,6 @@ fn appearance_page() -> SettingsPage { metadata: None, files: USER, }), - SettingsPageItem::SettingItem(SettingItem { - title: "UI Opacity", - description: "Opacity of the UI drawn on top of the image, between 0.0 (image fully visible) and 1.0 (opaque UI).", - field: Box::new(SettingField { - organization_override: None, - json_path: Some("background.ui_opacity"), - pick: |settings_content| { - settings_content.background.as_ref()?.ui_opacity.as_ref() - }, - write: |settings_content, value, _| { - settings_content - .background - .get_or_insert_default() - .ui_opacity = value; - }, - }), - metadata: None, - files: USER, - }), ] } diff --git a/crates/theme_settings/src/settings.rs b/crates/theme_settings/src/settings.rs index d9a3270ef3..f6e4025f2d 100644 --- a/crates/theme_settings/src/settings.rs +++ b/crates/theme_settings/src/settings.rs @@ -183,7 +183,6 @@ impl ThemeSelection { }, } } - /// Returns the [ThemeMode] for the [ThemeSelection]. pub fn mode(&self) -> Option { match self { diff --git a/crates/theme_settings/src/theme_settings.rs b/crates/theme_settings/src/theme_settings.rs index f56a46b405..f021c53006 100644 --- a/crates/theme_settings/src/theme_settings.rs +++ b/crates/theme_settings/src/theme_settings.rs @@ -100,6 +100,7 @@ pub fn init(themes_to_load: LoadThemes, cx: &mut App) { settings.experimental_theme_overrides.clone(), settings.theme_overrides.clone(), ); + let mut prev_background = background_tint_input(cx); cx.observe_global::(move |cx| { let settings = ThemeSettings::get_global(cx); @@ -116,6 +117,7 @@ pub fn init(themes_to_load: LoadThemes, cx: &mut App) { settings.experimental_theme_overrides.clone(), settings.theme_overrides.clone(), ); + let background = background_tint_input(cx); if buffer_font_size_settings != prev_buffer_font_size_settings { prev_buffer_font_size_settings = buffer_font_size_settings; @@ -147,9 +149,13 @@ pub fn init(themes_to_load: LoadThemes, cx: &mut App) { reset_markdown_preview_font_size(cx); } - if theme_name != prev_theme_name || theme_overrides != prev_theme_overrides { + if theme_name != prev_theme_name + || theme_overrides != prev_theme_overrides + || background != prev_background + { prev_theme_name = theme_name; prev_theme_overrides = theme_overrides; + prev_background = background; reload_theme(cx); } @@ -161,6 +167,15 @@ pub fn init(themes_to_load: LoadThemes, cx: &mut App) { .detach(); } + +/// The parts of the background image settings that affect the theme tint. +fn background_tint_input(cx: &App) -> Option<(Option, Option)> { + let background = cx + .try_global::() + .and_then(|store| store.merged_settings().background.clone())?; + Some((background.path, background.opacity)) +} + fn configured_theme(cx: &mut App) -> Arc { let themes = ThemeRegistry::default_global(cx); let theme_settings = ThemeSettings::get_global(cx); @@ -179,7 +194,38 @@ fn configured_theme(cx: &mut App) -> Arc { .unwrap_or_else(|_| themes.get(DEFAULT_DARK_THEME).unwrap()) } }; - theme_settings.apply_theme_overrides(theme) + let theme = theme_settings.apply_theme_overrides(theme); + tint_for_background_image(theme, cx) +} + +/// Tints the editor and terminal surface colors to let the background image +/// show through. Only applies while a background image path is configured. +/// Text and chrome colors are left untouched so readability is preserved. +fn tint_for_background_image(theme: Arc, cx: &App) -> Arc { + let Some(background) = cx + .try_global::() + .and_then(|store| store.merged_settings().background.clone()) + else { + return theme; + }; + if background.path.is_none() { + return theme; + } + + let opacity = background.opacity.unwrap_or(0.15).clamp(0.0, 1.0); + if opacity >= 1.0 { + return theme; + } + + let mut theme = (*theme).clone(); + let colors = &mut theme.styles.colors; + colors.background.a *= opacity; + colors.editor_background.a *= opacity; + colors.editor_gutter_background.a *= opacity; + colors.editor_subheader_background.a *= opacity; + colors.terminal_background.a *= opacity; + colors.panel_background.a *= opacity; + Arc::new(theme) } fn configured_icon_theme(cx: &mut App) -> Arc { diff --git a/crates/workspace/src/background_image.rs b/crates/workspace/src/background_image.rs index caeb8fe51d..3833d79732 100644 --- a/crates/workspace/src/background_image.rs +++ b/crates/workspace/src/background_image.rs @@ -14,8 +14,9 @@ use image::Frame; use settings::{BackgroundImageFit, RegisterSetting, Settings, SettingsStore}; use smallvec::SmallVec; -/// Default opacity of the workspace background image. -pub const DEFAULT_BACKGROUND_IMAGE_OPACITY: f32 = 0.6; +/// Default opacity of the editor and terminal surfaces drawn on top of +/// the background image. Lower values let the image show through more. +pub const DEFAULT_BACKGROUND_IMAGE_OPACITY: f32 = 0.15; /// Maximum time to wait for the image file to become readable before falling /// back to the local cache. Bounds how long an unreachable path (e.g. a dead /// network mount) can delay the background image; the workspace itself never @@ -29,10 +30,10 @@ pub struct BackgroundImageSettings { pub path: Option>, /// How the image is fitted into the workspace bounds. pub fit: BackgroundImageFit, - /// The opacity of the image, between 0.0 and 1.0. + /// The opacity of the editor and terminal surfaces drawn on top of the + /// image, between 0.0 (surfaces fully transparent) and 1.0 (surfaces + /// fully opaque, image hidden). pub opacity: f32, - /// The opacity of the UI drawn on top of the image, between 0.0 and 1.0. - pub ui_opacity: f32, } impl Default for BackgroundImageSettings { @@ -41,7 +42,6 @@ impl Default for BackgroundImageSettings { path: None, fit: BackgroundImageFit::Cover, opacity: DEFAULT_BACKGROUND_IMAGE_OPACITY, - ui_opacity: 1.0, } } } @@ -62,10 +62,6 @@ impl Settings for BackgroundImageSettings { .opacity .map(|opacity| opacity.clamp(0.0, 1.0)) .unwrap_or(DEFAULT_BACKGROUND_IMAGE_OPACITY), - ui_opacity: background - .ui_opacity - .map(|opacity| opacity.clamp(0.0, 1.0)) - .unwrap_or(1.0), } } } @@ -169,8 +165,7 @@ impl Render for BackgroundImage { .size_full() .child( img(ImageSource::Render(image)) - .object_fit(object_fit) - .opacity(self.settings.opacity), + .object_fit(object_fit), ) .into_any_element() } @@ -351,7 +346,6 @@ mod tests { path: Some("~/background.png".to_string()), fit: Some(BackgroundImageFit::Contain), opacity: Some(0.25), - ui_opacity: None, }); }); }); diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index b1f4ce8d2e..1a97606067 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -9323,10 +9323,6 @@ impl Render for Workspace { workspace: &self.weak_self, }; - let background_settings = - background_image::BackgroundImageSettings::get_global(cx); - let ui_opacity = background_settings.ui_opacity; - let ui = div() .size_full() .flex() @@ -9337,7 +9333,6 @@ impl Render for Workspace { .items_start() .text_color(colors.text) .overflow_hidden() - .when(ui_opacity < 1.0, |div| div.opacity(ui_opacity)) // Expose the title bar as an ARIA toolbar so region navigation // (FocusNextPart) can reach the top bar's controls and assistive // technology announces it as a toolbar. The contained controls form