Skip to content

Commit

Permalink
Start work on event handling
Browse files Browse the repository at this point in the history
  • Loading branch information
matthunz committed Nov 20, 2023
1 parent 89b40d7 commit b7640eb
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 31 deletions.
6 changes: 4 additions & 2 deletions examples/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ impl Component for Counter {
}

fn view<'a>(&mut self, bump: &'a Bump) -> impl View<'a, Self::Message> {
dbg!(self.count);

LinearLayout::new((
format_in!(bump, "High five count: {}", self.count),
LinearLayout::new((
Text::new("Up high!").on_click(Message::Increment),
Text::new("Down low!").on_click(Message::Decrement),
Text::new("Up high!").on_click(|_| Message::Increment),
Text::new("Down low!"),
)),
))
}
Expand Down
8 changes: 4 additions & 4 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::{render, Component, Element, View, AnyElement};
use crate::{render, AnyElement, Component, View};
use bumpalo::Bump;
use std::mem;

pub struct App<C> {
component: C,
element: Option<Box<dyn AnyElement>>,
pub(crate) element: Option<Box<dyn AnyElement>>,
bump: Bump,
}

Expand All @@ -25,7 +25,7 @@ impl<C> App<C> {
where
C: Component,
{
let mut view = self.component.view(&self.bump);
let view = self.component.view(&self.bump);
let view = self.bump.alloc(view);

if let Some(ref mut element) = self.element {
Expand All @@ -48,6 +48,6 @@ impl<C> App<C> {
{
self.view();

render::run(self.element.as_mut().unwrap().as_element_mut());
render::run(self);
}
}
8 changes: 7 additions & 1 deletion src/element/linear_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,19 @@ impl Element for LinearLayoutElement {
Size::default()
}

fn handle(&mut self, msg: crate::WindowMessage, output: &mut Vec<Box<dyn std::any::Any>>) {
for node in &mut self.nodes {
node.element.as_element_mut().handle(msg.clone(), output);
}
}

fn render(&mut self, canvas: &mut skia_safe::Canvas) {
let mut y = 0.;
for node in &mut self.nodes {
let size = node.element.as_element_mut().layout();

let mut surface =
surfaces::raster_n32_premul(skia_safe::ISize::new(1000, 200)).unwrap();
surfaces::raster_n32_premul(skia_safe::ISize::new(2000, 200)).unwrap();
node.element.as_element_mut().render(surface.canvas());
let image = surface.image_snapshot();
canvas.draw_image(image, skia_safe::Point::new(0., y), None);
Expand Down
14 changes: 12 additions & 2 deletions src/element/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::any::Any;

use skia_safe::Canvas;

mod linear_layout;
Expand All @@ -7,18 +9,26 @@ mod text;
use taffy::geometry::Size;
pub use text::TextElement;

use crate::WindowMessage;

pub trait Element {
fn layout(&mut self) -> Size<f64>;

fn handle(&mut self, msg: WindowMessage, output: &mut Vec<Box<dyn Any>>);

fn render(&mut self, canvas: &mut Canvas);
}

impl<T: Element + ?Sized> Element for &mut T{
impl<T: Element + ?Sized> Element for &mut T {
fn layout(&mut self) -> Size<f64> {
(&mut **self).layout()
}

fn handle(&mut self, msg: WindowMessage, output: &mut Vec<Box<dyn Any>>) {
(&mut **self).handle(msg, output)
}

fn render(&mut self, canvas: &mut Canvas) {
(&mut **self).render(canvas)
}
}
}
27 changes: 21 additions & 6 deletions src/element/text.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,44 @@
use crate::Element;
use crate::{Element, WindowMessage};
use kurbo::Point;
use skia_safe::{Color4f, Font, FontStyle, Paint, TextBlob, Typeface};
use taffy::geometry::Size;

pub struct TextElement {
pub struct TextElement<M> {
text_blob: TextBlob,
on_click: Option<Box<dyn FnMut(Point) -> M>>,
}

impl TextElement {
pub fn new(content: &str) -> Self {
impl<M> TextElement<M> {
pub fn new(content: &str, on_click: Option<Box<dyn FnMut(Point) -> M>>) -> Self {
let typeface = Typeface::new("monospace", FontStyle::default()).unwrap();
let font = Font::new(typeface, 100.);
let text_blob = TextBlob::new(content, &font).unwrap();

Self { text_blob }
Self {
text_blob,
on_click,
}
}
}

impl Element for TextElement {
impl<M: 'static> Element for TextElement<M> {
fn layout(&mut self) -> Size<f64> {
Size {
width: self.text_blob.bounds().width() as _,
height: (self.text_blob.bounds().height() / 2.) as _,
}
}

fn handle(&mut self, msg: WindowMessage, output: &mut Vec<Box<dyn std::any::Any>>) {
match msg {
WindowMessage::Click { position } => {
if let Some(ref mut f) = self.on_click {
output.push(Box::new(f(position)));
}
}
}
}

fn render(&mut self, canvas: &mut skia_safe::Canvas) {
let paint = Paint::new(Color4f::new(1., 0., 0., 1.), None);
canvas.draw_text_blob(
Expand Down
13 changes: 9 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ mod element;
pub use element::Element;

mod view;
use kurbo::Point;

pub use view::{LinearLayout, Text, View};

mod view_group;
Expand All @@ -33,16 +35,14 @@ macro_rules! format_in {
};
}


pub trait Component {
type Message;
type Message: 'static;

fn update(&mut self, msg: Self::Message);

fn view<'a>(&mut self, bump: &'a Bump) -> impl View<'a, Self::Message> ;
fn view<'a>(&mut self, bump: &'a Bump) -> impl View<'a, Self::Message>;
}


pub fn run(component: impl Component) {
let mut app = App::new(component);
app.run();
Expand All @@ -59,3 +59,8 @@ impl Node {
}
}
}

#[derive(Clone)]
pub enum WindowMessage {
Click { position: Point },
}
31 changes: 28 additions & 3 deletions src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use glutin::{
surface::{Surface as GlutinSurface, SurfaceAttributesBuilder, WindowSurface},
};
use glutin_winit::DisplayBuilder;
use kurbo::Point;
use raw_window_handle::HasRawWindowHandle;
use std::{
ffi::CString,
Expand All @@ -20,13 +21,13 @@ use winit::{
window::{Window, WindowBuilder},
};

use crate::Element;
use crate::{App, Component, Element};
use skia_safe::{
gpu::{self, backend_render_targets, gl::FramebufferInfo, SurfaceOrigin},
Color, ColorType, Surface,
};

pub fn run(element: &mut (impl Element + ?Sized)) {
pub fn run<C: Component>(app: &mut App<C>) {
let el = EventLoop::new().expect("Failed to create event loop");
let winit_window_builder = WindowBuilder::new()
.with_title("rust-skia-gl-window")
Expand Down Expand Up @@ -226,6 +227,26 @@ pub fn run(element: &mut (impl Element + ?Sized)) {
WindowEvent::RedrawRequested => {
draw_frame = true;
}
WindowEvent::MouseInput {
device_id: _,
state: _,
button: _,
} => {
let mut outputs = Vec::new();
app.element.as_mut().unwrap().as_element_mut().handle(
crate::WindowMessage::Click {
position: Point::default(),
},
&mut outputs,
);
let is_empty = outputs.is_empty();
for output in outputs {
app.handle(*output.downcast().unwrap());
}
if !is_empty {
app.view();
}
}
_ => (),
}
}
Expand All @@ -241,7 +262,11 @@ pub fn run(element: &mut (impl Element + ?Sized)) {
let canvas = env.surface.canvas();
canvas.clear(Color::WHITE);

element.render(canvas);
app.element
.as_mut()
.unwrap()
.as_element_mut()
.render(canvas);

env.gr_context.flush_and_submit();
env.gl_surface.swap_buffers(&env.gl_context).unwrap();
Expand Down
9 changes: 6 additions & 3 deletions src/view/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ pub trait View<'a, M> {
fn handle(&'a mut self, msg: M);
}

impl<'a, M> View<'a, M> for &'a str {
type Element = TextElement;
impl<'a, M> View<'a, M> for &'a str
where
M: 'static,
{
type Element = TextElement<M>;

fn build(&'a mut self) -> Self::Element {
TextElement::new(self)
TextElement::new(self, None)
}

fn rebuild(&'a mut self, _element: &mut Self::Element) {
Expand Down
17 changes: 11 additions & 6 deletions src/view/text.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use kurbo::Point;

use crate::{element::TextElement, View};
use std::borrow::Cow;

pub struct Text<'a, M> {
content: Cow<'a, str>,
on_click: Option<M>,
on_click: Option<Box<dyn FnMut(Point) -> M>>,
}

impl<'a, M> Text<'a, M> {
Expand All @@ -14,17 +16,20 @@ impl<'a, M> Text<'a, M> {
}
}

pub fn on_click(mut self, msg: M) -> Self {
self.on_click = Some(msg);
pub fn on_click(mut self, f: impl FnMut(Point) -> M + 'static) -> Self {
self.on_click = Some(Box::new(f));
self
}
}

impl<'a, M> View<'a, M> for Text<'a, M> {
type Element = TextElement;
impl<'a, M> View<'a, M> for Text<'a, M>
where
M: 'static,
{
type Element = TextElement<M>;

fn build(&'a mut self) -> Self::Element {
TextElement::new(&self.content)
TextElement::new(&self.content, self.on_click.take())
}

fn rebuild(&'a mut self, _element: &mut Self::Element) {}
Expand Down

0 comments on commit b7640eb

Please sign in to comment.