Detailed changes
@@ -45,6 +45,7 @@ fn generate_shader_bindings() -> PathBuf {
"Pixels".into(),
"PointF".into(),
"Hsla".into(),
+ "ScaledContentMask".into(),
"Uniforms".into(),
"AtlasTile".into(),
"Quad".into(),
@@ -58,12 +59,14 @@ fn generate_shader_bindings() -> PathBuf {
.with_src(crate_dir.join("src/scene.rs"))
.with_src(crate_dir.join("src/geometry.rs"))
.with_src(crate_dir.join("src/color.rs"))
+ .with_src(crate_dir.join("src/window.rs"))
.with_src(crate_dir.join("src/platform.rs"))
.with_src(crate_dir.join("src/platform/mac/metal_renderer.rs"))
.with_config(config)
.generate()
.expect("Unable to generate bindings")
.write_to_file(&output_path);
+
output_path
}
@@ -1,6 +1,6 @@
use crate::{
AnyElement, Bounds, Element, Layout, LayoutId, Overflow, ParentElement, Pixels, Point,
- Refineable, RefinementCascade, Result, StackContext, Style, StyleHelpers, Styled, ViewContext,
+ Refineable, RefinementCascade, Result, Style, StyleHelpers, Styled, ViewContext,
};
use parking_lot::Mutex;
use smallvec::SmallVec;
@@ -33,16 +33,9 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
cx: &mut ViewContext<S>,
) -> Result<(LayoutId, Self::FrameState)> {
let style = self.computed_style();
- let child_layout_ids = if let Some(text_style) = style.text_style(cx) {
- cx.with_text_style(text_style.clone(), |cx| self.layout_children(view, cx))?
- } else {
- self.layout_children(view, cx)?
- };
-
- Ok((
- cx.request_layout(style.into(), child_layout_ids.clone())?,
- child_layout_ids,
- ))
+ let child_layout_ids = style.apply_text_style(cx, |cx| self.layout_children(view, cx))?;
+ let layout_id = cx.request_layout(style.into(), child_layout_ids.clone())?;
+ Ok((layout_id, child_layout_ids))
}
fn paint(
@@ -56,20 +49,18 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
let style = self.computed_style();
style.paint(order, bounds, cx);
- let overflow = &style.overflow;
+
// // todo!("support only one dimension being hidden")
+ let overflow = &style.overflow;
// if style.overflow.y != Overflow::Visible || style.overflow.x != Overflow::Visible {
- // cx.scene().push_layer(Some(bounds));
- // pop_layer = true;
+ // cx.clip(layout.bounds, style.corner_radii, || )
// }
- if let Some(text_style) = style.text_style(cx) {
- cx.with_text_style(text_style.clone(), |cx| {
- self.paint_children(overflow, state, cx)
- })?;
- } else {
- self.paint_children(overflow, state, cx)?;
- }
+ style.apply_text_style(cx, |cx| {
+ style.apply_overflow(layout.bounds, cx, |cx| {
+ self.paint_children(overflow, state, cx)
+ })
+ })?;
self.handle_scroll(order, bounds, style.overflow.clone(), child_layouts, cx);
// todo!("enable inspector")
@@ -225,6 +225,20 @@ pub struct Bounds<T: Clone + Debug> {
pub size: Size<T>,
}
+impl<T: Clone + Debug + Sub<Output = T>> Bounds<T> {
+ pub fn from_corners(upper_left: Point<T>, lower_right: Point<T>) -> Self {
+ let origin = Point {
+ x: upper_left.x.clone(),
+ y: upper_left.y.clone(),
+ };
+ let size = Size {
+ width: lower_right.x - upper_left.x,
+ height: lower_right.y - upper_left.y,
+ };
+ Bounds { origin, size }
+ }
+}
+
impl<T, Rhs> Mul<Rhs> for Bounds<T>
where
T: Mul<Rhs, Output = Rhs> + Clone + Debug,
@@ -418,6 +432,28 @@ pub struct Corners<T: Clone + Debug> {
pub bottom_left: T,
}
+impl Corners<AbsoluteLength> {
+ pub fn to_pixels(&self, rem_size: Pixels) -> Corners<Pixels> {
+ Corners {
+ top_left: self.top_left.to_pixels(rem_size),
+ top_right: self.top_right.to_pixels(rem_size),
+ bottom_right: self.bottom_right.to_pixels(rem_size),
+ bottom_left: self.bottom_left.to_pixels(rem_size),
+ }
+ }
+}
+
+impl Corners<Pixels> {
+ pub fn scale(&self, factor: f32) -> Corners<ScaledPixels> {
+ Corners {
+ top_left: self.top_left.scale(factor),
+ top_right: self.top_right.scale(factor),
+ bottom_right: self.bottom_right.scale(factor),
+ bottom_left: self.bottom_left.scale(factor),
+ }
+ }
+}
+
impl<T: Clone + Debug> Corners<T> {
pub fn map<U: Clone + Debug, F: Fn(&T) -> U>(&self, f: F) -> Corners<U> {
Corners {
@@ -84,16 +84,16 @@ impl<T> DerefMut for MainThread<T> {
}
}
-pub trait StackContext {
- fn app(&mut self) -> &mut AppContext;
+pub trait BorrowAppContext {
+ fn app_mut(&mut self) -> &mut AppContext;
fn with_text_style<F, R>(&mut self, style: TextStyleRefinement, f: F) -> R
where
F: FnOnce(&mut Self) -> R,
{
- self.app().push_text_style(style);
+ self.app_mut().push_text_style(style);
let result = f(self);
- self.app().pop_text_style();
+ self.app_mut().pop_text_style();
result
}
@@ -101,9 +101,9 @@ pub trait StackContext {
where
F: FnOnce(&mut Self) -> R,
{
- self.app().push_state(state);
+ self.app_mut().push_state(state);
let result = f(self);
- self.app().pop_state::<T>();
+ self.app_mut().pop_state::<T>();
result
}
}
@@ -4,10 +4,10 @@
using namespace metal;
float4 hsla_to_rgba(Hsla hsla);
-float4 to_device_position(float2 unit_vertex, Bounds_Pixels bounds,
- Bounds_Pixels clip_bounds,
+float4 to_device_position(float2 unit_vertex, Bounds_ScaledPixels bounds,
+ Bounds_ScaledPixels clip_bounds,
constant Size_DevicePixels *viewport_size);
-float quad_sdf(float2 point, Bounds_Pixels bounds, Corners_Pixels corner_radii);
+float quad_sdf(float2 point, Bounds_ScaledPixels bounds, Corners_ScaledPixels corner_radii);
struct QuadVertexOutput {
float4 position [[position]];
@@ -131,7 +131,7 @@ vertex MonochromeSpriteVertexOutput monochrome_sprite_vertex(
float2 unit_vertex = unit_vertices[unit_vertex_id];
MonochromeSprite sprite = sprites[sprite_id];
float4 device_position = to_device_position(
- unit_vertex, sprite.bounds, sprite.clip_bounds, viewport_size);
+ unit_vertex, sprite.bounds, sprite.content_mask.bounds, viewport_size);
float2 tile_origin =
float2(sprite.tile.bounds.origin.x, sprite.tile.bounds.origin.y);
@@ -157,7 +157,7 @@ fragment float4 monochrome_sprite_fragment(
float4 sample =
atlas_texture.sample(atlas_texture_sampler, input.tile_position);
float clip_distance =
- quad_sdf(input.position.xy, sprite.clip_bounds, sprite.clip_corner_radii);
+ quad_sdf(input.position.xy, sprite.content_mask.bounds, sprite.content_mask.corner_radii);
float4 color = input.color;
color.a *= sample.a * saturate(0.5 - clip_distance);
return color;
@@ -211,8 +211,8 @@ float4 hsla_to_rgba(Hsla hsla) {
return rgba;
}
-float4 to_device_position(float2 unit_vertex, Bounds_Pixels bounds,
- Bounds_Pixels clip_bounds,
+float4 to_device_position(float2 unit_vertex, Bounds_ScaledPixels bounds,
+ Bounds_ScaledPixels clip_bounds,
constant Size_DevicePixels *input_viewport_size) {
float2 position =
unit_vertex * float2(bounds.size.width, bounds.size.height) +
@@ -229,8 +229,8 @@ float4 to_device_position(float2 unit_vertex, Bounds_Pixels bounds,
return float4(device_position, 0., 1.);
}
-float quad_sdf(float2 point, Bounds_Pixels bounds,
- Corners_Pixels corner_radii) {
+float quad_sdf(float2 point, Bounds_ScaledPixels bounds,
+ Corners_ScaledPixels corner_radii) {
float2 half_size = float2(bounds.size.width, bounds.size.height) / 2.;
float2 center = float2(bounds.origin.x, bounds.origin.y) + half_size;
float2 center_to_point = point - center;
@@ -1,7 +1,7 @@
use std::{iter::Peekable, mem};
use super::{Bounds, Hsla, Point};
-use crate::{AtlasTextureId, AtlasTile, Corners, Edges, ScaledPixels};
+use crate::{AtlasTextureId, AtlasTile, Corners, Edges, ScaledContentMask, ScaledPixels};
use collections::BTreeMap;
use smallvec::SmallVec;
@@ -234,8 +234,7 @@ impl From<Quad> for Primitive {
pub struct MonochromeSprite {
pub order: u32,
pub bounds: Bounds<ScaledPixels>,
- pub clip_bounds: Bounds<ScaledPixels>,
- pub clip_corner_radii: Corners<ScaledPixels>,
+ pub content_mask: ScaledContentMask,
pub color: Hsla,
pub tile: AtlasTile,
}
@@ -1,8 +1,8 @@
use crate::{
- phi, rems, AbsoluteLength, Bounds, Corners, CornersRefinement, DefiniteLength, Edges,
- EdgesRefinement, Font, FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point,
- PointRefinement, Quad, Rems, Result, RunStyle, SharedString, Size, SizeRefinement, ViewContext,
- WindowContext,
+ phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners,
+ CornersRefinement, DefiniteLength, Edges, EdgesRefinement, Font, FontFeatures, FontStyle,
+ FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Quad, Rems, Result, RunStyle,
+ SharedString, Size, SizeRefinement, ViewContext, WindowContext,
};
use refineable::Refineable;
pub use taffy::style::{
@@ -179,6 +179,57 @@ impl Style {
}
}
+ pub fn apply_text_style<C, F, R>(&self, cx: &mut C, f: F) -> R
+ where
+ C: BorrowAppContext,
+ F: FnOnce(&mut C) -> R,
+ {
+ if self.text.is_some() {
+ cx.with_text_style(self.text.clone(), f)
+ } else {
+ f(cx)
+ }
+ }
+
+ /// Apply overflow to content mask
+ pub fn apply_overflow<C, F, R>(&self, bounds: Bounds<Pixels>, cx: &mut C, f: F) -> R
+ where
+ C: BorrowWindow,
+ F: FnOnce(&mut C) -> R,
+ {
+ let current_mask = cx.content_mask();
+
+ let min = current_mask.bounds.origin;
+ let max = current_mask.bounds.lower_right();
+
+ let mask_corner_radii = Corners::default();
+ let mask_bounds = match (
+ self.overflow.x == Overflow::Visible,
+ self.overflow.y == Overflow::Visible,
+ ) {
+ // x and y both visible
+ (true, true) => return f(cx),
+ // x visible, y hidden
+ (true, false) => Bounds::from_corners(
+ point(min.x, bounds.origin.y),
+ point(max.x, bounds.lower_right().y),
+ ),
+ // x hidden, y visible
+ (false, true) => Bounds::from_corners(
+ point(bounds.origin.x, min.y),
+ point(bounds.lower_right().x, max.y),
+ ),
+ // both hidden
+ (false, false) => bounds,
+ };
+ let mask = ContentMask {
+ bounds: mask_bounds,
+ corner_radii: mask_corner_radii,
+ };
+
+ cx.with_content_mask(mask, f)
+ }
+
/// Paints the background of an element styled with this style.
pub fn paint<V: 'static>(&self, order: u32, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
let rem_size = cx.rem_size();
@@ -2,12 +2,6 @@ use smol::future::FutureExt;
use std::{future::Future, time::Duration};
pub use util::*;
-pub fn post_inc(value: &mut usize) -> usize {
- let prev = *value;
- *value += 1;
- prev
-}
-
pub async fn timeout<F, T>(timeout: Duration, f: F) -> Result<T, ()>
where
F: Future<Output = T>,
@@ -1,8 +1,8 @@
use crate::{
- px, AnyView, AppContext, AvailableSpace, Bounds, Context, Corners, Effect, Element, EntityId,
- FontId, GlyphId, GlyphRasterParams, Handle, Hsla, IsZero, LayerId, LayoutId, MainThread,
- MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point, Reference,
- Scene, Size, StackContext, Style, TaffyLayoutEngine, WeakHandle, WindowOptions,
+ px, AnyView, AppContext, AvailableSpace, BorrowAppContext, Bounds, Context, Corners, Effect,
+ Element, EntityId, FontId, GlyphId, GlyphRasterParams, Handle, Hsla, IsZero, LayerId, LayoutId,
+ MainThread, MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point,
+ Reference, ScaledPixels, Scene, Size, Style, TaffyLayoutEngine, WeakHandle, WindowOptions,
SUBPIXEL_VARIANTS,
};
use anyhow::Result;
@@ -74,8 +74,24 @@ impl Window {
#[derive(Clone, Debug)]
pub struct ContentMask {
- bounds: Bounds<Pixels>,
- corner_radii: Corners<Pixels>,
+ pub bounds: Bounds<Pixels>,
+ pub corner_radii: Corners<Pixels>,
+}
+
+impl ContentMask {
+ pub fn scale(&self, factor: f32) -> ScaledContentMask {
+ ScaledContentMask {
+ bounds: self.bounds.scale(factor),
+ corner_radii: self.corner_radii.scale(factor),
+ }
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+#[repr(C)]
+pub struct ScaledContentMask {
+ bounds: Bounds<ScaledPixels>,
+ corner_radii: Corners<ScaledPixels>,
}
pub struct WindowContext<'a, 'w> {
@@ -174,20 +190,6 @@ impl<'a, 'w> WindowContext<'a, 'w> {
self.window.current_layer_id.clone()
}
- pub fn current_clipping_mask(&self) -> ContentMask {
- self.window
- .content_mask_stack
- .last()
- .cloned()
- .unwrap_or_else(|| ContentMask {
- bounds: Bounds {
- origin: Point::default(),
- size: self.window.content_size,
- },
- corner_radii: Default::default(),
- })
- }
-
pub fn run_on_main<R>(
&self,
f: impl FnOnce(&mut MainThread<WindowContext>) -> R + Send + 'static,
@@ -239,14 +241,14 @@ impl<'a, 'w> WindowContext<'a, 'w> {
origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
size: tile.bounds.size.map(Into::into),
};
+ let content_mask = self.content_mask().scale(scale_factor);
self.window.scene.insert(
layer_id,
MonochromeSprite {
order,
bounds,
- clip_bounds: bounds,
- clip_corner_radii: Default::default(),
+ content_mask,
color,
tile,
},
@@ -330,8 +332,60 @@ impl<'a, 'w> std::ops::DerefMut for WindowContext<'a, 'w> {
}
}
-impl<S> StackContext for ViewContext<'_, '_, S> {
- fn app(&mut self) -> &mut AppContext {
+impl BorrowAppContext for WindowContext<'_, '_> {
+ fn app_mut(&mut self) -> &mut AppContext {
+ &mut *self.app
+ }
+}
+
+pub trait BorrowWindow: BorrowAppContext {
+ fn window(&self) -> &Window;
+ fn window_mut(&mut self) -> &mut Window;
+
+ fn with_content_mask<R>(&mut self, mask: ContentMask, f: impl FnOnce(&mut Self) -> R) -> R {
+ self.window_mut().content_mask_stack.push(mask);
+ let result = f(self);
+ self.window_mut().content_mask_stack.pop();
+ result
+ }
+
+ fn content_mask(&self) -> ContentMask {
+ self.window()
+ .content_mask_stack
+ .last()
+ .cloned()
+ .unwrap_or_else(|| ContentMask {
+ bounds: Bounds {
+ origin: Point::default(),
+ size: self.window().content_size,
+ },
+ corner_radii: Default::default(),
+ })
+ }
+
+ fn rem_size(&self) -> Pixels {
+ self.window().rem_size
+ }
+}
+
+impl BorrowWindow for WindowContext<'_, '_> {
+ fn window(&self) -> &Window {
+ &*self.window
+ }
+
+ fn window_mut(&mut self) -> &mut Window {
+ &mut *self.window
+ }
+}
+
+pub struct ViewContext<'a, 'w, S> {
+ window_cx: WindowContext<'a, 'w>,
+ entity_type: PhantomData<S>,
+ entity_id: EntityId,
+}
+
+impl<S> BorrowAppContext for ViewContext<'_, '_, S> {
+ fn app_mut(&mut self) -> &mut AppContext {
&mut *self.window_cx.app
}
@@ -356,10 +410,14 @@ impl<S> StackContext for ViewContext<'_, '_, S> {
}
}
-pub struct ViewContext<'a, 'w, S> {
- window_cx: WindowContext<'a, 'w>,
- entity_type: PhantomData<S>,
- entity_id: EntityId,
+impl<S> BorrowWindow for ViewContext<'_, '_, S> {
+ fn window(&self) -> &Window {
+ &self.window_cx.window
+ }
+
+ fn window_mut(&mut self) -> &mut Window {
+ &mut *self.window_cx.window
+ }
}
impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
@@ -1,4 +1,6 @@
-use gpui3::{Element, Hsla, Layout, LayoutId, Result, StackContext, ViewContext, WindowContext};
+use gpui3::{
+ BorrowAppContext, Element, Hsla, Layout, LayoutId, Result, ViewContext, WindowContext,
+};
use serde::{de::Visitor, Deserialize, Deserializer};
use std::{collections::HashMap, fmt};