Scale UI elements in the editor based on the buffer_font_size
(#11817)
This PR adjusts how UI elements are rendered inside of full-size editors to scale with the configured `buffer_font_size`. This fixes some issues where UI elements (such as the `IconButton`s used for code action and task run indicators) would not scale as the `buffer_font_size` was changed. We achieve this by changing the rem size when rendering the `EditorElement`, with a rem size that is derived from the `buffer_font_size`. `WindowContext` now has a new `with_rem_size` method that can be used to render an element with a given rem size. Note that this can only be called during `request_layout`, `prepaint`, or `paint`, similar to `with_text_style` or `with_content_mask`. ### Before <img width="1264" alt="Screenshot 2024-05-14 at 2 15 39 PM" src="https://github.com/zed-industries/zed/assets/1486634/05ad7f8d-c62f-4baa-bffd-38cace7f3710"> <img width="1264" alt="Screenshot 2024-05-14 at 2 15 49 PM" src="https://github.com/zed-industries/zed/assets/1486634/254cd11c-3723-488f-ab3d-ed653169056c"> ### After <img width="1264" alt="Screenshot 2024-05-14 at 2 13 02 PM" src="https://github.com/zed-industries/zed/assets/1486634/c8dad309-62a4-444f-bfeb-a0009dc08c03"> <img width="1264" alt="Screenshot 2024-05-14 at 2 13 06 PM" src="https://github.com/zed-industries/zed/assets/1486634/4d9a3a52-9656-4768-b210-840b4884e381"> Note: This diff is best viewed with whitespace changes hidden: <img width="245" alt="Screenshot 2024-05-14 at 2 22 45 PM" src="https://github.com/zed-industries/zed/assets/1486634/7cb9829f-9c1b-4224-95be-82182017ed90"> Release Notes: - Changed UI elements within the editor to scale based on `buffer_font_size` (e.g., code action indicators, task run indicators, etc.).
This commit is contained in:
parent
c8ddde27e1
commit
5b8bb6237f
2 changed files with 560 additions and 479 deletions
|
@ -58,7 +58,7 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
use sum_tree::Bias;
|
||||
use theme::{ActiveTheme, PlayerColor};
|
||||
use theme::{ActiveTheme, PlayerColor, ThemeSettings};
|
||||
use ui::prelude::*;
|
||||
use ui::{h_flex, ButtonLike, ButtonStyle, ContextMenu, Tooltip};
|
||||
use util::ResultExt;
|
||||
|
@ -3705,6 +3705,38 @@ enum Invisible {
|
|||
Whitespace { line_offset: usize },
|
||||
}
|
||||
|
||||
impl EditorElement {
|
||||
/// Returns the rem size to use when rendering the [`EditorElement`].
|
||||
///
|
||||
/// This allows UI elements to scale based on the `buffer_font_size`.
|
||||
fn rem_size(&self, cx: &WindowContext) -> Option<Pixels> {
|
||||
match self.editor.read(cx).mode {
|
||||
EditorMode::Full => {
|
||||
let buffer_font_size = ThemeSettings::get_global(cx).buffer_font_size;
|
||||
let rem_size_scale = {
|
||||
// Our default UI font size is 14px on a 16px base scale.
|
||||
// This means the default UI font size is 0.875rems.
|
||||
let default_font_size_scale = 14. / ui::BASE_REM_SIZE_IN_PX;
|
||||
|
||||
// We then determine the delta between a single rem and the default font
|
||||
// size scale.
|
||||
let default_font_size_delta = 1. - default_font_size_scale;
|
||||
|
||||
// Finally, we add this delta to 1rem to get the scale factor that
|
||||
// should be used to scale up the UI.
|
||||
1. + default_font_size_delta
|
||||
};
|
||||
|
||||
Some(buffer_font_size * rem_size_scale)
|
||||
}
|
||||
// We currently use single-line and auto-height editors in UI contexts,
|
||||
// so we don't want to scale everything with the buffer font size, as it
|
||||
// ends up looking off.
|
||||
EditorMode::SingleLine | EditorMode::AutoHeight { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Element for EditorElement {
|
||||
type RequestLayoutState = ();
|
||||
type PrepaintState = EditorLayout;
|
||||
|
@ -3718,6 +3750,8 @@ impl Element for EditorElement {
|
|||
_: Option<&GlobalElementId>,
|
||||
cx: &mut WindowContext,
|
||||
) -> (gpui::LayoutId, ()) {
|
||||
let rem_size = self.rem_size(cx);
|
||||
cx.with_rem_size(rem_size, |cx| {
|
||||
self.editor.update(cx, |editor, cx| {
|
||||
editor.set_style(self.style.clone(), cx);
|
||||
|
||||
|
@ -3761,6 +3795,7 @@ impl Element for EditorElement {
|
|||
|
||||
(layout_id, ())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn prepaint(
|
||||
|
@ -3776,6 +3811,9 @@ impl Element for EditorElement {
|
|||
..Default::default()
|
||||
};
|
||||
cx.set_view_id(self.editor.entity_id());
|
||||
|
||||
let rem_size = self.rem_size(cx);
|
||||
cx.with_rem_size(rem_size, |cx| {
|
||||
cx.with_text_style(Some(text_style), |cx| {
|
||||
cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
|
||||
let mut snapshot = self.editor.update(cx, |editor, cx| editor.snapshot(cx));
|
||||
|
@ -3868,7 +3906,8 @@ impl Element for EditorElement {
|
|||
self.editor.update(cx, |editor, cx| {
|
||||
autoscroll_containing_element =
|
||||
editor.autoscroll_requested() || editor.has_pending_selection();
|
||||
autoscroll_horizontally = editor.autoscroll_vertically(bounds, line_height, cx);
|
||||
autoscroll_horizontally =
|
||||
editor.autoscroll_vertically(bounds, line_height, cx);
|
||||
snapshot = editor.snapshot(cx);
|
||||
});
|
||||
|
||||
|
@ -3954,7 +3993,8 @@ impl Element for EditorElement {
|
|||
}
|
||||
}
|
||||
|
||||
let longest_line_width = layout_line(snapshot.longest_row(), &snapshot, &style, cx)
|
||||
let longest_line_width =
|
||||
layout_line(snapshot.longest_row(), &snapshot, &style, cx)
|
||||
.unwrap()
|
||||
.width;
|
||||
let mut scroll_width =
|
||||
|
@ -4110,9 +4150,9 @@ impl Element for EditorElement {
|
|||
if gutter_settings.code_actions {
|
||||
let newest_selection_point =
|
||||
newest_selection_head.to_point(&snapshot.display_snapshot);
|
||||
let buffer = snapshot
|
||||
.buffer_snapshot
|
||||
.buffer_line_for_row(MultiBufferRow(newest_selection_point.row));
|
||||
let buffer = snapshot.buffer_snapshot.buffer_line_for_row(
|
||||
MultiBufferRow(newest_selection_point.row),
|
||||
);
|
||||
if let Some((buffer, range)) = buffer {
|
||||
let buffer_id = buffer.remote_id();
|
||||
let row = range.start.row;
|
||||
|
@ -4120,7 +4160,8 @@ impl Element for EditorElement {
|
|||
self.editor.read(cx).tasks.contains_key(&(buffer_id, row));
|
||||
|
||||
if !has_test_indicator {
|
||||
code_actions_indicator = self.layout_code_actions_indicator(
|
||||
code_actions_indicator = self
|
||||
.layout_code_actions_indicator(
|
||||
line_height,
|
||||
newest_selection_head,
|
||||
scroll_pixel_position,
|
||||
|
@ -4250,6 +4291,7 @@ impl Element for EditorElement {
|
|||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn paint(
|
||||
|
@ -4303,6 +4345,8 @@ impl Element for EditorElement {
|
|||
}
|
||||
}
|
||||
});
|
||||
let rem_size = self.rem_size(cx);
|
||||
cx.with_rem_size(rem_size, |cx| {
|
||||
cx.with_text_style(Some(text_style), |cx| {
|
||||
cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
|
||||
self.paint_mouse_listeners(layout, hovered_hunk, cx);
|
||||
|
@ -4323,6 +4367,7 @@ impl Element for EditorElement {
|
|||
self.paint_mouse_context_menu(layout, cx);
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -490,7 +490,15 @@ pub struct Window {
|
|||
display_id: DisplayId,
|
||||
sprite_atlas: Arc<dyn PlatformAtlas>,
|
||||
text_system: Arc<WindowTextSystem>,
|
||||
pub(crate) rem_size: Pixels,
|
||||
rem_size: Pixels,
|
||||
/// An override value for the window's rem size.
|
||||
///
|
||||
/// This is used by `with_rem_size` to allow rendering an element tree with
|
||||
/// a given rem size.
|
||||
///
|
||||
/// Note: Right now we only allow for a single override value at a time, but
|
||||
/// this could likely be changed to be a stack of rem sizes.
|
||||
rem_size_override: Option<Pixels>,
|
||||
pub(crate) viewport_size: Size<Pixels>,
|
||||
layout_engine: Option<TaffyLayoutEngine>,
|
||||
pub(crate) root_view: Option<AnyView>,
|
||||
|
@ -763,6 +771,7 @@ impl Window {
|
|||
sprite_atlas,
|
||||
text_system,
|
||||
rem_size: px(16.),
|
||||
rem_size_override: None,
|
||||
viewport_size: content_size,
|
||||
layout_engine: Some(TaffyLayoutEngine::new()),
|
||||
root_view: None,
|
||||
|
@ -1202,7 +1211,9 @@ impl<'a> WindowContext<'a> {
|
|||
/// The size of an em for the base font of the application. Adjusting this value allows the
|
||||
/// UI to scale, just like zooming a web page.
|
||||
pub fn rem_size(&self) -> Pixels {
|
||||
self.window.rem_size
|
||||
self.window
|
||||
.rem_size_override
|
||||
.unwrap_or(self.window.rem_size)
|
||||
}
|
||||
|
||||
/// Sets the size of an em for the base font of the application. Adjusting this value allows the
|
||||
|
@ -1211,6 +1222,31 @@ impl<'a> WindowContext<'a> {
|
|||
self.window.rem_size = rem_size.into();
|
||||
}
|
||||
|
||||
/// Executes the provided function with the specified rem size.
|
||||
///
|
||||
/// This method must only be called as part of element drawing.
|
||||
pub fn with_rem_size<F, R>(&mut self, rem_size: Option<impl Into<Pixels>>, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut Self) -> R,
|
||||
{
|
||||
debug_assert!(
|
||||
matches!(
|
||||
self.window.draw_phase,
|
||||
DrawPhase::Prepaint | DrawPhase::Paint
|
||||
),
|
||||
"this method can only be called during request_layout, prepaint, or paint"
|
||||
);
|
||||
|
||||
if let Some(rem_size) = rem_size {
|
||||
self.window.rem_size_override = Some(rem_size.into());
|
||||
let result = f(self);
|
||||
self.window.rem_size_override.take();
|
||||
result
|
||||
} else {
|
||||
f(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// The line height associated with the current text style.
|
||||
pub fn line_height(&self) -> Pixels {
|
||||
let rem_size = self.rem_size();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue