Encode rem values derived from pixels using rems_from_px (#9367)

This PR adds a new `rems_from_px` helper function that can be used to
compute rem values based on a pixel value.

This is something we do fairly commonly, where we want to express a size
that is a given pixel size at the base rem size (e.g., "14px when the
rem size is 16px").

`rems_from_px` helps make the intent more explicit, as well as prevent
the base rem size from being duplicated everywhere.

Note: Ideally we would want `rems_from_px` to be `const`, but that
depends on https://github.com/rust-lang/rust/issues/57241.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2024-03-14 16:39:55 -04:00 committed by GitHub
parent a78576a6db
commit 404adbce5b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 54 additions and 35 deletions

View File

@ -86,7 +86,7 @@ impl Render for Breadcrumbs {
), ),
None => element None => element
// Match the height of the `ButtonLike` in the other arm. // Match the height of the `ButtonLike` in the other arm.
.h(rems(22. / 16.)) .h(rems_from_px(22.))
.child(breadcrumbs_stack), .child(breadcrumbs_stack),
} }
} }

View File

@ -174,7 +174,7 @@ impl Render for ChannelModal {
.child( .child(
h_flex() h_flex()
.w_full() .w_full()
.h(rems(22. / 16.)) .h(rems_from_px(22.))
.justify_between() .justify_between()
.line_height(rems(1.25)) .line_height(rems(1.25))
.child(CheckboxWithLabel::new( .child(CheckboxWithLabel::new(

View File

@ -521,7 +521,7 @@ impl ExtensionsPage {
.gap_2() .gap_2()
.border_1() .border_1()
.border_color(editor_border) .border_color(editor_border)
.min_w(rems(384. / 16.)) .min_w(rems_from_px(384.))
.rounded_lg() .rounded_lg()
.child(Icon::new(IconName::MagnifyingGlass)) .child(Icon::new(IconName::MagnifyingGlass))
.child(self.render_text_input(&self.query_editor, cx)), .child(self.render_text_input(&self.query_editor, cx)),

View File

@ -37,8 +37,8 @@ impl RenderOnce for AvatarAudioStatusIndicator {
div() div()
.absolute() .absolute()
.bottom(rems(-3. / 16.)) .bottom(rems_from_px(-3.))
.right(rems(-6. / 16.)) .right(rems_from_px(-6.))
.w(width_in_px + padding_x) .w(width_in_px + padding_x)
.h(icon_size.rems()) .h(icon_size.rems())
.child( .child(

View File

@ -1,5 +1,5 @@
use gpui::{relative, DefiniteLength, MouseButton}; use gpui::{relative, DefiniteLength, MouseButton};
use gpui::{rems, transparent_black, AnyElement, AnyView, ClickEvent, Hsla, Rems}; use gpui::{transparent_black, AnyElement, AnyView, ClickEvent, Hsla, Rems};
use smallvec::SmallVec; use smallvec::SmallVec;
use crate::prelude::*; use crate::prelude::*;
@ -278,10 +278,10 @@ pub enum ButtonSize {
impl ButtonSize { impl ButtonSize {
fn height(self) -> Rems { fn height(self) -> Rems {
match self { match self {
ButtonSize::Large => rems(32. / 16.), ButtonSize::Large => rems_from_px(32.),
ButtonSize::Default => rems(22. / 16.), ButtonSize::Default => rems_from_px(22.),
ButtonSize::Compact => rems(18. / 16.), ButtonSize::Compact => rems_from_px(18.),
ButtonSize::None => rems(16. / 16.), ButtonSize::None => rems_from_px(16.),
} }
} }
} }

View File

@ -1,4 +1,4 @@
use gpui::{rems, svg, IntoElement, Rems}; use gpui::{svg, IntoElement, Rems};
use strum::EnumIter; use strum::EnumIter;
use crate::prelude::*; use crate::prelude::*;
@ -15,10 +15,10 @@ pub enum IconSize {
impl IconSize { impl IconSize {
pub fn rems(self) -> Rems { pub fn rems(self) -> Rems {
match self { match self {
IconSize::Indicator => rems(10. / 16.), IconSize::Indicator => rems_from_px(10.),
IconSize::XSmall => rems(12. / 16.), IconSize::XSmall => rems_from_px(12.),
IconSize::Small => rems(14. / 16.), IconSize::Small => rems_from_px(14.),
IconSize::Medium => rems(16. / 16.), IconSize::Medium => rems_from_px(16.),
} }
} }
} }

View File

@ -1,5 +1,5 @@
use crate::{h_flex, prelude::*, Icon, IconName, IconSize}; use crate::{h_flex, prelude::*, Icon, IconName, IconSize};
use gpui::{relative, rems, Action, FocusHandle, IntoElement, Keystroke}; use gpui::{relative, Action, FocusHandle, IntoElement, Keystroke};
/// The way a [`KeyBinding`] should be displayed. /// The way a [`KeyBinding`] should be displayed.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
@ -158,12 +158,15 @@ impl RenderOnce for Key {
.py_0() .py_0()
.map(|this| { .map(|this| {
if single_char { if single_char {
this.w(rems(14. / 16.)).flex().flex_none().justify_center() this.w(rems_from_px(14.))
.flex()
.flex_none()
.justify_center()
} else { } else {
this.px_0p5() this.px_0p5()
} }
}) })
.h(rems(14. / 16.)) .h(rems_from_px(14.))
.text_ui() .text_ui()
.line_height(relative(1.)) .line_height(relative(1.))
.text_color(cx.theme().colors().text_muted) .text_color(cx.theme().colors().text_muted)
@ -184,7 +187,7 @@ pub struct KeyIcon {
impl RenderOnce for KeyIcon { impl RenderOnce for KeyIcon {
fn render(self, _cx: &mut WindowContext) -> impl IntoElement { fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
div().w(rems(14. / 16.)).child( div().w(rems_from_px(14.)).child(
Icon::new(self.icon) Icon::new(self.icon)
.size(IconSize::Small) .size(IconSize::Small)
.color(Color::Muted), .color(Color::Muted),

View File

@ -1,13 +1,13 @@
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use gpui::{ use gpui::{
div, overlay, point, prelude::FluentBuilder, px, rems, AnchorCorner, AnyElement, Bounds, div, overlay, point, prelude::FluentBuilder, px, AnchorCorner, AnyElement, Bounds,
DismissEvent, DispatchPhase, Element, ElementContext, ElementId, HitboxId, InteractiveElement, DismissEvent, DispatchPhase, Element, ElementContext, ElementId, HitboxId, InteractiveElement,
IntoElement, LayoutId, ManagedView, MouseDownEvent, ParentElement, Pixels, Point, View, IntoElement, LayoutId, ManagedView, MouseDownEvent, ParentElement, Pixels, Point, View,
VisualContext, WindowContext, VisualContext, WindowContext,
}; };
use crate::{Clickable, Selectable}; use crate::prelude::*;
pub trait PopoverTrigger: IntoElement + Clickable + Selectable + 'static {} pub trait PopoverTrigger: IntoElement + Clickable + Selectable + 'static {}
@ -102,7 +102,7 @@ impl<M: ManagedView> PopoverMenu<M> {
fn resolved_offset(&self, cx: &WindowContext) -> Point<Pixels> { fn resolved_offset(&self, cx: &WindowContext) -> Point<Pixels> {
self.offset.unwrap_or_else(|| { self.offset.unwrap_or_else(|| {
// Default offset = 4px padding + 1px border // Default offset = 4px padding + 1px border
let offset = rems(5. / 16.) * cx.rem_size(); let offset = rems_from_px(5.) * cx.rem_size();
match self.anchor { match self.anchor {
AnchorCorner::TopRight | AnchorCorner::BottomRight => point(offset, px(0.)), AnchorCorner::TopRight | AnchorCorner::BottomRight => point(offset, px(0.)),
AnchorCorner::TopLeft | AnchorCorner::BottomLeft => point(-offset, px(0.)), AnchorCorner::TopLeft | AnchorCorner::BottomLeft => point(-offset, px(0.)),

View File

@ -1,7 +1,9 @@
use crate::prelude::*; use std::cmp::Ordering;
use gpui::{AnyElement, IntoElement, Stateful}; use gpui::{AnyElement, IntoElement, Stateful};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::cmp::Ordering;
use crate::{prelude::*, BASE_REM_SIZE_IN_PX};
/// The position of a [`Tab`] within a list of tabs. /// The position of a [`Tab`] within a list of tabs.
#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
@ -51,9 +53,9 @@ impl Tab {
} }
} }
pub const CONTAINER_HEIGHT_IN_REMS: f32 = 29. / 16.; pub const CONTAINER_HEIGHT_IN_REMS: f32 = 29. / BASE_REM_SIZE_IN_PX;
const CONTENT_HEIGHT_IN_REMS: f32 = 28. / 16.; const CONTENT_HEIGHT_IN_REMS: f32 = 28. / BASE_REM_SIZE_IN_PX;
pub fn position(mut self, position: TabPosition) -> Self { pub fn position(mut self, position: TabPosition) -> Self {
self.position = position; self.position = position;

View File

@ -90,15 +90,13 @@ impl ParentElement for TabBar {
impl RenderOnce for TabBar { impl RenderOnce for TabBar {
fn render(self, cx: &mut WindowContext) -> impl IntoElement { fn render(self, cx: &mut WindowContext) -> impl IntoElement {
const HEIGHT_IN_REMS: f32 = 29. / 16.;
div() div()
.id(self.id) .id(self.id)
.group("tab_bar") .group("tab_bar")
.flex() .flex()
.flex_none() .flex_none()
.w_full() .w_full()
.h(rems(HEIGHT_IN_REMS)) .h(rems_from_px(29.))
.bg(cx.theme().colors().tab_bar_background) .bg(cx.theme().colors().tab_bar_background)
.when(!self.start_children.is_empty(), |this| { .when(!self.start_children.is_empty(), |this| {
this.child( this.child(

View File

@ -11,7 +11,7 @@ pub use crate::clickable::*;
pub use crate::disableable::*; pub use crate::disableable::*;
pub use crate::fixed::*; pub use crate::fixed::*;
pub use crate::selectable::*; pub use crate::selectable::*;
pub use crate::styles::{vh, vw}; pub use crate::styles::{rems_from_px, vh, vw};
pub use crate::visible_on_hover::*; pub use crate::visible_on_hover::*;
pub use crate::{h_flex, v_flex}; pub use crate::{h_flex, v_flex};
pub use crate::{Button, ButtonSize, ButtonStyle, IconButton, SelectableButton}; pub use crate::{Button, ButtonSize, ButtonStyle, IconButton, SelectableButton};

View File

@ -4,6 +4,8 @@ use gpui::{
use settings::Settings; use settings::Settings;
use theme::{ActiveTheme, ThemeSettings}; use theme::{ActiveTheme, ThemeSettings};
use crate::rems_from_px;
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub enum UiTextSize { pub enum UiTextSize {
/// The default size for UI text. /// The default size for UI text.
@ -38,10 +40,10 @@ pub enum UiTextSize {
impl UiTextSize { impl UiTextSize {
pub fn rems(self) -> Rems { pub fn rems(self) -> Rems {
match self { match self {
Self::Large => rems(16. / 16.), Self::Large => rems_from_px(16.),
Self::Default => rems(14. / 16.), Self::Default => rems_from_px(14.),
Self::Small => rems(12. / 16.), Self::Small => rems_from_px(12.),
Self::XSmall => rems(10. / 16.), Self::XSmall => rems_from_px(10.),
} }
} }
} }

View File

@ -1,4 +1,18 @@
use gpui::{Length, WindowContext}; use gpui::{rems, Length, Rems, WindowContext};
/// The base size of a rem, in pixels.
pub(crate) const BASE_REM_SIZE_IN_PX: f32 = 16.;
/// Returns a rem value derived from the provided pixel value and the base rem size (16px).
///
/// This can be used to compute rem values relative to pixel sizes, without
/// needing to hard-code the rem value.
///
/// For instance, instead of writing `rems(0.875)` you can write `rems_from_px(14.)`
#[inline(always)]
pub fn rems_from_px(px: f32) -> Rems {
rems(px / BASE_REM_SIZE_IN_PX)
}
/// Returns a [`Length`] corresponding to the specified percentage of the viewport's width. /// Returns a [`Length`] corresponding to the specified percentage of the viewport's width.
/// ///