summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2019-10-09 05:36:49 +0200
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2019-10-09 05:36:49 +0200
commita92a0b73ed7ed935df762d06c4249894fd35b227 (patch)
treefe5f67c3b7c2cc84d29e5345e02463f0b4ef6913
parent1a93f0ef4a669f37654efcf2102a9d59ada34f9e (diff)
downloadiced-a92a0b73ed7ed935df762d06c4249894fd35b227.tar.gz
iced-a92a0b73ed7ed935df762d06c4249894fd35b227.tar.bz2
iced-a92a0b73ed7ed935df762d06c4249894fd35b227.zip
Move `winit` logic from `iced` to `iced_winit`
- Added new `renderer::Windowed` trait. This shoud allow users to easily try different renderers by simply changing one line. - Renamed `UserInterface` traits to `Application`, as the `run` method takes total control of the current thread. - Moved `MouseCursor` back to `iced_native`. The new `renderer::Windowed` trait returns one on `draw`. - Split `iced_native` renderer in multiple modules, for consistency.
-rw-r--r--examples/tour.rs8
-rw-r--r--native/Cargo.toml1
-rw-r--r--native/src/lib.rs2
-rw-r--r--native/src/mouse_cursor.rs (renamed from wgpu/src/mouse_cursor.rs)0
-rw-r--r--native/src/renderer.rs39
-rw-r--r--native/src/renderer/debugger.rs25
-rw-r--r--native/src/renderer/windowed.rs17
-rw-r--r--src/lib.rs122
-rw-r--r--web/src/bus.rs4
-rw-r--r--web/src/lib.rs18
-rw-r--r--wgpu/src/lib.rs2
-rw-r--r--wgpu/src/renderer.rs36
-rw-r--r--winit/src/lib.rs126
13 files changed, 245 insertions, 155 deletions
diff --git a/examples/tour.rs b/examples/tour.rs
index 542efc66..6ce1e9f1 100644
--- a/examples/tour.rs
+++ b/examples/tour.rs
@@ -1,7 +1,7 @@
use iced::{
- button, slider, text::HorizontalAlignment, Align, Background, Button,
- Checkbox, Color, Column, Element, Image, Justify, Length, Radio, Row,
- Slider, Text, UserInterface,
+ button, slider, text::HorizontalAlignment, Align, Application, Background,
+ Button, Checkbox, Color, Column, Element, Image, Justify, Length, Radio,
+ Row, Slider, Text,
};
pub fn main() {
@@ -30,7 +30,7 @@ impl Tour {
}
}
-impl UserInterface for Tour {
+impl Application for Tour {
type Message = Message;
fn update(&mut self, event: Message) {
diff --git a/native/Cargo.toml b/native/Cargo.toml
index 5f7e5e41..07c14535 100644
--- a/native/Cargo.toml
+++ b/native/Cargo.toml
@@ -14,6 +14,7 @@ features = ["winit"]
iced_core = { version = "0.1.0-alpha", path = "../core" }
stretch = "0.2"
twox-hash = "1.5"
+raw-window-handle = "0.1"
# Enable to obtain conversion traits
winit = { version = "0.20.0-alpha3", optional = true }
diff --git a/native/src/lib.rs b/native/src/lib.rs
index 18ce3a37..cada56f9 100644
--- a/native/src/lib.rs
+++ b/native/src/lib.rs
@@ -206,6 +206,7 @@ mod element;
mod event;
mod hasher;
mod layout;
+mod mouse_cursor;
mod node;
mod style;
mod user_interface;
@@ -223,6 +224,7 @@ pub use element::Element;
pub use event::Event;
pub use hasher::Hasher;
pub use layout::Layout;
+pub use mouse_cursor::MouseCursor;
pub use node::Node;
pub use renderer::Renderer;
pub use style::Style;
diff --git a/wgpu/src/mouse_cursor.rs b/native/src/mouse_cursor.rs
index 4ef6361a..4ef6361a 100644
--- a/wgpu/src/mouse_cursor.rs
+++ b/native/src/mouse_cursor.rs
diff --git a/native/src/renderer.rs b/native/src/renderer.rs
index d16a0289..a56d7b76 100644
--- a/native/src/renderer.rs
+++ b/native/src/renderer.rs
@@ -1,8 +1,10 @@
//! Write your own renderer.
//!
-//! There is not a common entrypoint or trait for a __renderer__ in Iced.
-//! Instead, every [`Widget`] constrains its generic `Renderer` type as
-//! necessary.
+//! You will need to implement the `Renderer` trait first. It simply contains
+//! a `Primitive` associated type.
+//!
+//! There is no common trait to draw all the widgets. Instead, every [`Widget`]
+//! constrains its generic `Renderer` type as necessary.
//!
//! This approach is flexible and composable. For instance, the
//! [`Text`] widget only needs a [`text::Renderer`] while a [`Checkbox`] widget
@@ -17,32 +19,13 @@
//! [`text::Renderer`]: ../widget/text/trait.Renderer.html
//! [`Checkbox`]: ../widget/checkbox/struct.Checkbox.html
//! [`checkbox::Renderer`]: ../widget/checkbox/trait.Renderer.html
-use crate::{Color, Layout, Point, Widget};
+
+mod debugger;
+mod windowed;
+
+pub use debugger::Debugger;
+pub use windowed::Windowed;
pub trait Renderer {
type Primitive;
}
-
-/// A renderer able to graphically explain a [`Layout`].
-///
-/// [`Layout`]: ../struct.Layout.html
-pub trait Debugger: Renderer {
- /// Explains the [`Layout`] of an [`Element`] for debugging purposes.
- ///
- /// This will be called when [`Element::explain`] has been used. It should
- /// _explain_ the given [`Layout`] graphically.
- ///
- /// A common approach consists in recursively rendering the bounds of the
- /// [`Layout`] and its children.
- ///
- /// [`Layout`]: struct.Layout.html
- /// [`Element`]: struct.Element.html
- /// [`Element::explain`]: struct.Element.html#method.explain
- fn explain<Message>(
- &mut self,
- widget: &dyn Widget<Message, Self>,
- layout: Layout<'_>,
- cursor_position: Point,
- color: Color,
- ) -> Self::Primitive;
-}
diff --git a/native/src/renderer/debugger.rs b/native/src/renderer/debugger.rs
new file mode 100644
index 00000000..cb472dd4
--- /dev/null
+++ b/native/src/renderer/debugger.rs
@@ -0,0 +1,25 @@
+use crate::{Color, Layout, Point, Widget};
+
+/// A renderer able to graphically explain a [`Layout`].
+///
+/// [`Layout`]: ../struct.Layout.html
+pub trait Debugger: super::Renderer {
+ /// Explains the [`Layout`] of an [`Element`] for debugging purposes.
+ ///
+ /// This will be called when [`Element::explain`] has been used. It should
+ /// _explain_ the given [`Layout`] graphically.
+ ///
+ /// A common approach consists in recursively rendering the bounds of the
+ /// [`Layout`] and its children.
+ ///
+ /// [`Layout`]: struct.Layout.html
+ /// [`Element`]: struct.Element.html
+ /// [`Element::explain`]: struct.Element.html#method.explain
+ fn explain<Message>(
+ &mut self,
+ widget: &dyn Widget<Message, Self>,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ color: Color,
+ ) -> Self::Primitive;
+}
diff --git a/native/src/renderer/windowed.rs b/native/src/renderer/windowed.rs
new file mode 100644
index 00000000..f89da40b
--- /dev/null
+++ b/native/src/renderer/windowed.rs
@@ -0,0 +1,17 @@
+use crate::MouseCursor;
+
+use raw_window_handle::HasRawWindowHandle;
+
+pub trait Windowed: super::Renderer {
+ type Target;
+
+ fn new<W: HasRawWindowHandle>(window: &W) -> Self;
+
+ fn target(&self, width: u16, height: u16) -> Self::Target;
+
+ fn draw(
+ &mut self,
+ target: &mut Self::Target,
+ primitive: &Self::Primitive,
+ ) -> MouseCursor;
+}
diff --git a/src/lib.rs b/src/lib.rs
index 2e65ed6c..46574285 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -9,123 +9,35 @@ pub type Row<'a, Message> = iced_winit::Row<'a, Message, Renderer>;
pub type Column<'a, Message> = iced_winit::Column<'a, Message, Renderer>;
pub type Button<'a, Message> = iced_winit::Button<'a, Message, Renderer>;
-pub trait UserInterface {
+pub trait Application {
type Message;
fn update(&mut self, message: Self::Message);
fn view(&mut self) -> Element<Self::Message>;
- fn run(mut self)
+ fn run(self)
where
Self: 'static + Sized,
{
- use winit::{
- event::{Event, WindowEvent},
- event_loop::{ControlFlow, EventLoop},
- window::WindowBuilder,
- };
-
- let event_loop = EventLoop::new();
-
- // TODO: Ask for window settings and configure this properly
- let window = WindowBuilder::new()
- .build(&event_loop)
- .expect("Open window");
-
- let size = window.inner_size().to_physical(window.hidpi_factor());;
- let (width, height) = (size.width as u16, size.height as u16);
-
- let mut renderer = Renderer::new(&window);
- let mut target = renderer.target(width, height);
-
- let user_interface = iced_winit::UserInterface::build(
- document(&mut self, width, height),
- iced_winit::Cache::default(),
- &mut renderer,
- );
-
- let mut primitive = user_interface.draw(&mut renderer);
- let mut cache = Some(user_interface.into_cache());
- let mut events = Vec::new();
-
- window.request_redraw();
-
- event_loop.run(move |event, _, control_flow| match event {
- Event::EventsCleared => {
- // TODO: We should be able to keep a user interface alive
- // between events once we remove state references.
- //
- // This will allow us to rebuild it only when a message is
- // handled.
- let mut user_interface = iced_winit::UserInterface::build(
- document(&mut self, width, height),
- cache.take().unwrap(),
- &mut renderer,
- );
-
- let messages = user_interface.update(events.drain(..));
-
- if messages.is_empty() {
- primitive = user_interface.draw(&mut renderer);
-
- cache = Some(user_interface.into_cache());
- } else {
- // When there are messages, we are forced to rebuild twice
- // for now :^)
- let temp_cache = user_interface.into_cache();
-
- for message in messages {
- self.update(message);
- }
-
- let user_interface = iced_winit::UserInterface::build(
- document(&mut self, width, height),
- temp_cache,
- &mut renderer,
- );
-
- primitive = user_interface.draw(&mut renderer);
-
- cache = Some(user_interface.into_cache());
- }
-
- window.request_redraw();
- }
- Event::WindowEvent {
- event: WindowEvent::RedrawRequested,
- ..
- } => {
- renderer.draw(&mut target, &primitive);
-
- // TODO: Handle animations!
- // Maybe we can use `ControlFlow::WaitUntil` for this.
- }
- Event::WindowEvent {
- event: WindowEvent::CloseRequested,
- ..
- } => {
- *control_flow = ControlFlow::Exit;
- }
- _ => {
- *control_flow = ControlFlow::Wait;
- }
- })
+ iced_winit::Application::run(Instance(self))
}
}
-fn document<UserInterface>(
- user_interface: &mut UserInterface,
- width: u16,
- height: u16,
-) -> Element<UserInterface::Message>
+struct Instance<A: Application>(A);
+
+impl<A> iced_winit::Application for Instance<A>
where
- UserInterface: self::UserInterface,
- UserInterface::Message: 'static,
+ A: Application,
{
- Column::new()
- .width(Length::Units(width))
- .height(Length::Units(height))
- .push(user_interface.view())
- .into()
+ type Renderer = Renderer;
+ type Message = A::Message;
+
+ fn update(&mut self, message: Self::Message) {
+ self.0.update(message);
+ }
+
+ fn view(&mut self) -> Element<Self::Message> {
+ self.0.view()
+ }
}
diff --git a/web/src/bus.rs b/web/src/bus.rs
index d76466f5..b4fd67c7 100644
--- a/web/src/bus.rs
+++ b/web/src/bus.rs
@@ -1,4 +1,4 @@
-use crate::Application;
+use crate::Instance;
use std::rc::Rc;
@@ -14,7 +14,7 @@ where
pub fn new() -> Self {
Self {
publish: Rc::new(Box::new(|message, root| {
- let app = root.unwrap_mut::<Application<Message>>();
+ let app = root.unwrap_mut::<Instance<Message>>();
app.update(message)
})),
diff --git a/web/src/lib.rs b/web/src/lib.rs
index caf17df5..04848d07 100644
--- a/web/src/lib.rs
+++ b/web/src/lib.rs
@@ -11,7 +11,7 @@ pub use element::Element;
pub use iced_core::{Align, Color, Justify, Length};
pub use widget::*;
-pub trait UserInterface {
+pub trait Application {
type Message;
fn update(
@@ -25,23 +25,23 @@ pub trait UserInterface {
where
Self: 'static + Sized,
{
+ let app = Instance::new(self);
+
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let body = document.body().unwrap();
-
- let app = Application::new(self);
-
let vdom = dodrio::Vdom::new(&body, app);
+
vdom.forget();
}
}
-struct Application<Message> {
- ui: RefCell<Box<dyn UserInterface<Message = Message>>>,
+struct Instance<Message> {
+ ui: RefCell<Box<dyn Application<Message = Message>>>,
}
-impl<Message> Application<Message> {
- fn new(ui: impl UserInterface<Message = Message> + 'static) -> Self {
+impl<Message> Instance<Message> {
+ fn new(ui: impl Application<Message = Message> + 'static) -> Self {
Self {
ui: RefCell::new(Box::new(ui)),
}
@@ -55,7 +55,7 @@ impl<Message> Application<Message> {
}
}
-impl<Message> dodrio::Render for Application<Message>
+impl<Message> dodrio::Render for Instance<Message>
where
Message: 'static,
{
diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs
index 8f8d50e9..46849aab 100644
--- a/wgpu/src/lib.rs
+++ b/wgpu/src/lib.rs
@@ -1,4 +1,3 @@
-mod mouse_cursor;
mod primitive;
mod quad;
mod renderer;
@@ -7,6 +6,5 @@ mod transformation;
pub(crate) use quad::Quad;
pub(crate) use transformation::Transformation;
-pub use mouse_cursor::MouseCursor;
pub use primitive::Primitive;
pub use renderer::{Renderer, Target};
diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs
index ae5692e3..036efd27 100644
--- a/wgpu/src/renderer.rs
+++ b/wgpu/src/renderer.rs
@@ -1,6 +1,7 @@
use crate::{quad, Primitive, Quad, Transformation};
use iced_native::{
- renderer::Debugger, Background, Color, Layout, Point, Widget,
+ renderer::Debugger, renderer::Windowed, Background, Color, Layout,
+ MouseCursor, Point, Widget,
};
use raw_window_handle::HasRawWindowHandle;
@@ -41,7 +42,7 @@ pub struct Target {
}
impl Renderer {
- pub fn new<W: HasRawWindowHandle>(window: &W) -> Self {
+ fn new<W: HasRawWindowHandle>(window: &W) -> Self {
let adapter = Adapter::request(&RequestAdapterOptions {
power_preference: PowerPreference::LowPower,
backends: BackendBit::all(),
@@ -79,7 +80,7 @@ impl Renderer {
}
}
- pub fn target(&self, width: u16, height: u16) -> Target {
+ fn target(&self, width: u16, height: u16) -> Target {
Target {
width,
height,
@@ -97,7 +98,11 @@ impl Renderer {
}
}
- pub fn draw(&mut self, target: &mut Target, primitive: &Primitive) {
+ fn draw(
+ &mut self,
+ target: &mut Target,
+ primitive: &Primitive,
+ ) -> MouseCursor {
log::debug!("Drawing");
let frame = target.swap_chain.get_next_texture();
@@ -146,8 +151,9 @@ impl Renderer {
.expect("Draw text");
self.queue.submit(&[encoder.finish()]);
- }
+ MouseCursor::OutOfBounds
+ }
fn draw_primitive(&mut self, primitive: &Primitive) {
match primitive {
Primitive::None => {}
@@ -240,6 +246,26 @@ impl iced_native::Renderer for Renderer {
type Primitive = Primitive;
}
+impl Windowed for Renderer {
+ type Target = Target;
+
+ fn new<W: HasRawWindowHandle>(window: &W) -> Self {
+ Self::new(window)
+ }
+
+ fn target(&self, width: u16, height: u16) -> Target {
+ self.target(width, height)
+ }
+
+ fn draw(
+ &mut self,
+ target: &mut Target,
+ primitive: &Primitive,
+ ) -> MouseCursor {
+ self.draw(target, primitive)
+ }
+}
+
impl Debugger for Renderer {
fn explain<Message>(
&mut self,
diff --git a/winit/src/lib.rs b/winit/src/lib.rs
index 54a0bd9a..93e922d5 100644
--- a/winit/src/lib.rs
+++ b/winit/src/lib.rs
@@ -1,2 +1,128 @@
pub use iced_native::*;
pub use winit;
+
+pub use iced_native::renderer::Windowed;
+
+pub trait Application {
+ type Renderer: iced_native::renderer::Windowed
+ + iced_native::column::Renderer;
+
+ type Message;
+
+ fn update(&mut self, message: Self::Message);
+
+ fn view(&mut self) -> Element<Self::Message, Self::Renderer>;
+
+ fn run(mut self)
+ where
+ Self: 'static + Sized,
+ {
+ use winit::{
+ event::{Event, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ window::WindowBuilder,
+ };
+
+ let event_loop = EventLoop::new();
+
+ // TODO: Ask for window settings and configure this properly
+ let window = WindowBuilder::new()
+ .build(&event_loop)
+ .expect("Open window");
+
+ let size = window.inner_size().to_physical(window.hidpi_factor());;
+ let (width, height) = (size.width as u16, size.height as u16);
+
+ let mut renderer = Self::Renderer::new(&window);
+ let mut target = renderer.target(width, height);
+
+ let user_interface = UserInterface::build(
+ document(&mut self, width, height),
+ Cache::default(),
+ &mut renderer,
+ );
+
+ let mut primitive = user_interface.draw(&mut renderer);
+ let mut cache = Some(user_interface.into_cache());
+ let mut events = Vec::new();
+
+ window.request_redraw();
+
+ event_loop.run(move |event, _, control_flow| match event {
+ Event::EventsCleared => {
+ // TODO: We should be able to keep a user interface alive
+ // between events once we remove state references.
+ //
+ // This will allow us to rebuild it only when a message is
+ // handled.
+ let mut user_interface = UserInterface::build(
+ document(&mut self, width, height),
+ cache.take().unwrap(),
+ &mut renderer,
+ );
+
+ let messages = user_interface.update(events.drain(..));
+
+ if messages.is_empty() {
+ primitive = user_interface.draw(&mut renderer);
+
+ cache = Some(user_interface.into_cache());
+ } else {
+ // When there are messages, we are forced to rebuild twice
+ // for now :^)
+ let temp_cache = user_interface.into_cache();
+
+ for message in messages {
+ self.update(message);
+ }
+
+ let user_interface = UserInterface::build(
+ document(&mut self, width, height),
+ temp_cache,
+ &mut renderer,
+ );
+
+ primitive = user_interface.draw(&mut renderer);
+
+ cache = Some(user_interface.into_cache());
+ }
+
+ window.request_redraw();
+ }
+ Event::WindowEvent {
+ event: WindowEvent::RedrawRequested,
+ ..
+ } => {
+ renderer.draw(&mut target, &primitive);
+
+ // TODO: Handle animations!
+ // Maybe we can use `ControlFlow::WaitUntil` for this.
+ }
+ Event::WindowEvent {
+ event: WindowEvent::CloseRequested,
+ ..
+ } => {
+ *control_flow = ControlFlow::Exit;
+ }
+ _ => {
+ *control_flow = ControlFlow::Wait;
+ }
+ })
+ }
+}
+
+fn document<Application>(
+ application: &mut Application,
+ width: u16,
+ height: u16,
+) -> Element<Application::Message, Application::Renderer>
+where
+ Application: self::Application,
+ Application::Message: 'static,
+{
+ Column::new()
+ .width(Length::Units(width))
+ .height(Length::Units(height))
+ .push(application.view())
+ .into()
+}