diff --git a/Cargo.lock b/Cargo.lock index 5cf9d6c94..3dbf20999 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,9 +37,9 @@ checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" [[package]] name = "ash" -version = "0.37.0+1.3.209" +version = "0.37.1+1.3.235" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006ca68e0f2b03f22d6fa9f2860f85aed430d257fec20f8879b2145e7c7ae1a6" +checksum = "911015c962d56e2e4052f40182ca5462ba60a3d2ff04e827c365a0ab3d65726d" dependencies = [ "libloading", ] @@ -982,7 +982,7 @@ dependencies = [ [[package]] name = "glazier" version = "0.7.0" -source = "git+https://github.com/linebender/glazier#122e37a5fdf263ba61cf19bc8f74913b01634467" +source = "git+https://github.com/linebender/glazier#464c328ff842a07543461c9991adfaa3cd78181d" dependencies = [ "anyhow", "ashpd", diff --git a/src/app.rs b/src/app.rs index e2c5435ba..1165b3671 100644 --- a/src/app.rs +++ b/src/app.rs @@ -19,11 +19,12 @@ use std::time::Duration; use glazier::kurbo::Size; use glazier::{IdleHandle, IdleToken, WindowHandle}; use parley::FontContext; +use piet_scene::{SceneBuilder, SceneFragment}; use tokio::runtime::Runtime; use crate::event::{AsyncWake, EventResult}; use crate::id::IdPath; -use crate::widget::{CxState, EventCx, LayoutCx, PaintCx, Pod, Rendered, UpdateCx, WidgetState}; +use crate::widget::{CxState, EventCx, LayoutCx, PaintCx, Pod, UpdateCx, WidgetState}; use crate::{ event::Event, id::Id, @@ -170,7 +171,7 @@ where self.size = size; } - pub fn paint(&mut self) -> Rendered { + pub fn paint(&mut self) { loop { self.send_events(); // TODO: be more lazy re-rendering @@ -198,7 +199,8 @@ where continue; } let mut paint_cx = PaintCx::new(&mut cx_state, &mut self.root_state); - return root_pod.paint(&mut paint_cx); + root_pod.paint(&mut paint_cx); + break; } } @@ -273,6 +275,12 @@ where } } +impl> App { + pub fn fragment(&self) -> &SceneFragment { + self.root_pod.as_ref().unwrap().fragment() + } +} + impl, F: FnMut(&mut T) -> V> AppTask where V::Element: Widget + 'static, diff --git a/src/app_main.rs b/src/app_main.rs index d0416fa69..c516b960c 100644 --- a/src/app_main.rs +++ b/src/app_main.rs @@ -97,15 +97,15 @@ where fn prepare_paint(&mut self) {} fn paint(&mut self, _: &Region) { - let rendered = self.app.paint(); - self.render(rendered.0); + self.app.paint(); + self.render(); self.schedule_render(); } // TODO: temporary hack fn idle(&mut self, _: IdleToken) { - let rendered = self.app.paint(); - self.render(rendered.0); + self.app.paint(); + self.render(); self.schedule_render(); } @@ -160,6 +160,7 @@ where impl> MainState where V::Element: Widget, + T: Send, { fn new(app: App) -> Self { let state = MainState { @@ -186,7 +187,8 @@ where self.handle.invalidate(); } - fn render(&mut self, fragment: SceneFragment) { + fn render(&mut self) { + let fragment = self.app.fragment(); if self.pgpu_state.is_none() { let handle = &self.handle; let scale = handle.get_scale().unwrap(); diff --git a/src/widget.rs b/src/widget.rs index d0cbf74fb..7594e8f1b 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -28,6 +28,7 @@ use std::any::Any; use std::ops::{Deref, DerefMut}; use glazier::kurbo::{Rect, Size}; +use piet_scene::SceneBuilder; use self::contexts::LifeCycleCx; pub use self::contexts::{AlignCx, CxState, EventCx, LayoutCx, PaintCx, PreparePaintCx, UpdateCx}; @@ -79,11 +80,9 @@ pub trait Widget { #[allow(unused)] fn prepare_paint(&mut self, cx: &mut LayoutCx, visible: Rect) {} - fn paint(&mut self, cx: &mut PaintCx) -> Rendered; + fn paint(&mut self, cx: &mut PaintCx, builder: &mut SceneBuilder); } -pub struct Rendered(pub(crate) piet_scene::SceneFragment); - pub trait AnyWidget: Widget { fn as_any(&self) -> &dyn Any; @@ -135,8 +134,8 @@ impl Widget for Box { self.deref_mut().prepare_paint(cx, visible) } - fn paint(&mut self, cx: &mut PaintCx) -> Rendered { - self.deref_mut().paint(cx) + fn paint(&mut self, cx: &mut PaintCx, builder: &mut SceneBuilder) { + self.deref_mut().paint(cx, builder); } } diff --git a/src/widget/align.rs b/src/widget/align.rs index 48e87cc7c..0e9ca1be7 100644 --- a/src/widget/align.rs +++ b/src/widget/align.rs @@ -13,10 +13,9 @@ // limitations under the License. use glazier::kurbo::{Point, Size}; +use piet_scene::SceneBuilder; -use super::{ - contexts::LifeCycleCx, AlignCx, AnyWidget, EventCx, LifeCycle, Rendered, Widget, WidgetState, -}; +use super::{contexts::LifeCycleCx, AlignCx, AnyWidget, EventCx, LifeCycle, Widget, WidgetState}; #[derive(Clone, Copy, PartialEq)] pub enum AlignmentMerge { @@ -276,7 +275,7 @@ impl f64 + 'static> Widget for AlignmentGuide { } } - fn paint(&mut self, cx: &mut super::PaintCx) -> Rendered { - self.child.paint(cx) + fn paint(&mut self, cx: &mut super::PaintCx, builder: &mut SceneBuilder) { + self.child.paint(cx, builder); } } diff --git a/src/widget/button.rs b/src/widget/button.rs index cc5c2bbf7..b986621f0 100644 --- a/src/widget/button.rs +++ b/src/widget/button.rs @@ -22,7 +22,7 @@ use super::{ align::{FirstBaseline, LastBaseline, SingleAlignment}, contexts::LifeCycleCx, piet_scene_helpers::{self, UnitPoint}, - AlignCx, EventCx, LayoutCx, LifeCycle, PaintCx, RawEvent, Rendered, UpdateCx, Widget, + AlignCx, EventCx, LayoutCx, LifeCycle, PaintCx, RawEvent, UpdateCx, Widget, }; pub struct Button { @@ -122,7 +122,7 @@ impl Widget for Button { */ } - fn paint(&mut self, cx: &mut PaintCx) -> Rendered { + fn paint(&mut self, cx: &mut PaintCx, builder: &mut SceneBuilder) { let is_hot = cx.is_hot(); let is_active = cx.is_active(); let button_border_width = 2.0; @@ -156,16 +156,9 @@ impl Widget for Button { ) }; */ - let mut fragment = SceneFragment::default(); - let mut builder = SceneBuilder::for_fragment(&mut fragment); - piet_scene_helpers::stroke( - &mut builder, - &rounded_rect, - border_color, - button_border_width, - ); + piet_scene_helpers::stroke(builder, &rounded_rect, border_color, button_border_width); piet_scene_helpers::fill_lin_gradient( - &mut builder, + builder, &rounded_rect, bg_stops, UnitPoint::TOP, @@ -176,8 +169,7 @@ impl Widget for Button { let size = Size::new(layout.width() as f64, layout.height() as f64); let offset = (cx.size().to_vec2() - size.to_vec2()) * 0.5; let transform = Affine::translate(offset); - crate::text::render_text(&mut builder, transform, &layout); + crate::text::render_text(builder, transform, &layout); } - Rendered(fragment) } } diff --git a/src/widget/core.rs b/src/widget/core.rs index 68fa4983e..c77698e60 100644 --- a/src/widget/core.rs +++ b/src/widget/core.rs @@ -18,7 +18,8 @@ //! widget system, particularly its core.rs. use bitflags::bitflags; -use glazier::kurbo::{Affine, Point, Rect, Size}; +use glazier::kurbo::{Point, Rect, Size}; +use piet_scene::{SceneBuilder, SceneFragment}; use crate::Widget; @@ -29,7 +30,7 @@ use super::{ }, contexts::LifeCycleCx, AlignCx, AnyWidget, CxState, EventCx, LayoutCx, LifeCycle, PaintCx, PreparePaintCx, RawEvent, - Rendered, UpdateCx, + UpdateCx, }; bitflags! { @@ -52,6 +53,7 @@ bitflags! { pub struct Pod { pub(crate) state: WidgetState, pub(crate) widget: Box, + fragment: SceneFragment, } #[derive(Default, Debug)] @@ -116,6 +118,7 @@ impl Pod { flags: PodFlags::INIT_FLAGS, ..Default::default() }, + fragment: SceneFragment::default(), widget, } } @@ -295,24 +298,25 @@ impl Pod { self.widget.align(&mut child_cx, alignment); } - pub fn paint_raw(&mut self, cx: &mut PaintCx) { + pub fn paint_raw(&mut self, cx: &mut PaintCx, builder: &mut SceneBuilder) { let mut inner_cx = PaintCx { cx_state: cx.cx_state, widget_state: &mut self.state, }; - self.widget.paint(&mut inner_cx); + self.widget.paint(&mut inner_cx, builder); } pub fn prepare_paint(&mut self, cx: &mut PreparePaintCx, visible: Rect) { self.widget.prepare_paint(cx, visible); } - pub fn paint(&mut self, cx: &mut PaintCx) -> Rendered { + pub fn paint(&mut self, cx: &mut PaintCx) { let mut inner_cx = PaintCx { cx_state: cx.cx_state, widget_state: &mut self.state, }; - self.widget.paint(&mut inner_cx) + let mut builder = SceneBuilder::for_fragment(&mut self.fragment); + self.widget.paint(&mut inner_cx, &mut builder); } pub fn height_flexibility(&self) -> f64 { @@ -350,4 +354,12 @@ impl Pod { } false } + + /// Get the rendered scene fragment for the widget. + /// + /// This is only valid after a `paint` call, but the fragment can be retained + /// (skipping further paint calls) if the appearance does not change. + pub fn fragment(&self) -> &SceneFragment { + &self.fragment + } } diff --git a/src/widget/text.rs b/src/widget/text.rs index 775b1d2dd..db1585f21 100644 --- a/src/widget/text.rs +++ b/src/widget/text.rs @@ -21,7 +21,7 @@ use crate::text::ParleyBrush; use super::{ align::{FirstBaseline, LastBaseline, SingleAlignment, VertAlignment}, contexts::LifeCycleCx, - AlignCx, EventCx, LayoutCx, LifeCycle, PaintCx, RawEvent, Rendered, UpdateCx, Widget, + AlignCx, EventCx, LayoutCx, LifeCycle, PaintCx, RawEvent, UpdateCx, Widget, }; pub struct TextWidget { @@ -77,13 +77,10 @@ impl Widget for TextWidget { fn align(&self, cx: &mut AlignCx, alignment: SingleAlignment) {} - fn paint(&mut self, cx: &mut PaintCx) -> Rendered { - let mut fragment = SceneFragment::default(); - let mut builder = SceneBuilder::for_fragment(&mut fragment); + fn paint(&mut self, cx: &mut PaintCx, builder: &mut SceneBuilder) { if let Some(layout) = &self.layout { let transform = Affine::translate((40.0, 40.0)); - crate::text::render_text(&mut builder, transform, &layout); + crate::text::render_text(builder, transform, &layout); } - Rendered(fragment) } }