Skip to content

Commit

Permalink
Merge pull request #378 from kas-gui/work2
Browse files Browse the repository at this point in the history
Async rendering for Svg widget
  • Loading branch information
dhardy authored Jan 25, 2023
2 parents 440e5cd + d8e9dd1 commit 05f36ee
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 102 deletions.
36 changes: 18 additions & 18 deletions crates/kas-core/src/event/manager/mgr_pub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,13 +469,17 @@ impl EventState {
self.hover_icon = icon;
}

/// Push a message to the stack via a [`Future`]
/// Asynchronously push a message to the stack via a [`Future`]
///
/// Expects a future which, on completion, returns a message.
/// This message is then pushed to the message stack as if it were pushed
/// with [`Self::push`] from widget `id`.
/// The future is polled after event handling and after drawing and is able
/// to wake the event loop. This future is executed on the main thread; for
/// high-CPU tasks use [`Self::push_spawn`] instead.
///
/// The future will be polled before the event loop sleeps.
/// The future must resolve to a message on completion. This message is
/// pushed to the message stack as if it were pushed with [`EventMgr::push`]
/// from widget `id`, allowing this widget or any ancestor to handle it in
/// [`Widget::handle_message`].
//
// TODO: Can we identify the calling widget `id` via the context (EventMgr)?
pub fn push_async<Fut, M>(&mut self, id: WidgetId, fut: Fut)
where
Expand All @@ -485,13 +489,9 @@ impl EventState {
self.push_async_erased(id, async { Erased::new(fut.await) });
}

/// Push a type-erased message to the stack via a [`Future`]
/// Asynchronously push a type-erased message to the stack via a [`Future`]
///
/// Expects a future which, on completion, returns a message.
/// This message is then pushed to the message stack as if it were pushed
/// with [`Self::push_erased`] from widget `id`.
///
/// The future will be polled before the event loop sleeps.
/// This is a low-level variant of [`Self::push_async`].
pub fn push_async_erased<Fut>(&mut self, id: WidgetId, fut: Fut)
where
Fut: IntoFuture<Output = Erased> + 'static,
Expand All @@ -502,14 +502,14 @@ impl EventState {

/// Spawn a task, run on a thread pool
///
/// This method is similar to [`Self::push_async`], except that the future
/// is run on a worker thread (appropriate when significant CPU work is
/// required).
///
/// The future will be spawned before the event loop sleeps.
/// The future is spawned to a thread-pool before the event-handling loop
/// sleeps, and is able to wake the loop on completion. Tasks involving
/// significant CPU work should use this method over [`Self::push_async`].
///
/// Uses [`async-global-executor`].
/// See crate documentation for configuration.
/// This method is simply a wrapper around [`async_global_executor::spawn`]
/// and [`Self::push_async`]; if a different multi-threaded executor is
/// available, that may be used instead. See also [`async_global_executor`]
/// documentation of configuration.
#[cfg(feature = "spawn")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "spawn")))]
pub fn push_spawn<Fut, M>(&mut self, id: WidgetId, fut: Fut)
Expand Down
2 changes: 2 additions & 0 deletions crates/kas-resvg/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ svg = ["dep:resvg", "dep:usvg"]
tiny-skia = { version = "0.8.2" }
resvg = { version = "0.28.0", optional = true }
usvg = { version = "0.28.0", optional = true }
once_cell = "1.17.0"
thiserror = "1.0.23"

[dependencies.kas]
# We must rename this package since macros expect kas to be in scope:
Expand Down
21 changes: 9 additions & 12 deletions crates/kas-resvg/src/canvas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ pub trait CanvasProgram: std::fmt::Debug + Send + 'static {
/// Draw image
///
/// This method should draw an image to the canvas. It is called when the
/// pixmap is created and resized, when [`Canvas::redraw`] is called, and
/// when requested by [`CanvasProgram::do_redraw_animate`].
/// pixmap is created and resized and when requested by [`Self::need_redraw`].
///
/// Note that [`Layout::draw`] does not call this method, but instead draws
/// from a copy of the `pixmap` (updated each time this method completes).
fn draw(&mut self, pixmap: &mut Pixmap);

/// This method is called each time a frame is drawn. Note that since
Expand Down Expand Up @@ -88,18 +90,13 @@ impl<P: CanvasProgram> State<P> {
impl_scope! {
/// A canvas widget over the `tiny-skia` library
///
/// The widget is essentially a cached image drawn from a [`Pixmap`]
/// controlled through an implementation of [`CanvasProgram`].
/// Note that the `tiny-skia` API is re-exported as [`crate::tiny_skia`].
///
/// Canvas size is controlled by the sizing arguments passed to the constructor,
/// as well as the `stretch` factor and the display's scale factor `sf`.
/// Minimum size is `min_size * sf`. Ideal size is `ideal_size * sf` except that
/// if `fix_aspect` is true, then the ideal height is the one that preserves
/// aspect ratio for the given width. The canvas may also exceed the ideal size
/// if a [`Stretch`] factor greater than `None` is used.
///
/// The canvas (re)creates the backing pixmap when the size is set and draws
/// to the new pixmap immediately. If the canvas program is modified then
/// [`Canvas::redraw`] must be called to update the pixmap.
/// By default, a `Canvas` has a minimum size of 128x128 pixels and a high
/// stretch factor (i.e. will greedily occupy extra space). To adjust this
/// call one of the sizing/scaling methods.
#[autoimpl(Debug ignore self.inner)]
#[derive(Clone)]
#[widget]
Expand Down
Loading

0 comments on commit 05f36ee

Please sign in to comment.