Checkpoint

This commit is contained in:
Nathan Sobo 2023-10-02 15:43:03 -06:00
parent 77e67c19fe
commit 6046ed4f5c
7 changed files with 220 additions and 496 deletions

View file

@ -3,7 +3,7 @@ use crate::{
};
use parking_lot::Mutex;
use std::{marker::PhantomData, sync::Arc};
use util::{arc_cow::ArcCow, ResultExt};
use util::arc_cow::ArcCow;
impl<S: 'static> IntoAnyElement<S> for ArcCow<'static, str> {
fn into_any(self) -> AnyElement<S> {
@ -92,8 +92,6 @@ impl<S: 'static> Element for Text<S> {
paint_state: &mut Self::FrameState,
cx: &mut ViewContext<S>,
) -> Result<()> {
let bounds = layout.bounds;
let line;
let line_height;
{
@ -108,8 +106,8 @@ impl<S: 'static> Element for Text<S> {
let _text_style = cx.text_style();
// todo!("We haven't added visible bounds to the new element system yet, so this is a placeholder.");
let visible_bounds = bounds;
line.paint(bounds.origin, visible_bounds, line_height, cx)?;
let visible_bounds = layout.bounds;
line.paint(&layout, visible_bounds, line_height, cx)?;
Ok(())
}

View file

@ -425,7 +425,9 @@ unsafe impl<T: Clone + Debug + Zeroable + Pod> Zeroable for Corners<T> {}
unsafe impl<T: Clone + Debug + Zeroable + Pod> Pod for Corners<T> {}
#[derive(Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, PartialEq, PartialOrd)]
#[derive(
Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, PartialEq, PartialOrd, Zeroable, Pod,
)]
#[repr(transparent)]
pub struct Pixels(pub(crate) f32);
@ -445,6 +447,12 @@ impl Mul<Pixels> for f32 {
}
}
impl MulAssign<f32> for Pixels {
fn mul_assign(&mut self, other: f32) {
self.0 *= other;
}
}
impl Pixels {
pub fn round(&self) -> Self {
Self(self.0.round())
@ -489,9 +497,6 @@ impl From<f32> for Pixels {
}
}
unsafe impl bytemuck::Pod for Pixels {}
unsafe impl bytemuck::Zeroable for Pixels {}
impl Debug for Pixels {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} px", self.0)

View file

@ -14,33 +14,33 @@ struct QuadVertexOutput {
};
vertex QuadVertexOutput quad_vertex(
uint unit_vertex_id [[vertex_id]],
uint quad_id [[instance_id]],
uint unit_vertex_id [[vertex_id]], uint quad_id [[instance_id]],
constant float2 *unit_vertices [[buffer(QuadInputIndex_Vertices)]],
constant Quad *quads [[buffer(QuadInputIndex_Quads)]],
constant QuadUniforms *uniforms [[buffer(QuadInputIndex_Uniforms)]]
) {
constant QuadUniforms *uniforms [[buffer(QuadInputIndex_Uniforms)]]) {
float2 unit_vertex = unit_vertices[unit_vertex_id];
Quad quad = quads[quad_id];
float2 position_2d = unit_vertex * float2(quad.bounds.size.width, quad.bounds.size.height) + float2(quad.bounds.origin.x, quad.bounds.origin.y);
float2 position_2d =
unit_vertex * float2(quad.bounds.size.width, quad.bounds.size.height) +
float2(quad.bounds.origin.x, quad.bounds.origin.y);
position_2d.x = max(quad.clip_bounds.origin.x, position_2d.x);
position_2d.x = min(quad.clip_bounds.origin.x + quad.clip_bounds.size.width, position_2d.x);
position_2d.x = min(quad.clip_bounds.origin.x + quad.clip_bounds.size.width,
position_2d.x);
position_2d.y = max(quad.clip_bounds.origin.y, position_2d.y);
position_2d.y = min(quad.clip_bounds.origin.y + quad.clip_bounds.size.height, position_2d.y);
position_2d.y = min(quad.clip_bounds.origin.y + quad.clip_bounds.size.height,
position_2d.y);
float2 viewport_size = float2((float)uniforms->viewport_size.width, (float)uniforms->viewport_size.height);
float2 viewport_size = float2((float)uniforms->viewport_size.width,
(float)uniforms->viewport_size.height);
float4 device_position = to_device_position(position_2d, viewport_size);
float4 background_color = hsla_to_rgba(quad.background);
float4 border_color = hsla_to_rgba(quad.border_color);
return QuadVertexOutput {
device_position,
background_color,
border_color,
quad_id
};
return QuadVertexOutput{device_position, background_color, border_color,
quad_id};
}
float quad_sdf(float2 point, Bounds_Pixels bounds, Corners_Pixels corner_radii) {
float quad_sdf(float2 point, Bounds_Pixels bounds,
Corners_Pixels 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;
@ -59,21 +59,24 @@ float quad_sdf(float2 point, Bounds_Pixels bounds, Corners_Pixels corner_radii)
}
}
float2 rounded_edge_to_point = abs(center_to_point) - half_size + corner_radius;
float distance = length(max(0., rounded_edge_to_point))
+ min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y))
- corner_radius;
float2 rounded_edge_to_point =
abs(center_to_point) - half_size + corner_radius;
float distance =
length(max(0., rounded_edge_to_point)) +
min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y)) -
corner_radius;
return distance;
}
fragment float4 quad_fragment(
QuadVertexOutput input [[stage_in]],
constant Quad *quads [[buffer(QuadInputIndex_Quads)]]
) {
fragment float4 quad_fragment(QuadVertexOutput input [[stage_in]],
constant Quad *quads
[[buffer(QuadInputIndex_Quads)]]) {
Quad quad = quads[input.quad_id];
float2 half_size = float2(quad.bounds.size.width, quad.bounds.size.height) / 2.;
float2 center = float2(quad.bounds.origin.x, quad.bounds.origin.y) + half_size;
float2 half_size =
float2(quad.bounds.size.width, quad.bounds.size.height) / 2.;
float2 center =
float2(quad.bounds.origin.x, quad.bounds.origin.y) + half_size;
float2 center_to_point = input.position.xy - center;
float corner_radius;
if (center_to_point.x < 0.) {
@ -90,12 +93,19 @@ fragment float4 quad_fragment(
}
}
float2 rounded_edge_to_point = fabs(center_to_point) - half_size + corner_radius;
float distance = length(max(0., rounded_edge_to_point)) + min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y)) - corner_radius;
float2 rounded_edge_to_point =
fabs(center_to_point) - half_size + corner_radius;
float distance =
length(max(0., rounded_edge_to_point)) +
min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y)) -
corner_radius;
float vertical_border = center_to_point.x <= 0. ? quad.border_widths.left : quad.border_widths.right;
float horizontal_border = center_to_point.y <= 0. ? quad.border_widths.top : quad.border_widths.bottom;
float2 inset_size = half_size - corner_radius - float2(vertical_border, horizontal_border);
float vertical_border = center_to_point.x <= 0. ? quad.border_widths.left
: quad.border_widths.right;
float horizontal_border = center_to_point.y <= 0. ? quad.border_widths.top
: quad.border_widths.bottom;
float2 inset_size =
half_size - corner_radius - float2(vertical_border, horizontal_border);
float2 point_to_inset_corner = fabs(center_to_point) - inset_size;
float border_width;
if (point_to_inset_corner.x < 0. && point_to_inset_corner.y < 0.) {
@ -116,15 +126,23 @@ fragment float4 quad_fragment(
input.border_color.a *= 1. - saturate(0.5 - inset_distance);
// Alpha-blend the border and the background.
float output_alpha = quad.border_color.a + quad.background.a * (1. - quad.border_color.a);
float3 premultiplied_border_rgb = input.border_color.rgb * quad.border_color.a;
float3 premultiplied_background_rgb = input.background_color.rgb * input.background_color.a;
float3 premultiplied_output_rgb = premultiplied_border_rgb + premultiplied_background_rgb * (1. - input.border_color.a);
float output_alpha =
quad.border_color.a + quad.background.a * (1. - quad.border_color.a);
float3 premultiplied_border_rgb =
input.border_color.rgb * quad.border_color.a;
float3 premultiplied_background_rgb =
input.background_color.rgb * input.background_color.a;
float3 premultiplied_output_rgb =
premultiplied_border_rgb +
premultiplied_background_rgb * (1. - input.border_color.a);
color = float4(premultiplied_output_rgb, output_alpha);
}
float clip_distance = quad_sdf(input.position.xy, quad.clip_bounds, quad.clip_corner_radii);
return color * float4(1., 1., 1., saturate(0.5 - distance) * saturate(0.5 - clip_distance));
float clip_distance =
quad_sdf(input.position.xy, quad.clip_bounds, quad.clip_corner_radii);
return color *
float4(1., 1., 1.,
saturate(0.5 - distance) * saturate(0.5 - clip_distance));
}
float4 hsla_to_rgba(Hsla hsla) {
@ -133,9 +151,9 @@ float4 hsla_to_rgba(Hsla hsla) {
float l = hsla.l;
float a = hsla.a;
float c = (1.0 - fabs(2.0*l - 1.0)) * s;
float c = (1.0 - fabs(2.0 * l - 1.0)) * s;
float x = c * (1.0 - fabs(fmod(h, 2.0) - 1.0));
float m = l - c/2.0;
float m = l - c / 2.0;
float r = 0.0;
float g = 0.0;
@ -176,5 +194,7 @@ float4 hsla_to_rgba(Hsla hsla) {
}
float4 to_device_position(float2 pixel_position, float2 viewport_size) {
return float4(pixel_position / viewport_size * float2(2., -2.) + float2(-1., 1.), 0., 1.);
return float4(pixel_position / viewport_size * float2(2., -2.) +
float2(-1., 1.),
0., 1.);
}

View file

@ -1,7 +1,7 @@
use std::mem;
use super::{Bounds, Hsla, Pixels, Point};
use crate::{Corners, Edges};
use crate::{Corners, Edges, FontId, GlyphId};
use bytemuck::{Pod, Zeroable};
use collections::BTreeMap;
@ -17,6 +17,7 @@ pub struct Scene {
#[derive(Default, Debug)]
pub struct SceneLayer {
pub quads: Vec<Quad>,
pub symbol: Vec<Symbol>,
}
impl Scene {
@ -40,6 +41,7 @@ impl Scene {
let layer = self.layers.entry(primitive.order()).or_default();
match primitive {
Primitive::Quad(quad) => layer.quads.push(quad),
Primitive::MonochromeGlyph(glyph) => layer.symbol.push(glyph),
}
}
@ -51,20 +53,14 @@ impl Scene {
#[derive(Clone, Debug)]
pub enum Primitive {
Quad(Quad),
MonochromeGlyph(Symbol),
}
impl Primitive {
pub fn order(&self) -> u32 {
match self {
Primitive::Quad(quad) => quad.order,
}
}
pub fn is_transparent(&self) -> bool {
match self {
Primitive::Quad(quad) => {
quad.background.is_transparent() && quad.border_color.is_transparent()
}
Primitive::MonochromeGlyph(glyph) => glyph.order,
}
}
@ -73,6 +69,9 @@ impl Primitive {
Primitive::Quad(quad) => {
quad.scale(factor);
}
Primitive::MonochromeGlyph(glyph) => {
glyph.scale(factor);
}
}
}
}
@ -119,3 +118,27 @@ impl From<Quad> for Primitive {
Primitive::Quad(quad)
}
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct Symbol {
pub order: u32,
pub origin: Point<Pixels>,
pub font_id: FontId,
pub font_size: Pixels,
pub id: GlyphId,
pub color: Hsla,
}
impl Symbol {
pub fn scale(&mut self, factor: f32) {
self.font_size *= factor;
self.origin *= factor;
}
}
impl From<Symbol> for Primitive {
fn from(glyph: Symbol) -> Self {
Primitive::MonochromeGlyph(glyph)
}
}

View file

@ -1,9 +1,12 @@
mod font_features;
mod line;
mod line_wrapper;
mod text_layout_cache;
use anyhow::anyhow;
use bytemuck::{Pod, Zeroable};
pub use font_features::*;
pub use line::*;
use line_wrapper::*;
pub use text_layout_cache::*;
@ -20,7 +23,8 @@ use std::{
sync::Arc,
};
#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)]
#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug, Zeroable, Pod)]
#[repr(C)]
pub struct FontId(pub usize);
#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)]
@ -51,7 +55,6 @@ impl TextSystem {
pub fn font_id(&self, font: &Font) -> Result<FontId> {
let font_id = self.font_ids_by_font.read().get(font).copied();
if let Some(font_id) = font_id {
Ok(font_id)
} else {
@ -160,29 +163,18 @@ impl TextSystem {
) -> Result<Line> {
let mut font_runs = self.font_runs_pool.lock().pop().unwrap_or_default();
dbg!("got font runs from pool");
let mut last_font: Option<&Font> = None;
for (len, style) in runs {
dbg!(len);
if let Some(last_font) = last_font.as_ref() {
dbg!("a");
if **last_font == style.font {
dbg!("b");
font_runs.last_mut().unwrap().0 += len;
dbg!("c");
continue;
}
dbg!("d");
}
dbg!("e");
last_font = Some(&style.font);
dbg!("f");
font_runs.push((*len, self.font_id(&style.font)?));
dbg!("g");
}
dbg!("built font runs");
let layout = self
.text_layout_cache
.layout_line(text, font_size, &font_runs);
@ -332,7 +324,8 @@ pub struct RunStyle {
pub underline: Option<UnderlineStyle>,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Zeroable, Pod)]
#[repr(C)]
pub struct GlyphId(u32);
impl From<GlyphId> for u32 {

View file

@ -1,8 +1,4 @@
use crate::{
black, point, px, Bounds, FontId, Glyph, Hsla, LineLayout, Pixels, PlatformTextSystem, Point,
Run, RunStyle, UnderlineStyle, WindowContext,
};
use anyhow::Result;
use crate::{FontId, Glyph, LineLayout, Pixels, PlatformTextSystem, Run};
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
use smallvec::SmallVec;
use std::{
@ -40,7 +36,6 @@ impl TextLayoutCache {
font_size: Pixels,
runs: &[(usize, FontId)],
) -> Arc<LineLayout> {
dbg!("layout line");
let key = &CacheKeyRef {
text,
font_size,
@ -145,332 +140,12 @@ impl<'a> Hash for CacheKeyRef<'a> {
}
}
#[derive(Default, Debug, Clone)]
pub struct Line {
layout: Arc<LineLayout>,
style_runs: SmallVec<[StyleRun; 32]>,
}
#[derive(Debug, Clone)]
struct StyleRun {
len: u32,
color: Hsla,
underline: UnderlineStyle,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct ShapedBoundary {
pub run_ix: usize,
pub glyph_ix: usize,
}
impl Line {
pub fn new(layout: Arc<LineLayout>, runs: &[(usize, RunStyle)]) -> Self {
let mut style_runs = SmallVec::new();
for (len, style) in runs {
style_runs.push(StyleRun {
len: *len as u32,
color: style.color,
underline: style.underline.clone().unwrap_or_default(),
});
}
Self { layout, style_runs }
}
pub fn runs(&self) -> &[Run] {
&self.layout.runs
}
pub fn width(&self) -> Pixels {
self.layout.width
}
pub fn font_size(&self) -> Pixels {
self.layout.font_size
}
pub fn x_for_index(&self, index: usize) -> Pixels {
for run in &self.layout.runs {
for glyph in &run.glyphs {
if glyph.index >= index {
return glyph.position.x;
}
}
}
self.layout.width
}
pub fn font_for_index(&self, index: usize) -> Option<FontId> {
for run in &self.layout.runs {
for glyph in &run.glyphs {
if glyph.index >= index {
return Some(run.font_id);
}
}
}
None
}
pub fn len(&self) -> usize {
self.layout.len
}
pub fn is_empty(&self) -> bool {
self.layout.len == 0
}
pub fn index_for_x(&self, x: Pixels) -> Option<usize> {
if x >= self.layout.width {
None
} else {
for run in self.layout.runs.iter().rev() {
for glyph in run.glyphs.iter().rev() {
if glyph.position.x <= x {
return Some(glyph.index);
}
}
}
Some(0)
}
}
// todo!
pub fn paint(
&self,
origin: Point<Pixels>,
visible_bounds: Bounds<Pixels>,
line_height: Pixels,
cx: &mut WindowContext,
) -> Result<()> {
let padding_top = (line_height - self.layout.ascent - self.layout.descent) / 2.;
let baseline_offset = point(px(0.), padding_top + self.layout.ascent);
let mut style_runs = self.style_runs.iter();
let mut run_end = 0;
let mut color = black();
let mut underline = None;
for run in &self.layout.runs {
cx.text_system().with_font(run.font_id, |system, font| {
let max_glyph_width = system.bounding_box(font, self.layout.font_size)?.size.width;
for glyph in &run.glyphs {
let glyph_origin = origin + baseline_offset + glyph.position;
if glyph_origin.x > visible_bounds.upper_right().x {
break;
}
let mut finished_underline: Option<(Point<Pixels>, UnderlineStyle)> = None;
if glyph.index >= run_end {
if let Some(style_run) = style_runs.next() {
if let Some((_, underline_style)) = &mut underline {
if style_run.underline != *underline_style {
finished_underline = underline.take();
}
}
if style_run.underline.thickness > px(0.) {
underline.get_or_insert((
point(
glyph_origin.x,
origin.y
+ baseline_offset.y
+ (self.layout.descent * 0.618),
),
UnderlineStyle {
color: style_run.underline.color,
thickness: style_run.underline.thickness,
squiggly: style_run.underline.squiggly,
},
));
}
run_end += style_run.len as usize;
color = style_run.color;
} else {
run_end = self.layout.len;
finished_underline = underline.take();
}
}
if glyph_origin.x + max_glyph_width < visible_bounds.origin.x {
continue;
}
if let Some((_underline_origin, _underline_style)) = finished_underline {
// cx.scene().insert(Underline {
// origin: underline_origin,
// width: glyph_origin.x - underline_origin.x,
// thickness: underline_style.thickness.into(),
// color: underline_style.color.unwrap(),
// squiggly: underline_style.squiggly,
// });
}
// if glyph.is_emoji {
// cx.scene().push_image_glyph(scene::ImageGlyph {
// font_id: run.font_id,
// font_size: self.layout.font_size,
// id: glyph.id,
// origin: glyph_origin,
// });
// } else {
// cx.scene().push_glyph(scene::Glyph {
// font_id: run.font_id,
// font_size: self.layout.font_size,
// id: glyph.id,
// origin: glyph_origin,
// color,
// });
// }
}
anyhow::Ok(())
})??;
}
if let Some((_underline_start, _underline_style)) = underline.take() {
let _line_end_x = origin.x + self.layout.width;
// cx.scene().push_underline(Underline {
// origin: underline_start,
// width: line_end_x - underline_start.x,
// color: underline_style.color,
// thickness: underline_style.thickness.into(),
// squiggly: underline_style.squiggly,
// });
}
Ok(())
}
pub fn paint_wrapped(
&self,
origin: Point<Pixels>,
_visible_bounds: Bounds<Pixels>,
line_height: Pixels,
boundaries: &[ShapedBoundary],
cx: &mut WindowContext,
) -> Result<()> {
let padding_top = (line_height - self.layout.ascent - self.layout.descent) / 2.;
let baseline_offset = point(px(0.), padding_top + self.layout.ascent);
let mut boundaries = boundaries.into_iter().peekable();
let mut color_runs = self.style_runs.iter();
let mut style_run_end = 0;
let mut _color = black(); // todo!
let mut underline: Option<(Point<Pixels>, UnderlineStyle)> = None;
let mut glyph_origin = origin;
let mut prev_position = px(0.);
for (run_ix, run) in self.layout.runs.iter().enumerate() {
for (glyph_ix, glyph) in run.glyphs.iter().enumerate() {
glyph_origin.x += glyph.position.x - prev_position;
if boundaries
.peek()
.map_or(false, |b| b.run_ix == run_ix && b.glyph_ix == glyph_ix)
{
boundaries.next();
if let Some((_underline_origin, _underline_style)) = underline.take() {
// cx.scene().push_underline(Underline {
// origin: underline_origin,
// width: glyph_origin.x - underline_origin.x,
// thickness: underline_style.thickness.into(),
// color: underline_style.color.unwrap(),
// squiggly: underline_style.squiggly,
// });
}
glyph_origin = point(origin.x, glyph_origin.y + line_height);
}
prev_position = glyph.position.x;
let mut finished_underline = None;
if glyph.index >= style_run_end {
if let Some(style_run) = color_runs.next() {
style_run_end += style_run.len as usize;
_color = style_run.color;
if let Some((_, underline_style)) = &mut underline {
if style_run.underline != *underline_style {
finished_underline = underline.take();
}
}
if style_run.underline.thickness > px(0.) {
underline.get_or_insert((
glyph_origin
+ point(
px(0.),
baseline_offset.y + (self.layout.descent * 0.618),
),
UnderlineStyle {
color: Some(
style_run.underline.color.unwrap_or(style_run.color),
),
thickness: style_run.underline.thickness,
squiggly: style_run.underline.squiggly,
},
));
}
} else {
style_run_end = self.layout.len;
_color = black();
finished_underline = underline.take();
}
}
if let Some((_underline_origin, _underline_style)) = finished_underline {
// cx.scene().push_underline(Underline {
// origin: underline_origin,
// width: glyph_origin.x - underline_origin.x,
// thickness: underline_style.thickness.into(),
// color: underline_style.color.unwrap(),
// squiggly: underline_style.squiggly,
// });
}
cx.text_system().with_font(run.font_id, |system, font| {
let _glyph_bounds = Bounds {
origin: glyph_origin,
size: system.bounding_box(font, self.layout.font_size)?.size,
};
// if glyph_bounds.intersects(visible_bounds) {
// if glyph.is_emoji {
// cx.scene().push_image_glyph(scene::ImageGlyph {
// font_id: run.font_id,
// font_size: self.layout.font_size,
// id: glyph.id,
// origin: glyph_bounds.origin() + baseline_offset,
// });
// } else {
// cx.scene().push_glyph(scene::Glyph {
// font_id: run.font_id,
// font_size: self.layout.font_size,
// id: glyph.id,
// origin: glyph_bounds.origin() + baseline_offset,
// color,
// });
// }
// }
anyhow::Ok(())
})??;
}
}
if let Some((_underline_origin, _underline_style)) = underline.take() {
// let line_end_x = glyph_origin.x + self.layout.width - prev_position;
// cx.scene().push_underline(Underline {
// origin: underline_origin,
// width: line_end_x - underline_origin.x,
// thickness: underline_style.thickness.into(),
// color: underline_style.color,
// squiggly: underline_style.squiggly,
// });
}
Ok(())
}
}
impl Run {
pub fn glyphs(&self) -> &[Glyph] {
&self.glyphs

View file

@ -5,6 +5,7 @@ use crate::{
};
use anyhow::Result;
use futures::Future;
use smallvec::SmallVec;
use std::{any::TypeId, marker::PhantomData, mem, sync::Arc};
use util::ResultExt;
@ -18,6 +19,7 @@ pub struct Window {
layout_engine: TaffyLayoutEngine,
pub(crate) root_view: Option<AnyView<()>>,
mouse_position: Point<Pixels>,
z_index_stack: SmallVec<[u32; 8]>,
pub(crate) scene: Scene,
pub(crate) dirty: bool,
}
@ -56,6 +58,7 @@ impl Window {
layout_engine: TaffyLayoutEngine::new(),
root_view: None,
mouse_position,
z_index_stack: SmallVec::new(),
scene: Scene::new(scale_factor),
dirty: true,
}
@ -126,6 +129,13 @@ impl<'a, 'w> WindowContext<'a, 'w> {
&mut self.window.scene
}
pub fn with_z_index<R>(&mut self, z_index: u32, f: impl FnOnce(&mut Self) -> R) -> R {
self.window.z_index_stack.push(z_index);
let result = f(self);
self.window.z_index_stack.pop();
result
}
pub fn run_on_main<R>(
&self,
f: impl FnOnce(&mut MainThread<WindowContext>) -> R + Send + 'static,