Add general-purpose functions for sizing in viewport units (#3833)

Marshall Bowers created

This PR adds general-purpose functions for obtaining a `Length` in
viewport units.

Previously in #3600 we had added specific variants of `w` and `h` that
took viewport units, but I think it makes more sense to just have a
primitive that can compose with any styling method that accepts a
`Length` or `Into<Length>`.

Release Notes:

- N/A

Change summary

crates/outline2/src/outline.rs                  |  6 +-----
crates/storybook2/src/stories/viewport_units.rs |  8 ++++----
crates/ui2/src/prelude.rs                       |  1 +
crates/ui2/src/styled_ext.rs                    | 14 --------------
crates/ui2/src/styles.rs                        |  2 ++
crates/ui2/src/styles/units.rs                  | 15 +++++++++++++++
6 files changed, 23 insertions(+), 23 deletions(-)

Detailed changes

crates/outline2/src/outline.rs 🔗

@@ -79,12 +79,8 @@ impl OutlineView {
         editor: View<Editor>,
         cx: &mut ViewContext<Self>,
     ) -> OutlineView {
-        const MAX_HEIGHT_IN_VH: f32 = 0.75;
-
         let delegate = OutlineViewDelegate::new(cx.view().downgrade(), outline, editor, cx);
-        let picker = cx.new_view(|cx| {
-            Picker::new(delegate, cx).max_height(cx.viewport_size().height * MAX_HEIGHT_IN_VH)
-        });
+        let picker = cx.new_view(|cx| Picker::new(delegate, cx).max_height(vh(0.75, cx)));
         OutlineView { picker }
     }
 }

crates/storybook2/src/stories/viewport_units.rs 🔗

@@ -13,16 +13,16 @@ impl Render for ViewportUnitsStory {
                 .flex_row()
                 .child(
                     div()
-                        .w_vw(0.5, cx)
-                        .h_vh(0.8, cx)
+                        .w(vw(0.5, cx))
+                        .h(vh(0.8, cx))
                         .bg(gpui::red())
                         .text_color(gpui::white())
                         .child("50vw, 80vh"),
                 )
                 .child(
                     div()
-                        .w_vw(0.25, cx)
-                        .h_vh(0.33, cx)
+                        .w(vw(0.25, cx))
+                        .h(vh(0.33, cx))
                         .bg(gpui::green())
                         .text_color(gpui::white())
                         .child("25vw, 33vh"),

crates/ui2/src/prelude.rs 🔗

@@ -9,6 +9,7 @@ pub use crate::clickable::*;
 pub use crate::disableable::*;
 pub use crate::fixed::*;
 pub use crate::selectable::*;
+pub use crate::styles::{vh, vw};
 pub use crate::visible_on_hover::*;
 pub use crate::{h_stack, v_stack};
 pub use crate::{Button, ButtonSize, ButtonStyle, IconButton};

crates/ui2/src/styled_ext.rs 🔗

@@ -16,20 +16,6 @@ fn elevated<E: Styled>(this: E, cx: &mut WindowContext, index: ElevationIndex) -
 
 /// Extends [`Styled`](gpui::Styled) with Zed specific styling methods.
 pub trait StyledExt: Styled + Sized {
-    /// Sets the width of the element as a percentage of the viewport's width.
-    ///
-    /// `percent` should be a value between `0.0` and `1.0`.
-    fn w_vw(self, percent: f32, cx: &mut WindowContext) -> Self {
-        self.w(cx.viewport_size().width * percent)
-    }
-
-    /// Sets the height of the element as a percentage of the viewport's height.
-    ///
-    /// `percent` should be a value between `0.0` and `1.0`.
-    fn h_vh(self, percent: f32, cx: &mut WindowContext) -> Self {
-        self.h(cx.viewport_size().height * percent)
-    }
-
     /// Horizontally stacks elements.
     ///
     /// Sets `flex()`, `flex_row()`, `items_center()`

crates/ui2/src/styles.rs 🔗

@@ -1,7 +1,9 @@
 mod color;
 mod elevation;
 mod typography;
+mod units;
 
 pub use color::*;
 pub use elevation::*;
 pub use typography::*;
+pub use units::*;

crates/ui2/src/styles/units.rs 🔗

@@ -0,0 +1,15 @@
+use gpui::{Length, WindowContext};
+
+/// Returns a [`Length`] corresponding to the specified percentage of the viewport's width.
+///
+/// `percent` should be a value between `0.0` and `1.0`.
+pub fn vw(percent: f32, cx: &mut WindowContext) -> Length {
+    Length::from(cx.viewport_size().width * percent)
+}
+
+/// Returns a [`Length`] corresponding to the specified percentage of the viewport's height.
+///
+/// `percent` should be a value between `0.0` and `1.0`.
+pub fn vh(percent: f32, cx: &mut WindowContext) -> Length {
+    Length::from(cx.viewport_size().height * percent)
+}