Remove trait-specific draw logic in iced_native

This commit is contained in:
Héctor Ramón Jiménez 2021-10-14 16:07:22 +07:00
parent 3aae45c191
commit 03b3493138
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
71 changed files with 641 additions and 3126 deletions

View file

@ -11,8 +11,7 @@ mod circle {
// implemented by `iced_wgpu` and other renderers. // implemented by `iced_wgpu` and other renderers.
use iced_graphics::{Backend, Defaults, Primitive, Renderer}; use iced_graphics::{Backend, Defaults, Primitive, Renderer};
use iced_native::{ use iced_native::{
layout, mouse, Background, Color, Element, Hasher, Layout, Length, layout, Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget,
Point, Rectangle, Size, Widget,
}; };
pub struct Circle { pub struct Circle {
@ -55,20 +54,20 @@ mod circle {
&self, &self,
_renderer: &mut Renderer<B>, _renderer: &mut Renderer<B>,
_defaults: &Defaults, _defaults: &Defaults,
layout: Layout<'_>, _layout: Layout<'_>,
_cursor_position: Point, _cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> (Primitive, mouse::Interaction) { ) {
( // (
Primitive::Quad { // Primitive::Quad {
bounds: layout.bounds(), // bounds: layout.bounds(),
background: Background::Color(Color::BLACK), // background: Background::Color(Color::BLACK),
border_radius: self.radius, // border_radius: self.radius,
border_width: 0.0, // border_width: 0.0,
border_color: Color::TRANSPARENT, // border_color: Color::TRANSPARENT,
}, // },
mouse::Interaction::default(), // mouse::Interaction::default(),
) // )
} }
} }

View file

@ -55,98 +55,99 @@ mod rainbow {
&self, &self,
_renderer: &mut Renderer<B>, _renderer: &mut Renderer<B>,
_defaults: &Defaults, _defaults: &Defaults,
layout: Layout<'_>, _layout: Layout<'_>,
cursor_position: Point, _cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> (Primitive, mouse::Interaction) { ) {
let b = layout.bounds(); // let b = layout.bounds();
// R O Y G B I V // // R O Y G B I V
let color_r = [1.0, 0.0, 0.0, 1.0]; // let color_r = [1.0, 0.0, 0.0, 1.0];
let color_o = [1.0, 0.5, 0.0, 1.0]; // let color_o = [1.0, 0.5, 0.0, 1.0];
let color_y = [1.0, 1.0, 0.0, 1.0]; // let color_y = [1.0, 1.0, 0.0, 1.0];
let color_g = [0.0, 1.0, 0.0, 1.0]; // let color_g = [0.0, 1.0, 0.0, 1.0];
let color_gb = [0.0, 1.0, 0.5, 1.0]; // let color_gb = [0.0, 1.0, 0.5, 1.0];
let color_b = [0.0, 0.2, 1.0, 1.0]; // let color_b = [0.0, 0.2, 1.0, 1.0];
let color_i = [0.5, 0.0, 1.0, 1.0]; // let color_i = [0.5, 0.0, 1.0, 1.0];
let color_v = [0.75, 0.0, 0.5, 1.0]; // let color_v = [0.75, 0.0, 0.5, 1.0];
let posn_center = { // let posn_center = {
if b.contains(cursor_position) { // if b.contains(cursor_position) {
[cursor_position.x - b.x, cursor_position.y - b.y] // [cursor_position.x - b.x, cursor_position.y - b.y]
} else { // } else {
[b.width / 2.0, b.height / 2.0] // [b.width / 2.0, b.height / 2.0]
} // }
}; // };
let posn_tl = [0.0, 0.0]; // let posn_tl = [0.0, 0.0];
let posn_t = [b.width / 2.0, 0.0]; // let posn_t = [b.width / 2.0, 0.0];
let posn_tr = [b.width, 0.0]; // let posn_tr = [b.width, 0.0];
let posn_r = [b.width, b.height / 2.0]; // let posn_r = [b.width, b.height / 2.0];
let posn_br = [b.width, b.height]; // let posn_br = [b.width, b.height];
let posn_b = [(b.width / 2.0), b.height]; // let posn_b = [(b.width / 2.0), b.height];
let posn_bl = [0.0, b.height]; // let posn_bl = [0.0, b.height];
let posn_l = [0.0, b.height / 2.0]; // let posn_l = [0.0, b.height / 2.0];
( // (
Primitive::Translate { // Primitive::Translate {
translation: Vector::new(b.x, b.y), // translation: Vector::new(b.x, b.y),
content: Box::new(Primitive::Mesh2D { // content: Box::new(Primitive::Mesh2D {
size: b.size(), // size: b.size(),
buffers: Mesh2D { // buffers: Mesh2D {
vertices: vec![ // vertices: vec![
Vertex2D { // Vertex2D {
position: posn_center, // position: posn_center,
color: [1.0, 1.0, 1.0, 1.0], // color: [1.0, 1.0, 1.0, 1.0],
}, // },
Vertex2D { // Vertex2D {
position: posn_tl, // position: posn_tl,
color: color_r, // color: color_r,
}, // },
Vertex2D { // Vertex2D {
position: posn_t, // position: posn_t,
color: color_o, // color: color_o,
}, // },
Vertex2D { // Vertex2D {
position: posn_tr, // position: posn_tr,
color: color_y, // color: color_y,
}, // },
Vertex2D { // Vertex2D {
position: posn_r, // position: posn_r,
color: color_g, // color: color_g,
}, // },
Vertex2D { // Vertex2D {
position: posn_br, // position: posn_br,
color: color_gb, // color: color_gb,
}, // },
Vertex2D { // Vertex2D {
position: posn_b, // position: posn_b,
color: color_b, // color: color_b,
}, // },
Vertex2D { // Vertex2D {
position: posn_bl, // position: posn_bl,
color: color_i, // color: color_i,
}, // },
Vertex2D { // Vertex2D {
position: posn_l, // position: posn_l,
color: color_v, // color: color_v,
}, // },
], // ],
indices: vec![ // indices: vec![
0, 1, 2, // TL // 0, 1, 2, // TL
0, 2, 3, // T // 0, 2, 3, // T
0, 3, 4, // TR // 0, 3, 4, // TR
0, 4, 5, // R // 0, 4, 5, // R
0, 5, 6, // BR // 0, 5, 6, // BR
0, 6, 7, // B // 0, 6, 7, // B
0, 7, 8, // BL // 0, 7, 8, // BL
0, 8, 1, // L // 0, 8, 1, // L
], // ],
}, // },
}), // }),
}, // },
mouse::Interaction::default(), // mouse::Interaction::default(),
) // )
// TODO
} }
} }

View file

@ -160,18 +160,22 @@ pub fn main() {
} }
// And then iced on top // And then iced on top
let mouse_interaction = renderer.backend_mut().draw( renderer.present(|backend, primitive| {
&gl, backend.present(
&viewport, &gl,
state.primitive(), primitive,
&debug.overlay(), &viewport,
); &debug.overlay(),
);
});
// Update the mouse cursor // Update the mouse cursor
windowed_context.window().set_cursor_icon( // TODO
iced_winit::conversion::mouse_interaction( // windowed_context.window().set_cursor_icon(
mouse_interaction, // iced_winit::conversion::mouse_interaction(
), // mouse_interaction,
); // ),
// );
windowed_context.swap_buffers().unwrap(); windowed_context.swap_buffers().unwrap();
} }

View file

@ -195,26 +195,28 @@ pub fn main() {
} }
// And then iced on top // And then iced on top
let mouse_interaction = renderer.backend_mut().draw( renderer.present(|backend, primitive| {
&mut device, backend.present(
&mut staging_belt, &mut device,
&mut encoder, &mut staging_belt,
&view, &mut encoder,
&viewport, &view,
state.primitive(), primitive,
&debug.overlay(), &viewport,
); &debug.overlay(),
);
});
// Then we submit the work // Then we submit the work
staging_belt.finish(); staging_belt.finish();
queue.submit(Some(encoder.finish())); queue.submit(Some(encoder.finish()));
// Update the mouse cursor // Update the mouse cursor
window.set_cursor_icon( // window.set_cursor_icon(
iced_winit::conversion::mouse_interaction( // iced_winit::conversion::mouse_interaction(
mouse_interaction, // mouse_interaction,
), // ),
); // );
// And recall staging buffers // And recall staging buffers
local_pool local_pool

View file

@ -5,10 +5,8 @@ use crate::{Settings, Transformation, Viewport};
use iced_graphics::backend; use iced_graphics::backend;
use iced_graphics::font; use iced_graphics::font;
use iced_graphics::Layer; use iced_graphics::{Layer, Primitive};
use iced_graphics::Primitive;
use iced_native::alignment; use iced_native::alignment;
use iced_native::mouse;
use iced_native::{Font, Size}; use iced_native::{Font, Size};
/// A [`glow`] graphics backend for [`iced`]. /// A [`glow`] graphics backend for [`iced`].
@ -47,13 +45,13 @@ impl Backend {
/// ///
/// The text provided as overlay will be rendered on top of the primitives. /// The text provided as overlay will be rendered on top of the primitives.
/// This is useful for rendering debug information. /// This is useful for rendering debug information.
pub fn draw<T: AsRef<str>>( pub fn present<T: AsRef<str>>(
&mut self, &mut self,
gl: &glow::Context, gl: &glow::Context,
primitive: &Primitive,
viewport: &Viewport, viewport: &Viewport,
(primitive, mouse_interaction): &(Primitive, mouse::Interaction),
overlay_text: &[T], overlay_text: &[T],
) -> mouse::Interaction { ) {
let viewport_size = viewport.physical_size(); let viewport_size = viewport.physical_size();
let scale_factor = viewport.scale_factor() as f32; let scale_factor = viewport.scale_factor() as f32;
let projection = viewport.projection(); let projection = viewport.projection();
@ -70,8 +68,6 @@ impl Backend {
viewport_size.height, viewport_size.height,
); );
} }
*mouse_interaction
} }
fn flush( fn flush(

View file

@ -3,7 +3,6 @@ use crate::{Backend, Color, Error, Renderer, Settings, Viewport};
use core::ffi::c_void; use core::ffi::c_void;
use glow::HasContext; use glow::HasContext;
use iced_graphics::{Antialiasing, Size}; use iced_graphics::{Antialiasing, Size};
use iced_native::mouse;
/// A window graphics backend for iced powered by `glow`. /// A window graphics backend for iced powered by `glow`.
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
@ -59,14 +58,13 @@ impl iced_graphics::window::GLCompositor for Compositor {
} }
} }
fn draw<T: AsRef<str>>( fn present<T: AsRef<str>>(
&mut self, &mut self,
renderer: &mut Self::Renderer, renderer: &mut Self::Renderer,
viewport: &Viewport, viewport: &Viewport,
color: Color, color: Color,
output: &<Self::Renderer as iced_native::Renderer>::Output,
overlay: &[T], overlay: &[T],
) -> mouse::Interaction { ) {
let gl = &self.gl; let gl = &self.gl;
let [r, g, b, a] = color.into_linear(); let [r, g, b, a] = color.into_linear();
@ -76,6 +74,8 @@ impl iced_graphics::window::GLCompositor for Compositor {
gl.clear(glow::COLOR_BUFFER_BIT); gl.clear(glow::COLOR_BUFFER_BIT);
} }
renderer.backend_mut().draw(gl, viewport, output, overlay) renderer.present(|backend, primitive| {
backend.present(gl, primitive, viewport, overlay);
});
} }
} }

View file

@ -1,5 +1,5 @@
//! Create interactive, native cross-platform applications. //! Create interactive, native cross-platform applications.
use crate::{mouse, Error, Executor, Runtime}; use crate::{Error, Executor, Runtime};
pub use iced_winit::Application; pub use iced_winit::Application;
@ -179,9 +179,8 @@ async fn run_instance<A, E, C>(
&mut debug, &mut debug,
)); ));
let mut primitive = // TODO
user_interface.draw(&mut renderer, state.cursor_position()); // let mut mouse_interaction = mouse::Interaction::default();
let mut mouse_interaction = mouse::Interaction::default();
let mut events = Vec::new(); let mut events = Vec::new();
let mut messages = Vec::new(); let mut messages = Vec::new();
@ -246,8 +245,7 @@ async fn run_instance<A, E, C>(
} }
debug.draw_started(); debug.draw_started();
primitive = user_interface.draw(&mut renderer, state.cursor_position());
user_interface.draw(&mut renderer, state.cursor_position());
debug.draw_finished(); debug.draw_finished();
context.window().request_redraw(); context.window().request_redraw();
@ -291,8 +289,7 @@ async fn run_instance<A, E, C>(
debug.layout_finished(); debug.layout_finished();
debug.draw_started(); debug.draw_started();
primitive = user_interface user_interface.draw(&mut renderer, state.cursor_position());
.draw(&mut renderer, state.cursor_position());
debug.draw_finished(); debug.draw_finished();
context.resize(glutin::dpi::PhysicalSize::new( context.resize(glutin::dpi::PhysicalSize::new(
@ -305,11 +302,10 @@ async fn run_instance<A, E, C>(
viewport_version = current_viewport_version; viewport_version = current_viewport_version;
} }
let new_mouse_interaction = compositor.draw( compositor.present(
&mut renderer, &mut renderer,
state.viewport(), state.viewport(),
state.background_color(), state.background_color(),
&primitive,
&debug.overlay(), &debug.overlay(),
); );
@ -317,14 +313,6 @@ async fn run_instance<A, E, C>(
debug.render_finished(); debug.render_finished();
if new_mouse_interaction != mouse_interaction {
context.window().set_cursor_icon(
conversion::mouse_interaction(new_mouse_interaction),
);
mouse_interaction = new_mouse_interaction;
}
// TODO: Handle animations! // TODO: Handle animations!
// Maybe we can use `ControlFlow::WaitUntil` for this. // Maybe we can use `ControlFlow::WaitUntil` for this.
} }

View file

@ -4,7 +4,7 @@
//! ![The native path of the Iced ecosystem](https://github.com/hecrj/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/native.png?raw=true) //! ![The native path of the Iced ecosystem](https://github.com/hecrj/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/native.png?raw=true)
//! //!
//! [`iced`]: https://github.com/hecrj/iced //! [`iced`]: https://github.com/hecrj/iced
#![deny(missing_docs)] //#![deny(missing_docs)]
#![deny(missing_debug_implementations)] #![deny(missing_debug_implementations)]
#![deny(unused_results)] #![deny(unused_results)]
#![deny(unsafe_code)] #![deny(unsafe_code)]

View file

@ -1,9 +1,8 @@
//! Build and show dropdown menus. //! Build and show dropdown menus.
use crate::alignment;
use crate::backend::{self, Backend}; use crate::backend::{self, Backend};
use crate::{Primitive, Renderer}; use crate::Renderer;
use iced_native::{mouse, overlay, Color, Font, Padding, Point, Rectangle}; use iced_native::overlay;
pub use iced_style::menu::Style; pub use iced_style::menu::Style;
@ -12,105 +11,4 @@ where
B: Backend + backend::Text, B: Backend + backend::Text,
{ {
type Style = Style; type Style = Style;
fn decorate(
&mut self,
bounds: Rectangle,
_cursor_position: Point,
style: &Style,
(primitives, mouse_cursor): Self::Output,
) -> Self::Output {
(
Primitive::Group {
primitives: vec![
Primitive::Quad {
bounds,
background: style.background,
border_color: style.border_color,
border_width: style.border_width,
border_radius: 0.0,
},
primitives,
],
},
mouse_cursor,
)
}
fn draw<T: ToString>(
&mut self,
bounds: Rectangle,
cursor_position: Point,
viewport: &Rectangle,
options: &[T],
hovered_option: Option<usize>,
padding: Padding,
text_size: u16,
font: Font,
style: &Style,
) -> Self::Output {
use std::f32;
let is_mouse_over = bounds.contains(cursor_position);
let option_height = (text_size + padding.vertical()) as usize;
let mut primitives = Vec::new();
let offset = viewport.y - bounds.y;
let start = (offset / option_height as f32) as usize;
let end =
((offset + viewport.height) / option_height as f32).ceil() as usize;
let visible_options = &options[start..end.min(options.len())];
for (i, option) in visible_options.iter().enumerate() {
let i = start + i;
let is_selected = hovered_option == Some(i);
let bounds = Rectangle {
x: bounds.x,
y: bounds.y + (option_height * i) as f32,
width: bounds.width,
height: f32::from(text_size + padding.vertical()),
};
if is_selected {
primitives.push(Primitive::Quad {
bounds,
background: style.selected_background,
border_color: Color::TRANSPARENT,
border_width: 0.0,
border_radius: 0.0,
});
}
primitives.push(Primitive::Text {
content: option.to_string(),
bounds: Rectangle {
x: bounds.x + padding.left as f32,
y: bounds.center_y(),
width: f32::INFINITY,
..bounds
},
size: f32::from(text_size),
font,
color: if is_selected {
style.selected_text_color
} else {
style.text_color
},
horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Center,
});
}
(
Primitive::Group { primitives },
if is_mouse_over {
mouse::Interaction::Pointer
} else {
mouse::Interaction::default()
},
)
}
} }

View file

@ -1,30 +1,29 @@
use crate::{Backend, Defaults, Primitive}; use crate::{Backend, Defaults, Primitive};
use iced_native::layout::{self, Layout}; use iced_native::layout;
use iced_native::mouse; use iced_native::{Element, Rectangle};
use iced_native::{
Background, Color, Element, Point, Rectangle, Vector, Widget,
};
/// A backend-agnostic renderer that supports all the built-in widgets. /// A backend-agnostic renderer that supports all the built-in widgets.
#[derive(Debug)] #[derive(Debug)]
pub struct Renderer<B: Backend> { pub struct Renderer<B: Backend> {
backend: B, backend: B,
primitive: Primitive,
} }
impl<B: Backend> Renderer<B> { impl<B: Backend> Renderer<B> {
/// Creates a new [`Renderer`] from the given [`Backend`]. /// Creates a new [`Renderer`] from the given [`Backend`].
pub fn new(backend: B) -> Self { pub fn new(backend: B) -> Self {
Self { backend } Self {
backend,
primitive: Primitive::None,
}
} }
/// Returns a reference to the [`Backend`] of the [`Renderer`].
pub fn backend(&self) -> &B { pub fn backend(&self) -> &B {
&self.backend &self.backend
} }
/// Returns a mutable reference to the [`Backend`] of the [`Renderer`]. pub fn present(&mut self, f: impl FnOnce(&mut B, &Primitive)) {
pub fn backend_mut(&mut self) -> &mut B { f(&mut self.backend, &self.primitive);
&mut self.backend
} }
} }
@ -32,7 +31,6 @@ impl<B> iced_native::Renderer for Renderer<B>
where where
B: Backend, B: Backend,
{ {
type Output = (Primitive, mouse::Interaction);
type Defaults = Defaults; type Defaults = Defaults;
fn layout<'a, Message>( fn layout<'a, Message>(
@ -47,75 +45,5 @@ where
layout layout
} }
fn overlay( fn with_layer(&mut self, _bounds: Rectangle, _f: impl FnOnce(&mut Self)) {}
&mut self,
(base_primitive, base_cursor): (Primitive, mouse::Interaction),
(overlay_primitives, overlay_cursor): (Primitive, mouse::Interaction),
overlay_bounds: Rectangle,
) -> (Primitive, mouse::Interaction) {
(
Primitive::Group {
primitives: vec![
base_primitive,
Primitive::Clip {
bounds: Rectangle {
width: overlay_bounds.width + 0.5,
height: overlay_bounds.height + 0.5,
..overlay_bounds
},
offset: Vector::new(0, 0),
content: Box::new(overlay_primitives),
},
],
},
if base_cursor > overlay_cursor {
base_cursor
} else {
overlay_cursor
},
)
}
}
impl<B> layout::Debugger for Renderer<B>
where
B: Backend,
{
fn explain<Message>(
&mut self,
defaults: &Defaults,
widget: &dyn Widget<Message, Self>,
layout: Layout<'_>,
cursor_position: Point,
viewport: &Rectangle,
color: Color,
) -> Self::Output {
let (primitive, cursor) =
widget.draw(self, defaults, layout, cursor_position, viewport);
let mut primitives = Vec::new();
explain_layout(layout, color, &mut primitives);
primitives.push(primitive);
(Primitive::Group { primitives }, cursor)
}
}
fn explain_layout(
layout: Layout<'_>,
color: Color,
primitives: &mut Vec<Primitive>,
) {
primitives.push(Primitive::Quad {
bounds: layout.bounds(),
background: Background::Color(Color::TRANSPARENT),
border_radius: 0.0,
border_width: 1.0,
border_color: [0.6, 0.6, 0.6, 0.5].into(),
});
for child in layout.children() {
explain_layout(child, color, primitives);
}
} }

View file

@ -1,12 +1,8 @@
//! Allow your users to perform actions by pressing a button. //! Allow your users to perform actions by pressing a button.
//! //!
//! A [`Button`] has some local [`State`]. //! A [`Button`] has some local [`State`].
use crate::defaults::{self, Defaults}; use crate::{Backend, Renderer};
use crate::{Backend, Primitive, Renderer}; use iced_native::Padding;
use iced_native::mouse;
use iced_native::{
Background, Color, Element, Layout, Padding, Point, Rectangle, Vector,
};
pub use iced_native::button::State; pub use iced_native::button::State;
pub use iced_style::button::{Style, StyleSheet}; pub use iced_style::button::{Style, StyleSheet};
@ -24,88 +20,4 @@ where
const DEFAULT_PADDING: Padding = Padding::new(5); const DEFAULT_PADDING: Padding = Padding::new(5);
type Style = Box<dyn StyleSheet>; type Style = Box<dyn StyleSheet>;
fn draw<Message>(
&mut self,
_defaults: &Defaults,
bounds: Rectangle,
cursor_position: Point,
is_disabled: bool,
is_pressed: bool,
style: &Box<dyn StyleSheet>,
content: &Element<'_, Message, Self>,
content_layout: Layout<'_>,
) -> Self::Output {
let is_mouse_over = bounds.contains(cursor_position);
let styling = if is_disabled {
style.disabled()
} else if is_mouse_over {
if is_pressed {
style.pressed()
} else {
style.hovered()
}
} else {
style.active()
};
let (content, _) = content.draw(
self,
&Defaults {
text: defaults::Text {
color: styling.text_color,
},
},
content_layout,
cursor_position,
&bounds,
);
(
if styling.background.is_some() || styling.border_width > 0.0 {
let background = Primitive::Quad {
bounds,
background: styling
.background
.unwrap_or(Background::Color(Color::TRANSPARENT)),
border_radius: styling.border_radius,
border_width: styling.border_width,
border_color: styling.border_color,
};
if styling.shadow_offset == Vector::default() {
Primitive::Group {
primitives: vec![background, content],
}
} else {
// TODO: Implement proper shadow support
let shadow = Primitive::Quad {
bounds: Rectangle {
x: bounds.x + styling.shadow_offset.x,
y: bounds.y + styling.shadow_offset.y,
..bounds
},
background: Background::Color(
[0.0, 0.0, 0.0, 0.5].into(),
),
border_radius: styling.border_radius,
border_width: 0.0,
border_color: Color::TRANSPARENT,
};
Primitive::Group {
primitives: vec![shadow, background, content],
}
}
} else {
content
},
if is_mouse_over && !is_disabled {
mouse::Interaction::Pointer
} else {
mouse::Interaction::default()
},
)
}
} }

View file

@ -3,12 +3,10 @@
//! A [`Canvas`] widget can be used to draw different kinds of 2D shapes in a //! A [`Canvas`] widget can be used to draw different kinds of 2D shapes in a
//! [`Frame`]. It can be used for animation, data visualization, game graphics, //! [`Frame`]. It can be used for animation, data visualization, game graphics,
//! and more! //! and more!
use crate::{Backend, Defaults, Primitive, Renderer}; use crate::{Backend, Defaults, Renderer};
use iced_native::layout; use iced_native::layout;
use iced_native::mouse;
use iced_native::{ use iced_native::{
Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Size, Vector, Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget,
Widget,
}; };
use std::hash::Hash; use std::hash::Hash;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -190,28 +188,29 @@ where
&self, &self,
_renderer: &mut Renderer<B>, _renderer: &mut Renderer<B>,
_defaults: &Defaults, _defaults: &Defaults,
layout: Layout<'_>, _layout: Layout<'_>,
cursor_position: Point, _cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> (Primitive, mouse::Interaction) { ) {
let bounds = layout.bounds(); // let bounds = layout.bounds();
let translation = Vector::new(bounds.x, bounds.y); // let translation = Vector::new(bounds.x, bounds.y);
let cursor = Cursor::from_window_position(cursor_position); // let cursor = Cursor::from_window_position(cursor_position);
( // (
Primitive::Translate { // Primitive::Translate {
translation, // translation,
content: Box::new(Primitive::Group { // content: Box::new(Primitive::Group {
primitives: self // primitives: self
.program // .program
.draw(bounds, cursor) // .draw(bounds, cursor)
.into_iter() // .into_iter()
.map(Geometry::into_primitive) // .map(Geometry::into_primitive)
.collect(), // .collect(),
}), // }),
}, // },
self.program.mouse_interaction(bounds, cursor), // self.program.mouse_interaction(bounds, cursor),
) // )
// TODO
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {

View file

@ -1,10 +1,8 @@
//! Show toggle controls using checkboxes. //! Show toggle controls using checkboxes.
use crate::alignment;
use crate::backend::{self, Backend}; use crate::backend::{self, Backend};
use crate::{Primitive, Rectangle, Renderer}; use crate::Renderer;
use iced_native::checkbox; use iced_native::checkbox;
use iced_native::mouse;
pub use iced_style::checkbox::{Style, StyleSheet}; pub use iced_style::checkbox::{Style, StyleSheet};
@ -22,56 +20,4 @@ where
const DEFAULT_SIZE: u16 = 20; const DEFAULT_SIZE: u16 = 20;
const DEFAULT_SPACING: u16 = 15; const DEFAULT_SPACING: u16 = 15;
fn draw(
&mut self,
bounds: Rectangle,
is_checked: bool,
is_mouse_over: bool,
(label, _): Self::Output,
style_sheet: &Self::Style,
) -> Self::Output {
let style = if is_mouse_over {
style_sheet.hovered(is_checked)
} else {
style_sheet.active(is_checked)
};
let checkbox = Primitive::Quad {
bounds,
background: style.background,
border_radius: style.border_radius,
border_width: style.border_width,
border_color: style.border_color,
};
(
Primitive::Group {
primitives: if is_checked {
let check = Primitive::Text {
content: B::CHECKMARK_ICON.to_string(),
font: B::ICON_FONT,
size: bounds.height * 0.7,
bounds: Rectangle {
x: bounds.center_x(),
y: bounds.center_y(),
..bounds
},
color: style.checkmark_color,
horizontal_alignment: alignment::Horizontal::Center,
vertical_alignment: alignment::Vertical::Center,
};
vec![checkbox, check, label]
} else {
vec![checkbox, label]
},
},
if is_mouse_over {
mouse::Interaction::Pointer
} else {
mouse::Interaction::default()
},
)
}
} }

View file

@ -1,49 +1,5 @@
use crate::{Backend, Primitive, Renderer}; use crate::Renderer;
use iced_native::column;
use iced_native::mouse;
use iced_native::{Element, Layout, Point, Rectangle};
/// A container that distributes its contents vertically. /// A container that distributes its contents vertically.
pub type Column<'a, Message, Backend> = pub type Column<'a, Message, Backend> =
iced_native::Column<'a, Message, Renderer<Backend>>; iced_native::Column<'a, Message, Renderer<Backend>>;
impl<B> column::Renderer for Renderer<B>
where
B: Backend,
{
fn draw<Message>(
&mut self,
defaults: &Self::Defaults,
content: &[Element<'_, Message, Self>],
layout: Layout<'_>,
cursor_position: Point,
viewport: &Rectangle,
) -> Self::Output {
let mut mouse_interaction = mouse::Interaction::default();
(
Primitive::Group {
primitives: content
.iter()
.zip(layout.children())
.map(|(child, layout)| {
let (primitive, new_mouse_interaction) = child.draw(
self,
defaults,
layout,
cursor_position,
viewport,
);
if new_mouse_interaction > mouse_interaction {
mouse_interaction = new_mouse_interaction;
}
primitive
})
.collect(),
},
mouse_interaction,
)
}
}

View file

@ -1,8 +1,6 @@
//! Decorate content and apply alignment. //! Decorate content and apply alignment.
use crate::container; use crate::container;
use crate::defaults::{self, Defaults}; use crate::{Backend, Renderer};
use crate::{Backend, Primitive, Renderer};
use iced_native::{Background, Color, Element, Layout, Point, Rectangle};
pub use iced_style::container::{Style, StyleSheet}; pub use iced_style::container::{Style, StyleSheet};
@ -18,61 +16,4 @@ where
B: Backend, B: Backend,
{ {
type Style = Box<dyn container::StyleSheet>; type Style = Box<dyn container::StyleSheet>;
fn draw<Message>(
&mut self,
defaults: &Defaults,
bounds: Rectangle,
cursor_position: Point,
viewport: &Rectangle,
style_sheet: &Self::Style,
content: &Element<'_, Message, Self>,
content_layout: Layout<'_>,
) -> Self::Output {
let style = style_sheet.style();
let defaults = Defaults {
text: defaults::Text {
color: style.text_color.unwrap_or(defaults.text.color),
},
};
let (content, mouse_interaction) = content.draw(
self,
&defaults,
content_layout,
cursor_position,
viewport,
);
if let Some(background) = background(bounds, &style) {
(
Primitive::Group {
primitives: vec![background, content],
},
mouse_interaction,
)
} else {
(content, mouse_interaction)
}
}
}
pub(crate) fn background(
bounds: Rectangle,
style: &container::Style,
) -> Option<Primitive> {
if style.background.is_some() || style.border_width > 0.0 {
Some(Primitive::Quad {
bounds,
background: style
.background
.unwrap_or(Background::Color(Color::TRANSPARENT)),
border_radius: style.border_radius,
border_width: style.border_width,
border_color: style.border_color,
})
} else {
None
}
} }

View file

@ -3,10 +3,8 @@ pub mod viewer;
use crate::backend::{self, Backend}; use crate::backend::{self, Backend};
use crate::{Primitive, Renderer}; use crate::Renderer;
use iced_native::image; use iced_native::image;
use iced_native::mouse;
use iced_native::Layout;
pub use iced_native::image::{Handle, Image, Viewer}; pub use iced_native::image::{Handle, Image, Viewer};
@ -17,18 +15,4 @@ where
fn dimensions(&self, handle: &image::Handle) -> (u32, u32) { fn dimensions(&self, handle: &image::Handle) -> (u32, u32) {
self.backend().dimensions(handle) self.backend().dimensions(handle)
} }
fn draw(
&mut self,
handle: image::Handle,
layout: Layout<'_>,
) -> Self::Output {
(
Primitive::Image {
handle,
bounds: layout.bounds(),
},
mouse::Interaction::default(),
)
}
} }

View file

@ -1,55 +1,2 @@
//! Zoom and pan on an image. //! Zoom and pan on an image.
use crate::backend::{self, Backend}; pub use iced_native::image::Viewer;
use crate::{Primitive, Renderer};
use iced_native::image;
use iced_native::image::viewer;
use iced_native::mouse;
use iced_native::{Rectangle, Size, Vector};
impl<B> viewer::Renderer for Renderer<B>
where
B: Backend + backend::Image,
{
fn draw(
&mut self,
state: &viewer::State,
bounds: Rectangle,
image_size: Size,
translation: Vector,
handle: image::Handle,
is_mouse_over: bool,
) -> Self::Output {
(
{
Primitive::Clip {
bounds,
content: Box::new(Primitive::Translate {
translation,
content: Box::new(Primitive::Image {
handle,
bounds: Rectangle {
x: bounds.x,
y: bounds.y,
..Rectangle::with_size(image_size)
},
}),
}),
offset: Vector::new(0, 0),
}
},
{
if state.is_cursor_grabbed() {
mouse::Interaction::Grabbing
} else if is_mouse_over
&& (image_size.width > bounds.width
|| image_size.height > bounds.height)
{
mouse::Interaction::Grab
} else {
mouse::Interaction::Idle
}
},
)
}
}

View file

@ -7,12 +7,8 @@
//! drag and drop, and hotkey support. //! drag and drop, and hotkey support.
//! //!
//! [`pane_grid` example]: https://github.com/hecrj/iced/tree/0.3/examples/pane_grid //! [`pane_grid` example]: https://github.com/hecrj/iced/tree/0.3/examples/pane_grid
use crate::defaults; use crate::{Backend, Renderer};
use crate::{Backend, Color, Primitive, Renderer};
use iced_native::container;
use iced_native::mouse;
use iced_native::pane_grid; use iced_native::pane_grid;
use iced_native::{Element, Layout, Point, Rectangle, Vector};
pub use iced_native::pane_grid::{ pub use iced_native::pane_grid::{
Axis, Configuration, Content, Direction, DragEvent, Node, Pane, Axis, Configuration, Content, Direction, DragEvent, Node, Pane,
@ -35,270 +31,4 @@ where
B: Backend, B: Backend,
{ {
type Style = Box<dyn StyleSheet>; type Style = Box<dyn StyleSheet>;
fn draw<Message>(
&mut self,
defaults: &Self::Defaults,
content: &[(Pane, Content<'_, Message, Self>)],
dragging: Option<(Pane, Point)>,
resizing: Option<(Axis, Rectangle, bool)>,
layout: Layout<'_>,
style_sheet: &<Self as pane_grid::Renderer>::Style,
cursor_position: Point,
viewport: &Rectangle,
) -> Self::Output {
let pane_cursor_position = if dragging.is_some() {
// TODO: Remove once cursor availability is encoded in the type
// system
Point::new(-1.0, -1.0)
} else {
cursor_position
};
let mut mouse_interaction = mouse::Interaction::default();
let mut dragged_pane = None;
let mut panes: Vec<_> = content
.iter()
.zip(layout.children())
.enumerate()
.map(|(i, ((id, pane), layout))| {
let (primitive, new_mouse_interaction) = pane.draw(
self,
defaults,
layout,
pane_cursor_position,
viewport,
);
if new_mouse_interaction > mouse_interaction {
mouse_interaction = new_mouse_interaction;
}
if let Some((dragging, origin)) = dragging {
if *id == dragging {
dragged_pane = Some((i, layout, origin));
}
}
primitive
})
.collect();
let mut primitives = if let Some((index, layout, origin)) = dragged_pane
{
let pane = panes.remove(index);
let bounds = layout.bounds();
// TODO: Fix once proper layering is implemented.
// This is a pretty hacky way to achieve layering.
let clip = Primitive::Clip {
bounds: Rectangle {
x: cursor_position.x - origin.x,
y: cursor_position.y - origin.y,
width: bounds.width + 0.5,
height: bounds.height + 0.5,
},
offset: Vector::new(0, 0),
content: Box::new(Primitive::Translate {
translation: Vector::new(
cursor_position.x - bounds.x - origin.x,
cursor_position.y - bounds.y - origin.y,
),
content: Box::new(pane),
}),
};
panes.push(clip);
panes
} else {
panes
};
let (primitives, mouse_interaction) =
if let Some((axis, split_region, is_picked)) = resizing {
let highlight = if is_picked {
style_sheet.picked_split()
} else {
style_sheet.hovered_split()
};
if let Some(highlight) = highlight {
primitives.push(Primitive::Quad {
bounds: match axis {
Axis::Horizontal => Rectangle {
x: split_region.x,
y: (split_region.y
+ (split_region.height - highlight.width)
/ 2.0)
.round(),
width: split_region.width,
height: highlight.width,
},
Axis::Vertical => Rectangle {
x: (split_region.x
+ (split_region.width - highlight.width)
/ 2.0)
.round(),
y: split_region.y,
width: highlight.width,
height: split_region.height,
},
},
background: highlight.color.into(),
border_radius: 0.0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
});
}
(
primitives,
match axis {
Axis::Horizontal => {
mouse::Interaction::ResizingVertically
}
Axis::Vertical => {
mouse::Interaction::ResizingHorizontally
}
},
)
} else {
(primitives, mouse_interaction)
};
(
Primitive::Group { primitives },
if dragging.is_some() {
mouse::Interaction::Grabbing
} else {
mouse_interaction
},
)
}
fn draw_pane<Message>(
&mut self,
defaults: &Self::Defaults,
bounds: Rectangle,
style_sheet: &<Self as container::Renderer>::Style,
title_bar: Option<(&TitleBar<'_, Message, Self>, Layout<'_>)>,
body: (&Element<'_, Message, Self>, Layout<'_>),
cursor_position: Point,
viewport: &Rectangle,
) -> Self::Output {
let style = style_sheet.style();
let (body, body_layout) = body;
let (body_primitive, body_interaction) =
body.draw(self, defaults, body_layout, cursor_position, viewport);
let background = crate::widget::container::background(bounds, &style);
if let Some((title_bar, title_bar_layout)) = title_bar {
let show_controls = bounds.contains(cursor_position);
let is_over_pick_area =
title_bar.is_over_pick_area(title_bar_layout, cursor_position);
let (title_bar_primitive, title_bar_interaction) = title_bar.draw(
self,
defaults,
title_bar_layout,
cursor_position,
viewport,
show_controls,
);
(
Primitive::Group {
primitives: vec![
background.unwrap_or(Primitive::None),
title_bar_primitive,
body_primitive,
],
},
if title_bar_interaction > body_interaction {
title_bar_interaction
} else if is_over_pick_area {
mouse::Interaction::Grab
} else {
body_interaction
},
)
} else {
(
if let Some(background) = background {
Primitive::Group {
primitives: vec![background, body_primitive],
}
} else {
body_primitive
},
body_interaction,
)
}
}
fn draw_title_bar<Message>(
&mut self,
defaults: &Self::Defaults,
bounds: Rectangle,
style_sheet: &<Self as container::Renderer>::Style,
content: (&Element<'_, Message, Self>, Layout<'_>),
controls: Option<(&Element<'_, Message, Self>, Layout<'_>)>,
cursor_position: Point,
viewport: &Rectangle,
) -> Self::Output {
let style = style_sheet.style();
let (title_content, title_layout) = content;
let defaults = Self::Defaults {
text: defaults::Text {
color: style.text_color.unwrap_or(defaults.text.color),
},
};
let background = crate::widget::container::background(bounds, &style);
let (title_primitive, title_interaction) = title_content.draw(
self,
&defaults,
title_layout,
cursor_position,
viewport,
);
if let Some((controls, controls_layout)) = controls {
let (controls_primitive, controls_interaction) = controls.draw(
self,
&defaults,
controls_layout,
cursor_position,
viewport,
);
(
Primitive::Group {
primitives: vec![
background.unwrap_or(Primitive::None),
title_primitive,
controls_primitive,
],
},
controls_interaction.max(title_interaction),
)
} else {
(
if let Some(background) = background {
Primitive::Group {
primitives: vec![background, title_primitive],
}
} else {
title_primitive
},
title_interaction,
)
}
}
} }

View file

@ -1,9 +1,8 @@
//! Display a dropdown list of selectable values. //! Display a dropdown list of selectable values.
use crate::alignment;
use crate::backend::{self, Backend}; use crate::backend::{self, Backend};
use crate::{Primitive, Renderer}; use crate::Renderer;
use iced_native::{mouse, Font, Padding, Point, Rectangle}; use iced_native::Padding;
use iced_style::menu; use iced_style::menu;
pub use iced_native::pick_list::State; pub use iced_native::pick_list::State;
@ -24,80 +23,4 @@ where
fn menu_style(style: &Box<dyn StyleSheet>) -> menu::Style { fn menu_style(style: &Box<dyn StyleSheet>) -> menu::Style {
style.menu() style.menu()
} }
fn draw(
&mut self,
bounds: Rectangle,
cursor_position: Point,
selected: Option<String>,
placeholder: Option<&str>,
padding: Padding,
text_size: u16,
font: Font,
style: &Box<dyn StyleSheet>,
) -> Self::Output {
let is_mouse_over = bounds.contains(cursor_position);
let is_selected = selected.is_some();
let style = if is_mouse_over {
style.hovered()
} else {
style.active()
};
let background = Primitive::Quad {
bounds,
background: style.background,
border_color: style.border_color,
border_width: style.border_width,
border_radius: style.border_radius,
};
let arrow_down = Primitive::Text {
content: B::ARROW_DOWN_ICON.to_string(),
font: B::ICON_FONT,
size: bounds.height * style.icon_size,
bounds: Rectangle {
x: bounds.x + bounds.width - f32::from(padding.horizontal()),
y: bounds.center_y(),
..bounds
},
color: style.text_color,
horizontal_alignment: alignment::Horizontal::Right,
vertical_alignment: alignment::Vertical::Center,
};
(
Primitive::Group {
primitives: if let Some(label) =
selected.or_else(|| placeholder.map(str::to_string))
{
let label = Primitive::Text {
content: label,
size: f32::from(text_size),
font,
color: is_selected
.then(|| style.text_color)
.unwrap_or(style.placeholder_color),
bounds: Rectangle {
x: bounds.x + f32::from(padding.left),
y: bounds.center_y(),
..bounds
},
horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Center,
};
vec![background, label, arrow_down]
} else {
vec![background, arrow_down]
},
},
if is_mouse_over {
mouse::Interaction::Pointer
} else {
mouse::Interaction::default()
},
)
}
} }

View file

@ -2,10 +2,8 @@
//! //!
//! A [`ProgressBar`] has a range of possible values and a current value, //! A [`ProgressBar`] has a range of possible values and a current value,
//! as well as a length, height and style. //! as well as a length, height and style.
use crate::{Backend, Primitive, Renderer}; use crate::{Backend, Renderer};
use iced_native::mouse;
use iced_native::progress_bar; use iced_native::progress_bar;
use iced_native::{Color, Rectangle};
pub use iced_style::progress_bar::{Style, StyleSheet}; pub use iced_style::progress_bar::{Style, StyleSheet};
@ -22,53 +20,4 @@ where
type Style = Box<dyn StyleSheet>; type Style = Box<dyn StyleSheet>;
const DEFAULT_HEIGHT: u16 = 30; const DEFAULT_HEIGHT: u16 = 30;
fn draw(
&self,
bounds: Rectangle,
range: std::ops::RangeInclusive<f32>,
value: f32,
style_sheet: &Self::Style,
) -> Self::Output {
let style = style_sheet.style();
let (range_start, range_end) = range.into_inner();
let active_progress_width = if range_start >= range_end {
0.0
} else {
bounds.width * (value - range_start) / (range_end - range_start)
};
let background = Primitive::Group {
primitives: vec![Primitive::Quad {
bounds: Rectangle { ..bounds },
background: style.background,
border_radius: style.border_radius,
border_width: 0.0,
border_color: Color::TRANSPARENT,
}],
};
(
if active_progress_width > 0.0 {
let bar = Primitive::Quad {
bounds: Rectangle {
width: active_progress_width,
..bounds
},
background: style.bar,
border_radius: style.border_radius,
border_width: 0.0,
border_color: Color::TRANSPARENT,
};
Primitive::Group {
primitives: vec![background, bar],
}
} else {
background
},
mouse::Interaction::default(),
)
}
} }

View file

@ -1,10 +1,10 @@
//! Encode and display information in a QR code. //! Encode and display information in a QR code.
use crate::canvas; use crate::canvas;
use crate::{Backend, Defaults, Primitive, Renderer, Vector}; use crate::{Backend, Defaults, Renderer};
use iced_native::{ use iced_native::{
layout, mouse, Color, Element, Hasher, Layout, Length, Point, Rectangle, layout, Color, Element, Hasher, Layout, Length, Point, Rectangle, Size,
Size, Widget, Widget,
}; };
use thiserror::Error; use thiserror::Error;
@ -82,53 +82,54 @@ where
&self, &self,
_renderer: &mut Renderer<B>, _renderer: &mut Renderer<B>,
_defaults: &Defaults, _defaults: &Defaults,
layout: Layout<'_>, _layout: Layout<'_>,
_cursor_position: Point, _cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> (Primitive, mouse::Interaction) { ) {
let bounds = layout.bounds(); // let bounds = layout.bounds();
let side_length = self.state.width + 2 * QUIET_ZONE; // let side_length = self.state.width + 2 * QUIET_ZONE;
// Reuse cache if possible // // Reuse cache if possible
let geometry = self.state.cache.draw(bounds.size(), |frame| { // let geometry = self.state.cache.draw(bounds.size(), |frame| {
// Scale units to cell size // // Scale units to cell size
frame.scale(f32::from(self.cell_size)); // frame.scale(f32::from(self.cell_size));
// Draw background // // Draw background
frame.fill_rectangle( // frame.fill_rectangle(
Point::ORIGIN, // Point::ORIGIN,
Size::new(side_length as f32, side_length as f32), // Size::new(side_length as f32, side_length as f32),
self.light, // self.light,
); // );
// Avoid drawing on the quiet zone // // Avoid drawing on the quiet zone
frame.translate(Vector::new(QUIET_ZONE as f32, QUIET_ZONE as f32)); // frame.translate(Vector::new(QUIET_ZONE as f32, QUIET_ZONE as f32));
// Draw contents // // Draw contents
self.state // self.state
.contents // .contents
.iter() // .iter()
.enumerate() // .enumerate()
.filter(|(_, value)| **value == qrcode::Color::Dark) // .filter(|(_, value)| **value == qrcode::Color::Dark)
.for_each(|(index, _)| { // .for_each(|(index, _)| {
let row = index / self.state.width; // let row = index / self.state.width;
let column = index % self.state.width; // let column = index % self.state.width;
frame.fill_rectangle( // frame.fill_rectangle(
Point::new(column as f32, row as f32), // Point::new(column as f32, row as f32),
Size::UNIT, // Size::UNIT,
self.dark, // self.dark,
); // );
}); // });
}); // });
( // (
Primitive::Translate { // Primitive::Translate {
translation: Vector::new(bounds.x, bounds.y), // translation: Vector::new(bounds.x, bounds.y),
content: Box::new(geometry.into_primitive()), // content: Box::new(geometry.into_primitive()),
}, // },
mouse::Interaction::default(), // mouse::Interaction::default(),
) // )
// TODO
} }
} }

View file

@ -1,8 +1,6 @@
//! Create choices using radio buttons. //! Create choices using radio buttons.
use crate::{Backend, Primitive, Renderer}; use crate::{Backend, Renderer};
use iced_native::mouse;
use iced_native::radio; use iced_native::radio;
use iced_native::{Background, Color, Rectangle};
pub use iced_style::radio::{Style, StyleSheet}; pub use iced_style::radio::{Style, StyleSheet};
@ -21,58 +19,4 @@ where
const DEFAULT_SIZE: u16 = 28; const DEFAULT_SIZE: u16 = 28;
const DEFAULT_SPACING: u16 = 15; const DEFAULT_SPACING: u16 = 15;
fn draw(
&mut self,
bounds: Rectangle,
is_selected: bool,
is_mouse_over: bool,
(label, _): Self::Output,
style_sheet: &Self::Style,
) -> Self::Output {
let style = if is_mouse_over {
style_sheet.hovered()
} else {
style_sheet.active()
};
let size = bounds.width;
let dot_size = size / 2.0;
let radio = Primitive::Quad {
bounds,
background: style.background,
border_radius: size / 2.0,
border_width: style.border_width,
border_color: style.border_color,
};
(
Primitive::Group {
primitives: if is_selected {
let radio_circle = Primitive::Quad {
bounds: Rectangle {
x: bounds.x + dot_size / 2.0,
y: bounds.y + dot_size / 2.0,
width: bounds.width - dot_size,
height: bounds.height - dot_size,
},
background: Background::Color(style.dot_color),
border_radius: dot_size / 2.0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
};
vec![radio, radio_circle, label]
} else {
vec![radio, label]
},
},
if is_mouse_over {
mouse::Interaction::Pointer
} else {
mouse::Interaction::default()
},
)
}
} }

View file

@ -1,49 +1,5 @@
use crate::{Backend, Primitive, Renderer}; use crate::Renderer;
use iced_native::mouse;
use iced_native::row;
use iced_native::{Element, Layout, Point, Rectangle};
/// A container that distributes its contents horizontally. /// A container that distributes its contents horizontally.
pub type Row<'a, Message, Backend> = pub type Row<'a, Message, Backend> =
iced_native::Row<'a, Message, Renderer<Backend>>; iced_native::Row<'a, Message, Renderer<Backend>>;
impl<B> row::Renderer for Renderer<B>
where
B: Backend,
{
fn draw<Message>(
&mut self,
defaults: &Self::Defaults,
content: &[Element<'_, Message, Self>],
layout: Layout<'_>,
cursor_position: Point,
viewport: &Rectangle,
) -> Self::Output {
let mut mouse_interaction = mouse::Interaction::default();
(
Primitive::Group {
primitives: content
.iter()
.zip(layout.children())
.map(|(child, layout)| {
let (primitive, new_mouse_interaction) = child.draw(
self,
defaults,
layout,
cursor_position,
viewport,
);
if new_mouse_interaction > mouse_interaction {
mouse_interaction = new_mouse_interaction;
}
primitive
})
.collect(),
},
mouse_interaction,
)
}
}

View file

@ -1,9 +1,7 @@
//! Display a horizontal or vertical rule for dividing content. //! Display a horizontal or vertical rule for dividing content.
use crate::{Backend, Primitive, Renderer}; use crate::{Backend, Renderer};
use iced_native::mouse;
use iced_native::rule; use iced_native::rule;
use iced_native::{Background, Color, Rectangle};
pub use iced_style::rule::{FillMode, Style, StyleSheet}; pub use iced_style::rule::{FillMode, Style, StyleSheet};
@ -17,57 +15,4 @@ where
B: Backend, B: Backend,
{ {
type Style = Box<dyn StyleSheet>; type Style = Box<dyn StyleSheet>;
fn draw(
&mut self,
bounds: Rectangle,
style_sheet: &Self::Style,
is_horizontal: bool,
) -> Self::Output {
let style = style_sheet.style();
let line = if is_horizontal {
let line_y = (bounds.y + (bounds.height / 2.0)
- (style.width as f32 / 2.0))
.round();
let (offset, line_width) = style.fill_mode.fill(bounds.width);
let line_x = bounds.x + offset;
Primitive::Quad {
bounds: Rectangle {
x: line_x,
y: line_y,
width: line_width,
height: style.width as f32,
},
background: Background::Color(style.color),
border_radius: style.radius,
border_width: 0.0,
border_color: Color::TRANSPARENT,
}
} else {
let line_x = (bounds.x + (bounds.width / 2.0)
- (style.width as f32 / 2.0))
.round();
let (offset, line_height) = style.fill_mode.fill(bounds.height);
let line_y = bounds.y + offset;
Primitive::Quad {
bounds: Rectangle {
x: line_x,
y: line_y,
width: style.width as f32,
height: line_height,
},
background: Background::Color(style.color),
border_radius: style.radius,
border_width: 0.0,
border_color: Color::TRANSPARENT,
}
};
(line, mouse::Interaction::default())
}
} }

View file

@ -1,8 +1,7 @@
//! Navigate an endless amount of content with a scrollbar. //! Navigate an endless amount of content with a scrollbar.
use crate::{Backend, Primitive, Renderer}; use crate::{Backend, Renderer};
use iced_native::mouse;
use iced_native::scrollable; use iced_native::scrollable;
use iced_native::{Background, Color, Rectangle, Vector}; use iced_native::Rectangle;
pub use iced_native::scrollable::State; pub use iced_native::scrollable::State;
pub use iced_style::scrollable::{Scrollbar, Scroller, StyleSheet}; pub use iced_style::scrollable::{Scrollbar, Scroller, StyleSheet};
@ -73,86 +72,4 @@ where
None None
} }
} }
fn draw(
&mut self,
state: &scrollable::State,
bounds: Rectangle,
_content_bounds: Rectangle,
is_mouse_over: bool,
is_mouse_over_scrollbar: bool,
scrollbar: Option<scrollable::Scrollbar>,
offset: u32,
style_sheet: &Self::Style,
(content, mouse_interaction): Self::Output,
) -> Self::Output {
(
if let Some(scrollbar) = scrollbar {
let clip = Primitive::Clip {
bounds,
offset: Vector::new(0, offset),
content: Box::new(content),
};
let style = if state.is_scroller_grabbed() {
style_sheet.dragging()
} else if is_mouse_over_scrollbar {
style_sheet.hovered()
} else {
style_sheet.active()
};
let is_scrollbar_visible =
style.background.is_some() || style.border_width > 0.0;
let scroller = if is_mouse_over
|| state.is_scroller_grabbed()
|| is_scrollbar_visible
{
Primitive::Quad {
bounds: scrollbar.scroller.bounds,
background: Background::Color(style.scroller.color),
border_radius: style.scroller.border_radius,
border_width: style.scroller.border_width,
border_color: style.scroller.border_color,
}
} else {
Primitive::None
};
let scrollbar = if is_scrollbar_visible {
Primitive::Quad {
bounds: scrollbar.bounds,
background: style
.background
.unwrap_or(Background::Color(Color::TRANSPARENT)),
border_radius: style.border_radius,
border_width: style.border_width,
border_color: style.border_color,
}
} else {
Primitive::None
};
let scroll = Primitive::Clip {
bounds,
offset: Vector::new(0, 0),
content: Box::new(Primitive::Group {
primitives: vec![scrollbar, scroller],
}),
};
Primitive::Group {
primitives: vec![clip, scroll],
}
} else {
content
},
if is_mouse_over_scrollbar || state.is_scroller_grabbed() {
mouse::Interaction::Idle
} else {
mouse_interaction
},
)
}
} }

View file

@ -1,10 +1,8 @@
//! Display an interactive selector of a single value from a range of values. //! Display an interactive selector of a single value from a range of values.
//! //!
//! A [`Slider`] has some local [`State`]. //! A [`Slider`] has some local [`State`].
use crate::{Backend, Primitive, Renderer}; use crate::{Backend, Renderer};
use iced_native::mouse;
use iced_native::slider; use iced_native::slider;
use iced_native::{Background, Color, Point, Rectangle};
pub use iced_native::slider::State; pub use iced_native::slider::State;
pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet}; pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet};
@ -23,101 +21,4 @@ where
type Style = Box<dyn StyleSheet>; type Style = Box<dyn StyleSheet>;
const DEFAULT_HEIGHT: u16 = 22; const DEFAULT_HEIGHT: u16 = 22;
fn draw(
&mut self,
bounds: Rectangle,
cursor_position: Point,
range: std::ops::RangeInclusive<f32>,
value: f32,
is_dragging: bool,
style_sheet: &Self::Style,
) -> Self::Output {
let is_mouse_over = bounds.contains(cursor_position);
let style = if is_dragging {
style_sheet.dragging()
} else if is_mouse_over {
style_sheet.hovered()
} else {
style_sheet.active()
};
let rail_y = bounds.y + (bounds.height / 2.0).round();
let (rail_top, rail_bottom) = (
Primitive::Quad {
bounds: Rectangle {
x: bounds.x,
y: rail_y,
width: bounds.width,
height: 2.0,
},
background: Background::Color(style.rail_colors.0),
border_radius: 0.0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
},
Primitive::Quad {
bounds: Rectangle {
x: bounds.x,
y: rail_y + 2.0,
width: bounds.width,
height: 2.0,
},
background: Background::Color(style.rail_colors.1),
border_radius: 0.0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
},
);
let (handle_width, handle_height, handle_border_radius) = match style
.handle
.shape
{
HandleShape::Circle { radius } => {
(radius * 2.0, radius * 2.0, radius)
}
HandleShape::Rectangle {
width,
border_radius,
} => (f32::from(width), f32::from(bounds.height), border_radius),
};
let (range_start, range_end) = range.into_inner();
let handle_offset = if range_start >= range_end {
0.0
} else {
(bounds.width - handle_width) * (value - range_start)
/ (range_end - range_start)
};
let handle = Primitive::Quad {
bounds: Rectangle {
x: bounds.x + handle_offset.round(),
y: rail_y - handle_height / 2.0,
width: handle_width,
height: handle_height,
},
background: Background::Color(style.handle.color),
border_radius: handle_border_radius,
border_width: style.handle.border_width,
border_color: style.handle.border_color,
};
(
Primitive::Group {
primitives: vec![rail_top, rail_bottom, handle],
},
if is_dragging {
mouse::Interaction::Grabbing
} else if is_mouse_over {
mouse::Interaction::Grab
} else {
mouse::Interaction::default()
},
)
}
} }

View file

@ -1,15 +1 @@
use crate::{Backend, Primitive, Renderer};
use iced_native::mouse;
use iced_native::space;
use iced_native::Rectangle;
pub use iced_native::Space; pub use iced_native::Space;
impl<B> space::Renderer for Renderer<B>
where
B: Backend,
{
fn draw(&mut self, _bounds: Rectangle) -> Self::Output {
(Primitive::None, mouse::Interaction::default())
}
}

View file

@ -1,7 +1,7 @@
//! Display vector graphics in your application. //! Display vector graphics in your application.
use crate::backend::{self, Backend}; use crate::backend::{self, Backend};
use crate::{Primitive, Renderer}; use crate::Renderer;
use iced_native::{mouse, svg, Layout}; use iced_native::svg;
pub use iced_native::svg::{Handle, Svg}; pub use iced_native::svg::{Handle, Svg};
@ -12,18 +12,4 @@ where
fn dimensions(&self, handle: &svg::Handle) -> (u32, u32) { fn dimensions(&self, handle: &svg::Handle) -> (u32, u32) {
self.backend().viewport_dimensions(handle) self.backend().viewport_dimensions(handle)
} }
fn draw(
&mut self,
handle: svg::Handle,
layout: Layout<'_>,
) -> Self::Output {
(
Primitive::Svg {
handle,
bounds: layout.bounds(),
},
mouse::Interaction::default(),
)
}
} }

View file

@ -1,10 +1,8 @@
//! Write some text for your users to read. //! Write some text for your users to read.
use crate::backend::{self, Backend}; use crate::backend::{self, Backend};
use crate::{Primitive, Renderer}; use crate::Renderer;
use iced_native::alignment;
use iced_native::mouse;
use iced_native::text; use iced_native::text;
use iced_native::{Color, Font, Point, Rectangle, Size}; use iced_native::{Font, Point, Size};
/// A paragraph of text. /// A paragraph of text.
/// ///
@ -52,41 +50,4 @@ where
nearest_only, nearest_only,
) )
} }
fn draw(
&mut self,
defaults: &Self::Defaults,
bounds: Rectangle,
content: &str,
size: u16,
font: Font,
color: Option<Color>,
horizontal_alignment: alignment::Horizontal,
vertical_alignment: alignment::Vertical,
) -> Self::Output {
let x = match horizontal_alignment {
alignment::Horizontal::Left => bounds.x,
alignment::Horizontal::Center => bounds.center_x(),
alignment::Horizontal::Right => bounds.x + bounds.width,
};
let y = match vertical_alignment {
alignment::Vertical::Top => bounds.y,
alignment::Vertical::Center => bounds.center_y(),
alignment::Vertical::Bottom => bounds.y + bounds.height,
};
(
Primitive::Text {
content: content.to_string(),
size: f32::from(size),
bounds: Rectangle { x, y, ..bounds },
color: color.unwrap_or(defaults.text.color),
font,
horizontal_alignment,
vertical_alignment,
},
mouse::Interaction::default(),
)
}
} }

View file

@ -1,14 +1,9 @@
//! Display fields that can be filled with text. //! Display fields that can be filled with text.
//! //!
//! A [`TextInput`] has some local [`State`]. //! A [`TextInput`] has some local [`State`].
use crate::alignment;
use crate::backend::{self, Backend}; use crate::backend::{self, Backend};
use crate::{ use crate::{Font, Rectangle, Renderer, Size};
Background, Color, Font, Point, Primitive, Rectangle, Renderer, Size,
Vector,
};
use iced_native::mouse;
use iced_native::text_input::{self, cursor}; use iced_native::text_input::{self, cursor};
use std::f32; use std::f32;
@ -66,181 +61,6 @@ where
0.0 0.0
} }
} }
fn draw(
&mut self,
bounds: Rectangle,
text_bounds: Rectangle,
cursor_position: Point,
font: Font,
size: u16,
placeholder: &str,
value: &text_input::Value,
state: &text_input::State,
style_sheet: &Self::Style,
) -> Self::Output {
let is_mouse_over = bounds.contains(cursor_position);
let style = if state.is_focused() {
style_sheet.focused()
} else if is_mouse_over {
style_sheet.hovered()
} else {
style_sheet.active()
};
let input = Primitive::Quad {
bounds,
background: style.background,
border_radius: style.border_radius,
border_width: style.border_width,
border_color: style.border_color,
};
let text = value.to_string();
let text_value = Primitive::Text {
content: if text.is_empty() {
placeholder.to_string()
} else {
text.clone()
},
color: if text.is_empty() {
style_sheet.placeholder_color()
} else {
style_sheet.value_color()
},
font,
bounds: Rectangle {
y: text_bounds.center_y(),
width: f32::INFINITY,
..text_bounds
},
size: f32::from(size),
horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Center,
};
let (contents_primitive, offset) = if state.is_focused() {
let cursor = state.cursor();
let (cursor_primitive, offset) = match cursor.state(value) {
cursor::State::Index(position) => {
let (text_value_width, offset) =
measure_cursor_and_scroll_offset(
self,
text_bounds,
value,
size,
position,
font,
);
(
Primitive::Quad {
bounds: Rectangle {
x: text_bounds.x + text_value_width,
y: text_bounds.y,
width: 1.0,
height: text_bounds.height,
},
background: Background::Color(
style_sheet.value_color(),
),
border_radius: 0.0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
},
offset,
)
}
cursor::State::Selection { start, end } => {
let left = start.min(end);
let right = end.max(start);
let (left_position, left_offset) =
measure_cursor_and_scroll_offset(
self,
text_bounds,
value,
size,
left,
font,
);
let (right_position, right_offset) =
measure_cursor_and_scroll_offset(
self,
text_bounds,
value,
size,
right,
font,
);
let width = right_position - left_position;
(
Primitive::Quad {
bounds: Rectangle {
x: text_bounds.x + left_position,
y: text_bounds.y,
width,
height: text_bounds.height,
},
background: Background::Color(
style_sheet.selection_color(),
),
border_radius: 0.0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
},
if end == right {
right_offset
} else {
left_offset
},
)
}
};
(
Primitive::Group {
primitives: vec![cursor_primitive, text_value],
},
Vector::new(offset as u32, 0),
)
} else {
(text_value, Vector::new(0, 0))
};
let text_width = self.measure_value(
if text.is_empty() { placeholder } else { &text },
size,
font,
);
let contents = if text_width > text_bounds.width {
Primitive::Clip {
bounds: text_bounds,
offset,
content: Box::new(contents_primitive),
}
} else {
contents_primitive
};
(
Primitive::Group {
primitives: vec![input, contents],
},
if is_mouse_over {
mouse::Interaction::Text
} else {
mouse::Interaction::default()
},
)
}
} }
fn measure_cursor_and_scroll_offset<B>( fn measure_cursor_and_scroll_offset<B>(

View file

@ -1,19 +1,10 @@
//! Show toggle controls using togglers. //! Show toggle controls using togglers.
use crate::backend::{self, Backend}; use crate::backend::{self, Backend};
use crate::{Primitive, Renderer}; use crate::Renderer;
use iced_native::mouse;
use iced_native::toggler; use iced_native::toggler;
use iced_native::Rectangle;
pub use iced_style::toggler::{Style, StyleSheet}; pub use iced_style::toggler::{Style, StyleSheet};
/// Makes sure that the border radius of the toggler looks good at every size.
const BORDER_RADIUS_RATIO: f32 = 32.0 / 13.0;
/// The space ratio between the background Quad and the Toggler bounds, and
/// between the background Quad and foreground Quad.
const SPACE_RATIO: f32 = 0.05;
/// A toggler that can be toggled. /// A toggler that can be toggled.
/// ///
/// This is an alias of an `iced_native` toggler with an `iced_wgpu::Renderer`. /// This is an alias of an `iced_native` toggler with an `iced_wgpu::Renderer`.
@ -27,73 +18,4 @@ where
type Style = Box<dyn StyleSheet>; type Style = Box<dyn StyleSheet>;
const DEFAULT_SIZE: u16 = 20; const DEFAULT_SIZE: u16 = 20;
fn draw(
&mut self,
bounds: Rectangle,
is_active: bool,
is_mouse_over: bool,
label: Option<Self::Output>,
style_sheet: &Self::Style,
) -> Self::Output {
let style = if is_mouse_over {
style_sheet.hovered(is_active)
} else {
style_sheet.active(is_active)
};
let border_radius = bounds.height as f32 / BORDER_RADIUS_RATIO;
let space = SPACE_RATIO * bounds.height as f32;
let toggler_background_bounds = Rectangle {
x: bounds.x + space,
y: bounds.y + space,
width: bounds.width - (2.0 * space),
height: bounds.height - (2.0 * space),
};
let toggler_background = Primitive::Quad {
bounds: toggler_background_bounds,
background: style.background.into(),
border_radius,
border_width: 1.0,
border_color: style.background_border.unwrap_or(style.background),
};
let toggler_foreground_bounds = Rectangle {
x: bounds.x
+ if is_active {
bounds.width - 2.0 * space - (bounds.height - (4.0 * space))
} else {
2.0 * space
},
y: bounds.y + (2.0 * space),
width: bounds.height - (4.0 * space),
height: bounds.height - (4.0 * space),
};
let toggler_foreground = Primitive::Quad {
bounds: toggler_foreground_bounds,
background: style.foreground.into(),
border_radius,
border_width: 1.0,
border_color: style.foreground_border.unwrap_or(style.foreground),
};
(
Primitive::Group {
primitives: match label {
Some((l, _)) => {
vec![l, toggler_background, toggler_foreground]
}
None => vec![toggler_background, toggler_foreground],
},
},
if is_mouse_over {
mouse::Interaction::Pointer
} else {
mouse::Interaction::default()
},
)
}
} }

View file

@ -1,11 +1,6 @@
//! Decorate content and apply alignment. //! Decorate content and apply alignment.
use crate::backend::{self, Backend}; use crate::backend::{self, Backend};
use crate::defaults::{self, Defaults}; use crate::Renderer;
use crate::{Primitive, Renderer, Vector};
use iced_native::container;
use iced_native::layout::{self, Layout};
use iced_native::{Element, Padding, Point, Rectangle, Size, Text};
/// An element decorating some content. /// An element decorating some content.
/// ///
@ -21,148 +16,4 @@ where
B: Backend + backend::Text, B: Backend + backend::Text,
{ {
const DEFAULT_PADDING: u16 = 5; const DEFAULT_PADDING: u16 = 5;
fn draw<Message>(
&mut self,
defaults: &Defaults,
cursor_position: Point,
content_layout: Layout<'_>,
viewport: &Rectangle,
content: &Element<'_, Message, Self>,
tooltip: &Text<Self>,
position: Position,
style_sheet: &<Self as container::Renderer>::Style,
gap: u16,
padding: u16,
) -> Self::Output {
let (content, mouse_interaction) = content.draw(
self,
&defaults,
content_layout,
cursor_position,
viewport,
);
let bounds = content_layout.bounds();
if bounds.contains(cursor_position) {
use iced_native::Widget;
let gap = f32::from(gap);
let style = style_sheet.style();
let defaults = Defaults {
text: defaults::Text {
color: style.text_color.unwrap_or(defaults.text.color),
},
};
let text_layout = Widget::<(), Self>::layout(
tooltip,
self,
&layout::Limits::new(Size::ZERO, viewport.size())
.pad(Padding::new(padding)),
);
let padding = f32::from(padding);
let text_bounds = text_layout.bounds();
let x_center = bounds.x + (bounds.width - text_bounds.width) / 2.0;
let y_center =
bounds.y + (bounds.height - text_bounds.height) / 2.0;
let mut tooltip_bounds = {
let offset = match position {
Position::Top => Vector::new(
x_center,
bounds.y - text_bounds.height - gap - padding,
),
Position::Bottom => Vector::new(
x_center,
bounds.y + bounds.height + gap + padding,
),
Position::Left => Vector::new(
bounds.x - text_bounds.width - gap - padding,
y_center,
),
Position::Right => Vector::new(
bounds.x + bounds.width + gap + padding,
y_center,
),
Position::FollowCursor => Vector::new(
cursor_position.x,
cursor_position.y - text_bounds.height,
),
};
Rectangle {
x: offset.x - padding,
y: offset.y - padding,
width: text_bounds.width + padding * 2.0,
height: text_bounds.height + padding * 2.0,
}
};
if tooltip_bounds.x < viewport.x {
tooltip_bounds.x = viewport.x;
} else if viewport.x + viewport.width
< tooltip_bounds.x + tooltip_bounds.width
{
tooltip_bounds.x =
viewport.x + viewport.width - tooltip_bounds.width;
}
if tooltip_bounds.y < viewport.y {
tooltip_bounds.y = viewport.y;
} else if viewport.y + viewport.height
< tooltip_bounds.y + tooltip_bounds.height
{
tooltip_bounds.y =
viewport.y + viewport.height - tooltip_bounds.height;
}
let (tooltip, _) = Widget::<(), Self>::draw(
tooltip,
self,
&defaults,
Layout::with_offset(
Vector::new(
tooltip_bounds.x + padding,
tooltip_bounds.y + padding,
),
&text_layout,
),
cursor_position,
viewport,
);
(
Primitive::Group {
primitives: vec![
content,
Primitive::Clip {
bounds: *viewport,
offset: Vector::new(0, 0),
content: Box::new(
if let Some(background) =
crate::container::background(
tooltip_bounds,
&style,
)
{
Primitive::Group {
primitives: vec![background, tooltip],
}
} else {
tooltip
},
),
},
],
},
mouse_interaction,
)
} else {
(content, mouse_interaction)
}
}
} }

View file

@ -1,7 +1,5 @@
use crate::{Color, Error, Viewport}; use crate::{Color, Error, Viewport};
use iced_native::mouse;
use raw_window_handle::HasRawWindowHandle; use raw_window_handle::HasRawWindowHandle;
use thiserror::Error; use thiserror::Error;
@ -30,9 +28,8 @@ pub trait Compositor: Sized {
window: &W, window: &W,
) -> Self::Surface; ) -> Self::Surface;
/// Crates a new [`SwapChain`] for the given [`Surface`]. /// Configures a new [`Surface`] with the given dimensions.
/// ///
/// [`SwapChain`]: Self::SwapChain
/// [`Surface`]: Self::Surface /// [`Surface`]: Self::Surface
fn configure_surface( fn configure_surface(
&mut self, &mut self,
@ -41,18 +38,17 @@ pub trait Compositor: Sized {
height: u32, height: u32,
); );
/// Draws the output primitives to the next frame of the given [`SwapChain`]. /// Presents the [`Renderer`] primitives to the next frame of the given [`Surface`].
/// ///
/// [`SwapChain`]: Self::SwapChain /// [`SwapChain`]: Self::SwapChain
fn draw<T: AsRef<str>>( fn present<T: AsRef<str>>(
&mut self, &mut self,
renderer: &mut Self::Renderer, renderer: &mut Self::Renderer,
surface: &mut Self::Surface, surface: &mut Self::Surface,
viewport: &Viewport, viewport: &Viewport,
background_color: Color, background_color: Color,
output: &<Self::Renderer as iced_native::Renderer>::Output,
overlay: &[T], overlay: &[T],
) -> Result<mouse::Interaction, SurfaceError>; ) -> Result<(), SurfaceError>;
} }
/// Result of an unsuccessful call to [`Compositor::draw`]. /// Result of an unsuccessful call to [`Compositor::draw`].
@ -63,13 +59,13 @@ pub enum SurfaceError {
"A timeout was encountered while trying to acquire the next frame" "A timeout was encountered while trying to acquire the next frame"
)] )]
Timeout, Timeout,
/// The underlying surface has changed, and therefore the swap chain must be updated. /// The underlying surface has changed, and therefore the surface must be updated.
#[error( #[error(
"The underlying surface has changed, and therefore the swap chain must be updated." "The underlying surface has changed, and therefore the surface must be updated."
)] )]
Outdated, Outdated,
/// The swap chain has been lost and needs to be recreated. /// The swap chain has been lost and needs to be recreated.
#[error("The swap chain has been lost and needs to be recreated")] #[error("The surface has been lost and needs to be recreated")]
Lost, Lost,
/// There is no more memory left to allocate a new frame. /// There is no more memory left to allocate a new frame.
#[error("There is no more memory left to allocate a new frame")] #[error("There is no more memory left to allocate a new frame")]

View file

@ -1,5 +1,4 @@
use crate::{Color, Error, Size, Viewport}; use crate::{Color, Error, Size, Viewport};
use iced_native::mouse;
use core::ffi::c_void; use core::ffi::c_void;
@ -49,15 +48,15 @@ pub trait GLCompositor: Sized {
/// Resizes the viewport of the [`GLCompositor`]. /// Resizes the viewport of the [`GLCompositor`].
fn resize_viewport(&mut self, physical_size: Size<u32>); fn resize_viewport(&mut self, physical_size: Size<u32>);
/// Draws the provided output with the given [`Renderer`]. /// Presents the primitives of the [`Renderer`] to the next frame of the
/// [`GLCompositor`].
/// ///
/// [`Renderer`]: crate::Renderer /// [`Renderer`]: crate::Renderer
fn draw<T: AsRef<str>>( fn present<T: AsRef<str>>(
&mut self, &mut self,
renderer: &mut Self::Renderer, renderer: &mut Self::Renderer,
viewport: &Viewport, viewport: &Viewport,
background_color: Color, background_color: Color,
output: &<Self::Renderer as iced_native::Renderer>::Output,
overlay: &[T], overlay: &[T],
) -> mouse::Interaction; );
} }

View file

@ -189,7 +189,7 @@ where
) -> Element<'a, Message, Renderer> ) -> Element<'a, Message, Renderer>
where where
Message: 'static, Message: 'static,
Renderer: 'a + layout::Debugger, Renderer: 'a,
{ {
Element { Element {
widget: Box::new(Explain::new(self, color.into())), widget: Box::new(Explain::new(self, color.into())),
@ -245,7 +245,7 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
viewport: &Rectangle, viewport: &Rectangle,
) -> Renderer::Output { ) {
self.widget self.widget
.draw(renderer, defaults, layout, cursor_position, viewport) .draw(renderer, defaults, layout, cursor_position, viewport)
} }
@ -340,7 +340,7 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
viewport: &Rectangle, viewport: &Rectangle,
) -> Renderer::Output { ) {
self.widget self.widget
.draw(renderer, defaults, layout, cursor_position, viewport) .draw(renderer, defaults, layout, cursor_position, viewport)
} }
@ -378,7 +378,7 @@ where
impl<'a, Message, Renderer> Widget<Message, Renderer> impl<'a, Message, Renderer> Widget<Message, Renderer>
for Explain<'a, Message, Renderer> for Explain<'a, Message, Renderer>
where where
Renderer: crate::Renderer + layout::Debugger, Renderer: crate::Renderer,
{ {
fn width(&self) -> Length { fn width(&self) -> Length {
self.element.widget.width() self.element.widget.width()
@ -417,20 +417,12 @@ where
fn draw( fn draw(
&self, &self,
renderer: &mut Renderer, _renderer: &mut Renderer,
defaults: &Renderer::Defaults, _defaults: &Renderer::Defaults,
layout: Layout<'_>, _layout: Layout<'_>,
cursor_position: Point, _cursor_position: Point,
viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
renderer.explain(
defaults,
self.element.widget.as_ref(),
layout,
cursor_position,
viewport,
self.color,
)
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {

View file

@ -1,11 +1,9 @@
//! Position your widgets properly. //! Position your widgets properly.
mod debugger;
mod limits; mod limits;
mod node; mod node;
pub mod flex; pub mod flex;
pub use debugger::Debugger;
pub use limits::Limits; pub use limits::Limits;
pub use node::Node; pub use node::Node;

View file

@ -1,24 +0,0 @@
use crate::{Color, Layout, Point, Rectangle, Renderer, Widget};
/// A renderer able to graphically explain a [`Layout`].
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.
///
/// [`Element`]: crate::Element
/// [`Element::explain`]: crate::Element::explain
fn explain<Message>(
&mut self,
defaults: &Self::Defaults,
widget: &dyn Widget<Message, Self>,
layout: Layout<'_>,
cursor_position: Point,
viewport: &Rectangle,
color: Color,
) -> Self::Output;
}

View file

@ -28,7 +28,7 @@
//! [`druid`]: https://github.com/xi-editor/druid //! [`druid`]: https://github.com/xi-editor/druid
//! [`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle //! [`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle
//! [renderer]: crate::renderer //! [renderer]: crate::renderer
#![deny(missing_docs)] //#![deny(missing_docs)]
#![deny(missing_debug_implementations)] #![deny(missing_debug_implementations)]
#![deny(unused_results)] #![deny(unused_results)]
#![forbid(unsafe_code)] #![forbid(unsafe_code)]

View file

@ -35,7 +35,7 @@ where
defaults: &Renderer::Defaults, defaults: &Renderer::Defaults,
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
) -> Renderer::Output; );
/// Computes the _layout_ hash of the [`Overlay`]. /// Computes the _layout_ hash of the [`Overlay`].
/// ///

View file

@ -74,7 +74,7 @@ where
defaults: &Renderer::Defaults, defaults: &Renderer::Defaults,
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
) -> Renderer::Output { ) {
self.overlay self.overlay
.draw(renderer, defaults, layout, cursor_position) .draw(renderer, defaults, layout, cursor_position)
} }
@ -145,7 +145,7 @@ where
defaults: &Renderer::Defaults, defaults: &Renderer::Defaults,
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
) -> Renderer::Output { ) {
self.content self.content
.draw(renderer, defaults, layout, cursor_position) .draw(renderer, defaults, layout, cursor_position)
} }

View file

@ -239,21 +239,22 @@ where
defaults: &Renderer::Defaults, defaults: &Renderer::Defaults,
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
) -> Renderer::Output { ) {
let primitives = self.container.draw( // TODO
renderer, // let primitives = self.container.draw(
defaults, // renderer,
layout, // defaults,
cursor_position, // layout,
&layout.bounds(), // cursor_position,
); // &layout.bounds(),
// );
renderer.decorate( // renderer.decorate(
layout.bounds(), // layout.bounds(),
cursor_position, // cursor_position,
&self.style, // &self.style,
primitives, // primitives,
) // )
} }
} }
@ -378,24 +379,13 @@ where
fn draw( fn draw(
&self, &self,
renderer: &mut Renderer, _renderer: &mut Renderer,
_defaults: &Renderer::Defaults, _defaults: &Renderer::Defaults,
layout: Layout<'_>, _layout: Layout<'_>,
cursor_position: Point, _cursor_position: Point,
viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
self::Renderer::draw( // TODO
renderer,
layout.bounds(),
cursor_position,
viewport,
self.options,
*self.hovered_option,
self.padding,
self.text_size.unwrap_or(renderer.default_size()),
self.font,
&self.style,
)
} }
} }
@ -410,31 +400,6 @@ pub trait Renderer:
{ {
/// The [`Menu`] style supported by this renderer. /// The [`Menu`] style supported by this renderer.
type Style: Default + Clone; type Style: Default + Clone;
/// Decorates a the list of options of a [`Menu`].
///
/// This method can be used to draw a background for the [`Menu`].
fn decorate(
&mut self,
bounds: Rectangle,
cursor_position: Point,
style: &<Self as Renderer>::Style,
primitive: Self::Output,
) -> Self::Output;
/// Draws the list of options of a [`Menu`].
fn draw<T: ToString>(
&mut self,
bounds: Rectangle,
cursor_position: Point,
viewport: &Rectangle,
options: &[T],
hovered_option: Option<usize>,
padding: Padding,
text_size: u16,
font: Self::Font,
style: &<Self as Renderer>::Style,
) -> Self::Output;
} }
impl<'a, T, Message, Renderer> Into<Element<'a, Message, Renderer>> impl<'a, T, Message, Renderer> Into<Element<'a, Message, Renderer>>

View file

@ -1,5 +1,5 @@
use crate::{ use crate::{
Cache, Clipboard, Command, Debug, Event, Point, Program, Renderer, Size, Cache, Clipboard, Command, Debug, Event, Point, Program, Size,
UserInterface, UserInterface,
}; };
@ -12,7 +12,6 @@ where
{ {
program: P, program: P,
cache: Option<Cache>, cache: Option<Cache>,
primitive: <P::Renderer as Renderer>::Output,
queued_events: Vec<Event>, queued_events: Vec<Event>,
queued_messages: Vec<P::Message>, queued_messages: Vec<P::Message>,
} }
@ -38,16 +37,11 @@ where
debug, debug,
); );
debug.draw_started();
let primitive = user_interface.draw(renderer, cursor_position);
debug.draw_finished();
let cache = Some(user_interface.into_cache()); let cache = Some(user_interface.into_cache());
State { State {
program, program,
cache, cache,
primitive,
queued_events: Vec::new(), queued_events: Vec::new(),
queued_messages: Vec::new(), queued_messages: Vec::new(),
} }
@ -58,11 +52,6 @@ where
&self.program &self.program
} }
/// Returns a reference to the current rendering primitive of the [`State`].
pub fn primitive(&self) -> &<P::Renderer as Renderer>::Output {
&self.primitive
}
/// Queues an event in the [`State`] for processing during an [`update`]. /// Queues an event in the [`State`] for processing during an [`update`].
/// ///
/// [`update`]: Self::update /// [`update`]: Self::update
@ -120,7 +109,7 @@ where
if messages.is_empty() { if messages.is_empty() {
debug.draw_started(); debug.draw_started();
self.primitive = user_interface.draw(renderer, cursor_position); user_interface.draw(renderer, cursor_position);
debug.draw_finished(); debug.draw_finished();
self.cache = Some(user_interface.into_cache()); self.cache = Some(user_interface.into_cache());
@ -151,7 +140,7 @@ where
); );
debug.draw_started(); debug.draw_started();
self.primitive = user_interface.draw(renderer, cursor_position); user_interface.draw(renderer, cursor_position);
debug.draw_finished(); debug.draw_finished();
self.cache = Some(user_interface.into_cache()); self.cache = Some(user_interface.into_cache());

View file

@ -30,12 +30,6 @@ use crate::{layout, Element, Rectangle};
/// A component that can take the state of a user interface and produce an /// A component that can take the state of a user interface and produce an
/// output for its users. /// output for its users.
pub trait Renderer: Sized { pub trait Renderer: Sized {
/// The type of output of the [`Renderer`].
///
/// If you are implementing a graphical renderer, your output will most
/// likely be a tree of visual primitives.
type Output;
/// The default styling attributes of the [`Renderer`]. /// The default styling attributes of the [`Renderer`].
/// ///
/// This type can be leveraged to implement style inheritance. /// This type can be leveraged to implement style inheritance.
@ -53,12 +47,5 @@ pub trait Renderer: Sized {
element.layout(self, limits) element.layout(self, limits)
} }
/// Overlays the `overlay` output with the given bounds on top of the `base` fn with_layer(&mut self, bounds: Rectangle, f: impl FnOnce(&mut Self));
/// output.
fn overlay(
&mut self,
base: Self::Output,
overlay: Self::Output,
overlay_bounds: Rectangle,
) -> Self::Output;
} }

View file

@ -1,20 +1,15 @@
use crate::alignment;
use crate::button; use crate::button;
use crate::checkbox; use crate::checkbox;
use crate::column;
use crate::container; use crate::container;
use crate::pane_grid; use crate::pane_grid;
use crate::progress_bar; use crate::progress_bar;
use crate::radio; use crate::radio;
use crate::row;
use crate::scrollable; use crate::scrollable;
use crate::slider; use crate::slider;
use crate::text; use crate::text;
use crate::text_input; use crate::text_input;
use crate::toggler; use crate::toggler;
use crate::{ use crate::{Font, Padding, Point, Rectangle, Renderer, Size};
Color, Element, Font, Layout, Padding, Point, Rectangle, Renderer, Size,
};
/// A renderer that does nothing. /// A renderer that does nothing.
/// ///
@ -30,35 +25,9 @@ impl Null {
} }
impl Renderer for Null { impl Renderer for Null {
type Output = ();
type Defaults = (); type Defaults = ();
fn overlay(&mut self, _base: (), _overlay: (), _overlay_bounds: Rectangle) { fn with_layer(&mut self, _bounds: Rectangle, _f: impl FnOnce(&mut Self)) {}
}
}
impl column::Renderer for Null {
fn draw<Message>(
&mut self,
_defaults: &Self::Defaults,
_content: &[Element<'_, Message, Self>],
_layout: Layout<'_>,
_cursor_position: Point,
_viewport: &Rectangle,
) {
}
}
impl row::Renderer for Null {
fn draw<Message>(
&mut self,
_defaults: &Self::Defaults,
_content: &[Element<'_, Message, Self>],
_layout: Layout<'_>,
_cursor_position: Point,
_viewport: &Rectangle,
) {
}
} }
impl text::Renderer for Null { impl text::Renderer for Null {
@ -89,19 +58,6 @@ impl text::Renderer for Null {
) -> Option<text::Hit> { ) -> Option<text::Hit> {
None None
} }
fn draw(
&mut self,
_defaults: &Self::Defaults,
_bounds: Rectangle,
_content: &str,
_size: u16,
_font: Font,
_color: Option<Color>,
_horizontal_alignment: alignment::Horizontal,
_vertical_alignment: alignment::Vertical,
) {
}
} }
impl scrollable::Renderer for Null { impl scrollable::Renderer for Null {
@ -118,20 +74,6 @@ impl scrollable::Renderer for Null {
) -> Option<scrollable::Scrollbar> { ) -> Option<scrollable::Scrollbar> {
None None
} }
fn draw(
&mut self,
_scrollable: &scrollable::State,
_bounds: Rectangle,
_content_bounds: Rectangle,
_is_mouse_over: bool,
_is_mouse_over_scrollbar: bool,
_scrollbar: Option<scrollable::Scrollbar>,
_offset: u32,
_style: &Self::Style,
_content: Self::Output,
) {
}
} }
impl text_input::Renderer for Null { impl text_input::Renderer for Null {
@ -151,39 +93,12 @@ impl text_input::Renderer for Null {
) -> f32 { ) -> f32 {
0.0 0.0
} }
fn draw(
&mut self,
_bounds: Rectangle,
_text_bounds: Rectangle,
_cursor_position: Point,
_font: Font,
_size: u16,
_placeholder: &str,
_value: &text_input::Value,
_state: &text_input::State,
_style: &Self::Style,
) -> Self::Output {
}
} }
impl button::Renderer for Null { impl button::Renderer for Null {
const DEFAULT_PADDING: Padding = Padding::ZERO; const DEFAULT_PADDING: Padding = Padding::ZERO;
type Style = (); type Style = ();
fn draw<Message>(
&mut self,
_defaults: &Self::Defaults,
_bounds: Rectangle,
_cursor_position: Point,
_is_disabled: bool,
_is_pressed: bool,
_style: &Self::Style,
_content: &Element<'_, Message, Self>,
_content_layout: Layout<'_>,
) -> Self::Output {
}
} }
impl radio::Renderer for Null { impl radio::Renderer for Null {
@ -191,16 +106,6 @@ impl radio::Renderer for Null {
const DEFAULT_SIZE: u16 = 20; const DEFAULT_SIZE: u16 = 20;
const DEFAULT_SPACING: u16 = 15; const DEFAULT_SPACING: u16 = 15;
fn draw(
&mut self,
_bounds: Rectangle,
_is_selected: bool,
_is_mouse_over: bool,
_label: Self::Output,
_style: &Self::Style,
) {
}
} }
impl checkbox::Renderer for Null { impl checkbox::Renderer for Null {
@ -208,122 +113,30 @@ impl checkbox::Renderer for Null {
const DEFAULT_SIZE: u16 = 20; const DEFAULT_SIZE: u16 = 20;
const DEFAULT_SPACING: u16 = 15; const DEFAULT_SPACING: u16 = 15;
fn draw(
&mut self,
_bounds: Rectangle,
_is_checked: bool,
_is_mouse_over: bool,
_label: Self::Output,
_style: &Self::Style,
) {
}
} }
impl slider::Renderer for Null { impl slider::Renderer for Null {
type Style = (); type Style = ();
const DEFAULT_HEIGHT: u16 = 30; const DEFAULT_HEIGHT: u16 = 30;
fn draw(
&mut self,
_bounds: Rectangle,
_cursor_position: Point,
_range: std::ops::RangeInclusive<f32>,
_value: f32,
_is_dragging: bool,
_style_sheet: &Self::Style,
) {
}
} }
impl progress_bar::Renderer for Null { impl progress_bar::Renderer for Null {
type Style = (); type Style = ();
const DEFAULT_HEIGHT: u16 = 30; const DEFAULT_HEIGHT: u16 = 30;
fn draw(
&self,
_bounds: Rectangle,
_range: std::ops::RangeInclusive<f32>,
_value: f32,
_style: &Self::Style,
) {
}
} }
impl container::Renderer for Null { impl container::Renderer for Null {
type Style = (); type Style = ();
fn draw<Message>(
&mut self,
_defaults: &Self::Defaults,
_bounds: Rectangle,
_cursor_position: Point,
_viewport: &Rectangle,
_style: &Self::Style,
_content: &Element<'_, Message, Self>,
_content_layout: Layout<'_>,
) {
}
} }
impl pane_grid::Renderer for Null { impl pane_grid::Renderer for Null {
type Style = (); type Style = ();
fn draw<Message>(
&mut self,
_defaults: &Self::Defaults,
_content: &[(pane_grid::Pane, pane_grid::Content<'_, Message, Self>)],
_dragging: Option<(pane_grid::Pane, Point)>,
_resizing: Option<(pane_grid::Axis, Rectangle, bool)>,
_layout: Layout<'_>,
_style: &<Self as pane_grid::Renderer>::Style,
_cursor_position: Point,
_viewport: &Rectangle,
) {
}
fn draw_pane<Message>(
&mut self,
_defaults: &Self::Defaults,
_bounds: Rectangle,
_style: &<Self as container::Renderer>::Style,
_title_bar: Option<(
&pane_grid::TitleBar<'_, Message, Self>,
Layout<'_>,
)>,
_body: (&Element<'_, Message, Self>, Layout<'_>),
_cursor_position: Point,
_viewport: &Rectangle,
) {
}
fn draw_title_bar<Message>(
&mut self,
_defaults: &Self::Defaults,
_bounds: Rectangle,
_style: &<Self as container::Renderer>::Style,
_content: (&Element<'_, Message, Self>, Layout<'_>),
_controls: Option<(&Element<'_, Message, Self>, Layout<'_>)>,
_cursor_position: Point,
_viewport: &Rectangle,
) {
}
} }
impl toggler::Renderer for Null { impl toggler::Renderer for Null {
type Style = (); type Style = ();
const DEFAULT_SIZE: u16 = 20; const DEFAULT_SIZE: u16 = 20;
fn draw(
&mut self,
_bounds: Rectangle,
_is_checked: bool,
_is_mouse_over: bool,
_label: Option<Self::Output>,
_style: &Self::Style,
) {
}
} }

View file

@ -329,11 +329,7 @@ where
/// // Flush rendering operations... /// // Flush rendering operations...
/// } /// }
/// ``` /// ```
pub fn draw( pub fn draw(&mut self, renderer: &mut Renderer, cursor_position: Point) {
&mut self,
renderer: &mut Renderer,
cursor_position: Point,
) -> Renderer::Output {
let viewport = Rectangle::with_size(self.bounds); let viewport = Rectangle::with_size(self.bounds);
let overlay = if let Some(mut overlay) = let overlay = if let Some(mut overlay) =
@ -348,40 +344,36 @@ where
let overlay_bounds = layer.layout.bounds(); let overlay_bounds = layer.layout.bounds();
let overlay_primitives = overlay.draw( renderer.with_layer(overlay_bounds, |renderer| {
renderer, overlay.draw(
&Renderer::Defaults::default(), renderer,
Layout::new(&layer.layout), &Renderer::Defaults::default(),
cursor_position, Layout::new(&layer.layout),
); cursor_position,
);
});
self.overlay = Some(layer); self.overlay = Some(layer);
Some((overlay_primitives, overlay_bounds)) Some(overlay_bounds)
} else { } else {
None None
}; };
if let Some((overlay_primitives, overlay_bounds)) = overlay { if let Some(overlay_bounds) = overlay {
let base_cursor = if overlay_bounds.contains(cursor_position) { let base_cursor = if overlay_bounds.contains(cursor_position) {
Point::new(-1.0, -1.0) Point::new(-1.0, -1.0)
} else { } else {
cursor_position cursor_position
}; };
let base_primitives = self.root.widget.draw( self.root.widget.draw(
renderer, renderer,
&Renderer::Defaults::default(), &Renderer::Defaults::default(),
Layout::new(&self.base.layout), Layout::new(&self.base.layout),
base_cursor, base_cursor,
&viewport, &viewport,
); );
renderer.overlay(
base_primitives,
overlay_primitives,
overlay_bounds,
)
} else { } else {
self.root.widget.draw( self.root.widget.draw(
renderer, renderer,
@ -389,7 +381,7 @@ where
Layout::new(&self.base.layout), Layout::new(&self.base.layout),
cursor_position, cursor_position,
&viewport, &viewport,
) );
} }
} }

View file

@ -135,7 +135,7 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
viewport: &Rectangle, viewport: &Rectangle,
) -> Renderer::Output; );
/// Computes the _layout_ hash of the [`Widget`]. /// Computes the _layout_ hash of the [`Widget`].
/// ///

View file

@ -248,17 +248,7 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
renderer.draw(
defaults,
layout.bounds(),
cursor_position,
self.on_press.is_none(),
self.state.is_pressed,
&self.style,
&self.content,
layout.children().next().unwrap(),
)
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -289,19 +279,6 @@ pub trait Renderer: crate::Renderer + Sized {
/// The style supported by this renderer. /// The style supported by this renderer.
type Style: Default; type Style: Default;
/// Draws a [`Button`].
fn draw<Message>(
&mut self,
defaults: &Self::Defaults,
bounds: Rectangle,
cursor_position: Point,
is_disabled: bool,
is_pressed: bool,
style: &Self::Style,
content: &Element<'_, Message, Self>,
content_layout: Layout<'_>,
) -> Self::Output;
} }
impl<'a, Message, Renderer> From<Button<'a, Message, Renderer>> impl<'a, Message, Renderer> From<Button<'a, Message, Renderer>>

View file

@ -5,7 +5,6 @@ use crate::alignment::{self, Alignment};
use crate::event::{self, Event}; use crate::event::{self, Event};
use crate::layout; use crate::layout;
use crate::mouse; use crate::mouse;
use crate::row;
use crate::text; use crate::text;
use crate::touch; use crate::touch;
use crate::{ use crate::{
@ -121,7 +120,7 @@ impl<Message, Renderer: self::Renderer + text::Renderer>
impl<Message, Renderer> Widget<Message, Renderer> impl<Message, Renderer> Widget<Message, Renderer>
for Checkbox<Message, Renderer> for Checkbox<Message, Renderer>
where where
Renderer: self::Renderer + text::Renderer + row::Renderer, Renderer: self::Renderer + text::Renderer,
{ {
fn width(&self) -> Length { fn width(&self) -> Length {
self.width self.width
@ -187,36 +186,29 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
let bounds = layout.bounds(); // let bounds = layout.bounds();
let mut children = layout.children(); // let mut children = layout.children();
let checkbox_layout = children.next().unwrap(); // let checkbox_layout = children.next().unwrap();
let label_layout = children.next().unwrap(); // let label_layout = children.next().unwrap();
let checkbox_bounds = checkbox_layout.bounds(); // let checkbox_bounds = checkbox_layout.bounds();
let label = text::Renderer::draw( // let label = text::Renderer::draw(
renderer, // renderer,
defaults, // defaults,
label_layout.bounds(), // label_layout.bounds(),
&self.label, // &self.label,
self.text_size.unwrap_or(renderer.default_size()), // self.text_size.unwrap_or(renderer.default_size()),
self.font, // self.font,
self.text_color, // self.text_color,
alignment::Horizontal::Left, // alignment::Horizontal::Left,
alignment::Vertical::Center, // alignment::Vertical::Center,
); // );
let is_mouse_over = bounds.contains(cursor_position); // let is_mouse_over = bounds.contains(cursor_position);
self::Renderer::draw( // TODO
renderer,
checkbox_bounds,
self.is_checked,
is_mouse_over,
label,
&self.style,
)
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -242,28 +234,12 @@ pub trait Renderer: crate::Renderer {
/// The default spacing of a [`Checkbox`]. /// The default spacing of a [`Checkbox`].
const DEFAULT_SPACING: u16; const DEFAULT_SPACING: u16;
/// Draws a [`Checkbox`].
///
/// It receives:
/// * the bounds of the [`Checkbox`]
/// * whether the [`Checkbox`] is selected or not
/// * whether the mouse is over the [`Checkbox`] or not
/// * the drawn label of the [`Checkbox`]
fn draw(
&mut self,
bounds: Rectangle,
is_checked: bool,
is_mouse_over: bool,
label: Self::Output,
style: &Self::Style,
) -> Self::Output;
} }
impl<'a, Message, Renderer> From<Checkbox<Message, Renderer>> impl<'a, Message, Renderer> From<Checkbox<Message, Renderer>>
for Element<'a, Message, Renderer> for Element<'a, Message, Renderer>
where where
Renderer: 'a + self::Renderer + text::Renderer + row::Renderer, Renderer: 'a + self::Renderer + text::Renderer,
Message: 'a, Message: 'a,
{ {
fn from( fn from(

View file

@ -105,7 +105,7 @@ impl<'a, Message, Renderer> Column<'a, Message, Renderer> {
impl<'a, Message, Renderer> Widget<Message, Renderer> impl<'a, Message, Renderer> Widget<Message, Renderer>
for Column<'a, Message, Renderer> for Column<'a, Message, Renderer>
where where
Renderer: self::Renderer, Renderer: crate::Renderer,
{ {
fn width(&self) -> Length { fn width(&self) -> Length {
self.width self.width
@ -169,14 +169,8 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
viewport: &Rectangle, viewport: &Rectangle,
) -> Renderer::Output { ) {
renderer.draw( // TODO
defaults,
&self.children,
layout,
cursor_position,
viewport,
)
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -208,33 +202,10 @@ where
} }
} }
/// The renderer of a [`Column`].
///
/// Your [renderer] will need to implement this trait before being
/// able to use a [`Column`] in your user interface.
///
/// [renderer]: crate::renderer
pub trait Renderer: crate::Renderer + Sized {
/// Draws a [`Column`].
///
/// It receives:
/// - the children of the [`Column`]
/// - the [`Layout`] of the [`Column`] and its children
/// - the cursor position
fn draw<Message>(
&mut self,
defaults: &Self::Defaults,
content: &[Element<'_, Message, Self>],
layout: Layout<'_>,
cursor_position: Point,
viewport: &Rectangle,
) -> Self::Output;
}
impl<'a, Message, Renderer> From<Column<'a, Message, Renderer>> impl<'a, Message, Renderer> From<Column<'a, Message, Renderer>>
for Element<'a, Message, Renderer> for Element<'a, Message, Renderer>
where where
Renderer: 'a + self::Renderer, Renderer: 'a + crate::Renderer,
Message: 'a, Message: 'a,
{ {
fn from( fn from(

View file

@ -179,16 +179,8 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
viewport: &Rectangle, viewport: &Rectangle,
) -> Renderer::Output { ) {
renderer.draw( // TODO
defaults,
layout.bounds(),
cursor_position,
viewport,
&self.style,
&self.content,
layout.children().next().unwrap(),
)
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -221,18 +213,6 @@ where
pub trait Renderer: crate::Renderer { pub trait Renderer: crate::Renderer {
/// The style supported by this renderer. /// The style supported by this renderer.
type Style: Default; type Style: Default;
/// Draws a [`Container`].
fn draw<Message>(
&mut self,
defaults: &Self::Defaults,
bounds: Rectangle,
cursor_position: Point,
viewport: &Rectangle,
style: &Self::Style,
content: &Element<'_, Message, Self>,
content_layout: Layout<'_>,
) -> Self::Output;
} }
impl<'a, Message, Renderer> From<Container<'a, Message, Renderer>> impl<'a, Message, Renderer> From<Container<'a, Message, Renderer>>

View file

@ -96,8 +96,8 @@ where
layout: Layout<'_>, layout: Layout<'_>,
_cursor_position: Point, _cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
renderer.draw(self.handle.clone(), layout) // TODO
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -225,9 +225,6 @@ impl std::fmt::Debug for Data {
pub trait Renderer: crate::Renderer { pub trait Renderer: crate::Renderer {
/// Returns the dimensions of an [`Image`] located on the given path. /// Returns the dimensions of an [`Image`] located on the given path.
fn dimensions(&self, handle: &Handle) -> (u32, u32); fn dimensions(&self, handle: &Handle) -> (u32, u32);
/// Draws an [`Image`].
fn draw(&mut self, handle: Handle, layout: Layout<'_>) -> Self::Output;
} }
impl<'a, Message, Renderer> From<Image> for Element<'a, Message, Renderer> impl<'a, Message, Renderer> From<Image> for Element<'a, Message, Renderer>

View file

@ -88,7 +88,7 @@ impl<'a> Viewer<'a> {
/// will be respected. /// will be respected.
fn image_size<Renderer>(&self, renderer: &Renderer, bounds: Size) -> Size fn image_size<Renderer>(&self, renderer: &Renderer, bounds: Size) -> Size
where where
Renderer: self::Renderer + image::Renderer, Renderer: image::Renderer,
{ {
let (width, height) = renderer.dimensions(&self.handle); let (width, height) = renderer.dimensions(&self.handle);
@ -115,7 +115,7 @@ impl<'a> Viewer<'a> {
impl<'a, Message, Renderer> Widget<Message, Renderer> for Viewer<'a> impl<'a, Message, Renderer> Widget<Message, Renderer> for Viewer<'a>
where where
Renderer: self::Renderer + image::Renderer, Renderer: image::Renderer,
{ {
fn width(&self) -> Length { fn width(&self) -> Length {
self.width self.width
@ -287,7 +287,7 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
let bounds = layout.bounds(); let bounds = layout.bounds();
let image_size = self.image_size(renderer, bounds.size()); let image_size = self.image_size(renderer, bounds.size());
@ -302,16 +302,6 @@ where
}; };
let is_mouse_over = bounds.contains(cursor_position); let is_mouse_over = bounds.contains(cursor_position);
self::Renderer::draw(
renderer,
&self.state,
bounds,
image_size,
translation,
self.handle.clone(),
is_mouse_over,
)
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -373,38 +363,9 @@ impl State {
} }
} }
/// The renderer of an [`Viewer`].
///
/// Your [renderer] will need to implement this trait before being
/// able to use a [`Viewer`] in your user interface.
///
/// [renderer]: crate::renderer
pub trait Renderer: crate::Renderer + Sized {
/// Draws the [`Viewer`].
///
/// It receives:
/// - the [`State`] of the [`Viewer`]
/// - the bounds of the [`Viewer`] widget
/// - the [`Size`] of the scaled [`Viewer`] image
/// - the translation of the clipped image
/// - the [`Handle`] to the underlying image
/// - whether the mouse is over the [`Viewer`] or not
///
/// [`Handle`]: image::Handle
fn draw(
&mut self,
state: &State,
bounds: Rectangle,
image_size: Size,
translation: Vector,
handle: image::Handle,
is_mouse_over: bool,
) -> Self::Output;
}
impl<'a, Message, Renderer> From<Viewer<'a>> for Element<'a, Message, Renderer> impl<'a, Message, Renderer> From<Viewer<'a>> for Element<'a, Message, Renderer>
where where
Renderer: 'a + self::Renderer + image::Renderer, Renderer: 'a + image::Renderer,
Message: 'a, Message: 'a,
{ {
fn from(viewer: Viewer<'a>) -> Element<'a, Message, Renderer> { fn from(viewer: Viewer<'a>) -> Element<'a, Message, Renderer> {

View file

@ -32,7 +32,6 @@ use crate::event::{self, Event};
use crate::layout; use crate::layout;
use crate::mouse; use crate::mouse;
use crate::overlay; use crate::overlay;
use crate::row;
use crate::touch; use crate::touch;
use crate::{ use crate::{
Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Size, Vector, Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Size, Vector,
@ -480,66 +479,56 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
viewport: &Rectangle, viewport: &Rectangle,
) -> Renderer::Output { ) {
let picked_split = self // let picked_split = self
.state // .state
.picked_split() // .picked_split()
.and_then(|(split, axis)| { // .and_then(|(split, axis)| {
let bounds = layout.bounds(); // let bounds = layout.bounds();
let splits = self // let splits = self
.state // .state
.split_regions(f32::from(self.spacing), bounds.size()); // .split_regions(f32::from(self.spacing), bounds.size());
let (_axis, region, ratio) = splits.get(&split)?; // let (_axis, region, ratio) = splits.get(&split)?;
let region = axis.split_line_bounds( // let region = axis.split_line_bounds(
*region, // *region,
*ratio, // *ratio,
f32::from(self.spacing), // f32::from(self.spacing),
); // );
Some((axis, region + Vector::new(bounds.x, bounds.y), true)) // Some((axis, region + Vector::new(bounds.x, bounds.y), true))
}) // })
.or_else(|| match self.on_resize { // .or_else(|| match self.on_resize {
Some((leeway, _)) => { // Some((leeway, _)) => {
let bounds = layout.bounds(); // let bounds = layout.bounds();
let relative_cursor = Point::new( // let relative_cursor = Point::new(
cursor_position.x - bounds.x, // cursor_position.x - bounds.x,
cursor_position.y - bounds.y, // cursor_position.y - bounds.y,
); // );
let splits = self // let splits = self
.state // .state
.split_regions(f32::from(self.spacing), bounds.size()); // .split_regions(f32::from(self.spacing), bounds.size());
let (_split, axis, region) = hovered_split( // let (_split, axis, region) = hovered_split(
splits.iter(), // splits.iter(),
f32::from(self.spacing + leeway), // f32::from(self.spacing + leeway),
relative_cursor, // relative_cursor,
)?; // )?;
Some(( // Some((
axis, // axis,
region + Vector::new(bounds.x, bounds.y), // region + Vector::new(bounds.x, bounds.y),
false, // false,
)) // ))
} // }
None => None, // None => None,
}); // });
self::Renderer::draw( // TODO
renderer,
defaults,
&self.elements,
self.state.picked_pane(),
picked_split,
layout,
&self.style,
cursor_position,
viewport,
)
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -578,69 +567,12 @@ where
pub trait Renderer: crate::Renderer + container::Renderer + Sized { pub trait Renderer: crate::Renderer + container::Renderer + Sized {
/// The style supported by this renderer. /// The style supported by this renderer.
type Style: Default; type Style: Default;
/// Draws a [`PaneGrid`].
///
/// It receives:
/// - the elements of the [`PaneGrid`]
/// - the [`Pane`] that is currently being dragged
/// - the [`Axis`] that is currently being resized
/// - the [`Layout`] of the [`PaneGrid`] and its elements
/// - the cursor position
fn draw<Message>(
&mut self,
defaults: &Self::Defaults,
content: &[(Pane, Content<'_, Message, Self>)],
dragging: Option<(Pane, Point)>,
resizing: Option<(Axis, Rectangle, bool)>,
layout: Layout<'_>,
style: &<Self as self::Renderer>::Style,
cursor_position: Point,
viewport: &Rectangle,
) -> Self::Output;
/// Draws a [`Pane`].
///
/// It receives:
/// - the [`TitleBar`] of the [`Pane`], if any
/// - the [`Content`] of the [`Pane`]
/// - the [`Layout`] of the [`Pane`] and its elements
/// - the cursor position
fn draw_pane<Message>(
&mut self,
defaults: &Self::Defaults,
bounds: Rectangle,
style: &<Self as container::Renderer>::Style,
title_bar: Option<(&TitleBar<'_, Message, Self>, Layout<'_>)>,
body: (&Element<'_, Message, Self>, Layout<'_>),
cursor_position: Point,
viewport: &Rectangle,
) -> Self::Output;
/// Draws a [`TitleBar`].
///
/// It receives:
/// - the bounds, style of the [`TitleBar`]
/// - the style of the [`TitleBar`]
/// - the content of the [`TitleBar`] with its layout
/// - the controls of the [`TitleBar`] with their [`Layout`], if any
/// - the cursor position
fn draw_title_bar<Message>(
&mut self,
defaults: &Self::Defaults,
bounds: Rectangle,
style: &<Self as container::Renderer>::Style,
content: (&Element<'_, Message, Self>, Layout<'_>),
controls: Option<(&Element<'_, Message, Self>, Layout<'_>)>,
cursor_position: Point,
viewport: &Rectangle,
) -> Self::Output;
} }
impl<'a, Message, Renderer> From<PaneGrid<'a, Message, Renderer>> impl<'a, Message, Renderer> From<PaneGrid<'a, Message, Renderer>>
for Element<'a, Message, Renderer> for Element<'a, Message, Renderer>
where where
Renderer: 'a + self::Renderer + row::Renderer, Renderer: 'a + self::Renderer,
Message: 'a, Message: 'a,
{ {
fn from( fn from(

View file

@ -61,32 +61,33 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
viewport: &Rectangle, viewport: &Rectangle,
) -> Renderer::Output { ) {
if let Some(title_bar) = &self.title_bar { // TODO
let mut children = layout.children(); // if let Some(title_bar) = &self.title_bar {
let title_bar_layout = children.next().unwrap(); // let mut children = layout.children();
let body_layout = children.next().unwrap(); // let title_bar_layout = children.next().unwrap();
// let body_layout = children.next().unwrap();
renderer.draw_pane( // renderer.draw_pane(
defaults, // defaults,
layout.bounds(), // layout.bounds(),
&self.style, // &self.style,
Some((title_bar, title_bar_layout)), // Some((title_bar, title_bar_layout)),
(&self.body, body_layout), // (&self.body, body_layout),
cursor_position, // cursor_position,
viewport, // viewport,
) // )
} else { // } else {
renderer.draw_pane( // renderer.draw_pane(
defaults, // defaults,
layout.bounds(), // layout.bounds(),
&self.style, // &self.style,
None, // None,
(&self.body, layout), // (&self.body, layout),
cursor_position, // cursor_position,
viewport, // viewport,
) // )
} // }
} }
/// Returns whether the [`Content`] with the given [`Layout`] can be picked /// Returns whether the [`Content`] with the given [`Layout`] can be picked

View file

@ -90,34 +90,34 @@ where
cursor_position: Point, cursor_position: Point,
viewport: &Rectangle, viewport: &Rectangle,
show_controls: bool, show_controls: bool,
) -> Renderer::Output { ) {
let mut children = layout.children(); // let mut children = layout.children();
let padded = children.next().unwrap(); // let padded = children.next().unwrap();
let mut children = padded.children(); // let mut children = padded.children();
let title_layout = children.next().unwrap(); // let title_layout = children.next().unwrap();
let controls = if let Some(controls) = &self.controls { // let controls = if let Some(controls) = &self.controls {
let controls_layout = children.next().unwrap(); // let controls_layout = children.next().unwrap();
if show_controls || self.always_show_controls { // if show_controls || self.always_show_controls {
Some((controls, controls_layout)) // Some((controls, controls_layout))
} else { // } else {
None // None
} // }
} else { // } else {
None // None
}; // };
renderer.draw_title_bar( // renderer.draw_title_bar(
defaults, // defaults,
layout.bounds(), // layout.bounds(),
&self.style, // &self.style,
(&self.content, title_layout), // (&self.content, title_layout),
controls, // controls,
cursor_position, // cursor_position,
viewport, // viewport,
) // )
} }
/// Returns whether the mouse cursor is over the pick area of the /// Returns whether the mouse cursor is over the pick area of the

View file

@ -327,18 +327,8 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
self::Renderer::draw( // TODO
renderer,
layout.bounds(),
cursor_position,
self.selected.as_ref().map(ToString::to_string),
self.placeholder.as_ref().map(String::as_str),
self.padding,
self.text_size.unwrap_or(renderer.default_size()),
self.font,
&self.style,
)
} }
fn overlay( fn overlay(
@ -387,19 +377,6 @@ pub trait Renderer: text::Renderer + menu::Renderer {
fn menu_style( fn menu_style(
style: &<Self as Renderer>::Style, style: &<Self as Renderer>::Style,
) -> <Self as menu::Renderer>::Style; ) -> <Self as menu::Renderer>::Style;
/// Draws a [`PickList`].
fn draw(
&mut self,
bounds: Rectangle,
cursor_position: Point,
selected: Option<String>,
placeholder: Option<&str>,
padding: Padding,
text_size: u16,
font: Self::Font,
style: &<Self as Renderer>::Style,
) -> Self::Output;
} }
impl<'a, T: 'a, Message, Renderer> Into<Element<'a, Message, Renderer>> impl<'a, T: 'a, Message, Renderer> Into<Element<'a, Message, Renderer>>

View file

@ -97,13 +97,8 @@ where
layout: Layout<'_>, layout: Layout<'_>,
_cursor_position: Point, _cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
renderer.draw( // TODO
layout.bounds(),
self.range.clone(),
self.value,
&self.style,
)
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -127,22 +122,6 @@ pub trait Renderer: crate::Renderer {
/// The default height of a [`ProgressBar`]. /// The default height of a [`ProgressBar`].
const DEFAULT_HEIGHT: u16; const DEFAULT_HEIGHT: u16;
/// Draws a [`ProgressBar`].
///
/// It receives:
/// * the bounds of the [`ProgressBar`]
/// * the range of values of the [`ProgressBar`]
/// * the current value of the [`ProgressBar`]
/// * maybe a specific background of the [`ProgressBar`]
/// * maybe a specific active color of the [`ProgressBar`]
fn draw(
&self,
bounds: Rectangle,
range: RangeInclusive<f32>,
value: f32,
style: &Self::Style,
) -> Self::Output;
} }
impl<'a, Message, Renderer> From<ProgressBar<Renderer>> impl<'a, Message, Renderer> From<ProgressBar<Renderer>>

View file

@ -5,7 +5,6 @@ use crate::alignment::{self, Alignment};
use crate::event::{self, Event}; use crate::event::{self, Event};
use crate::layout; use crate::layout;
use crate::mouse; use crate::mouse;
use crate::row;
use crate::text; use crate::text;
use crate::touch; use crate::touch;
use crate::{ use crate::{
@ -136,7 +135,7 @@ where
impl<Message, Renderer> Widget<Message, Renderer> for Radio<Message, Renderer> impl<Message, Renderer> Widget<Message, Renderer> for Radio<Message, Renderer>
where where
Message: Clone, Message: Clone,
Renderer: self::Renderer + text::Renderer + row::Renderer, Renderer: self::Renderer + text::Renderer,
{ {
fn width(&self) -> Length { fn width(&self) -> Length {
self.width self.width
@ -199,36 +198,37 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
let bounds = layout.bounds(); // TODO
let mut children = layout.children(); // let bounds = layout.bounds();
// let mut children = layout.children();
let radio_layout = children.next().unwrap(); // let radio_layout = children.next().unwrap();
let label_layout = children.next().unwrap(); // let label_layout = children.next().unwrap();
let radio_bounds = radio_layout.bounds(); // let radio_bounds = radio_layout.bounds();
let label = text::Renderer::draw( // let label = text::Renderer::draw(
renderer, // renderer,
defaults, // defaults,
label_layout.bounds(), // label_layout.bounds(),
&self.label, // &self.label,
self.text_size.unwrap_or(renderer.default_size()), // self.text_size.unwrap_or(renderer.default_size()),
self.font, // self.font,
self.text_color, // self.text_color,
alignment::Horizontal::Left, // alignment::Horizontal::Left,
alignment::Vertical::Center, // alignment::Vertical::Center,
); // );
let is_mouse_over = bounds.contains(cursor_position); // let is_mouse_over = bounds.contains(cursor_position);
self::Renderer::draw( // self::Renderer::draw(
renderer, // renderer,
radio_bounds, // radio_bounds,
self.is_selected, // self.is_selected,
is_mouse_over, // is_mouse_over,
label, // label,
&self.style, // &self.style,
) // )
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -254,29 +254,13 @@ pub trait Renderer: crate::Renderer {
/// The default spacing of a [`Radio`] button. /// The default spacing of a [`Radio`] button.
const DEFAULT_SPACING: u16; const DEFAULT_SPACING: u16;
/// Draws a [`Radio`] button.
///
/// It receives:
/// * the bounds of the [`Radio`]
/// * whether the [`Radio`] is selected or not
/// * whether the mouse is over the [`Radio`] or not
/// * the drawn label of the [`Radio`]
fn draw(
&mut self,
bounds: Rectangle,
is_selected: bool,
is_mouse_over: bool,
label: Self::Output,
style: &Self::Style,
) -> Self::Output;
} }
impl<'a, Message, Renderer> From<Radio<Message, Renderer>> impl<'a, Message, Renderer> From<Radio<Message, Renderer>>
for Element<'a, Message, Renderer> for Element<'a, Message, Renderer>
where where
Message: 'a + Clone, Message: 'a + Clone,
Renderer: 'a + self::Renderer + row::Renderer + text::Renderer, Renderer: 'a + self::Renderer + text::Renderer,
{ {
fn from(radio: Radio<Message, Renderer>) -> Element<'a, Message, Renderer> { fn from(radio: Radio<Message, Renderer>) -> Element<'a, Message, Renderer> {
Element::new(radio) Element::new(radio)

View file

@ -104,7 +104,7 @@ impl<'a, Message, Renderer> Row<'a, Message, Renderer> {
impl<'a, Message, Renderer> Widget<Message, Renderer> impl<'a, Message, Renderer> Widget<Message, Renderer>
for Row<'a, Message, Renderer> for Row<'a, Message, Renderer>
where where
Renderer: self::Renderer, Renderer: crate::Renderer,
{ {
fn width(&self) -> Length { fn width(&self) -> Length {
self.width self.width
@ -168,14 +168,15 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
viewport: &Rectangle, viewport: &Rectangle,
) -> Renderer::Output { ) {
renderer.draw( // TODO
defaults, // renderer.draw(
&self.children, // defaults,
layout, // &self.children,
cursor_position, // layout,
viewport, // cursor_position,
) // viewport,
// )
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -207,33 +208,10 @@ where
} }
} }
/// The renderer of a [`Row`].
///
/// Your [renderer] will need to implement this trait before being
/// able to use a [`Row`] in your user interface.
///
/// [renderer]: crate::renderer
pub trait Renderer: crate::Renderer + Sized {
/// Draws a [`Row`].
///
/// It receives:
/// - the children of the [`Row`]
/// - the [`Layout`] of the [`Row`] and its children
/// - the cursor position
fn draw<Message>(
&mut self,
defaults: &Self::Defaults,
children: &[Element<'_, Message, Self>],
layout: Layout<'_>,
cursor_position: Point,
viewport: &Rectangle,
) -> Self::Output;
}
impl<'a, Message, Renderer> From<Row<'a, Message, Renderer>> impl<'a, Message, Renderer> From<Row<'a, Message, Renderer>>
for Element<'a, Message, Renderer> for Element<'a, Message, Renderer>
where where
Renderer: 'a + self::Renderer, Renderer: 'a + crate::Renderer,
Message: 'a, Message: 'a,
{ {
fn from(row: Row<'a, Message, Renderer>) -> Element<'a, Message, Renderer> { fn from(row: Row<'a, Message, Renderer>) -> Element<'a, Message, Renderer> {

View file

@ -72,8 +72,9 @@ where
layout: Layout<'_>, layout: Layout<'_>,
_cursor_position: Point, _cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
renderer.draw(layout.bounds(), &self.style, self.is_horizontal) // TODO
// renderer.draw(layout.bounds(), &self.style, self.is_horizontal)
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -89,19 +90,6 @@ where
pub trait Renderer: crate::Renderer { pub trait Renderer: crate::Renderer {
/// The style supported by this renderer. /// The style supported by this renderer.
type Style: Default; type Style: Default;
/// Draws a [`Rule`].
///
/// It receives:
/// * the bounds of the [`Rule`]
/// * the style of the [`Rule`]
/// * whether the [`Rule`] is horizontal (true) or vertical (false)
fn draw(
&mut self,
bounds: Rectangle,
style: &Self::Style,
is_horizontal: bool,
) -> Self::Output;
} }
impl<'a, Message, Renderer> From<Rule<Renderer>> impl<'a, Message, Renderer> From<Rule<Renderer>>

View file

@ -1,5 +1,4 @@
//! Navigate an endless amount of content with a scrollbar. //! Navigate an endless amount of content with a scrollbar.
use crate::column;
use crate::event::{self, Event}; use crate::event::{self, Event};
use crate::layout; use crate::layout;
use crate::mouse; use crate::mouse;
@ -381,57 +380,45 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
let bounds = layout.bounds(); // TODO
let content_layout = layout.children().next().unwrap(); // let bounds = layout.bounds();
let content_bounds = content_layout.bounds(); // let content_layout = layout.children().next().unwrap();
let offset = self.state.offset(bounds, content_bounds); // let content_bounds = content_layout.bounds();
let scrollbar = renderer.scrollbar( // let offset = self.state.offset(bounds, content_bounds);
bounds, // let scrollbar = renderer.scrollbar(
content_bounds, // bounds,
offset, // content_bounds,
self.scrollbar_width, // offset,
self.scrollbar_margin, // self.scrollbar_width,
self.scroller_width, // self.scrollbar_margin,
); // self.scroller_width,
// );
let is_mouse_over = bounds.contains(cursor_position); // let is_mouse_over = bounds.contains(cursor_position);
let is_mouse_over_scrollbar = scrollbar // let is_mouse_over_scrollbar = scrollbar
.as_ref() // .as_ref()
.map(|scrollbar| scrollbar.is_mouse_over(cursor_position)) // .map(|scrollbar| scrollbar.is_mouse_over(cursor_position))
.unwrap_or(false); // .unwrap_or(false);
let content = { // let content = {
let cursor_position = if is_mouse_over && !is_mouse_over_scrollbar { // let cursor_position = if is_mouse_over && !is_mouse_over_scrollbar {
Point::new(cursor_position.x, cursor_position.y + offset as f32) // Point::new(cursor_position.x, cursor_position.y + offset as f32)
} else { // } else {
Point::new(cursor_position.x, -1.0) // Point::new(cursor_position.x, -1.0)
}; // };
self.content.draw( // self.content.draw(
renderer, // renderer,
defaults, // defaults,
content_layout, // content_layout,
cursor_position, // cursor_position,
&Rectangle { // &Rectangle {
y: bounds.y + offset as f32, // y: bounds.y + offset as f32,
..bounds // ..bounds
}, // },
) // )
}; // };
self::Renderer::draw(
renderer,
&self.state,
bounds,
content_layout.bounds(),
is_mouse_over,
is_mouse_over_scrollbar,
scrollbar,
offset,
&self.style,
content,
)
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -635,7 +622,7 @@ pub struct Scroller {
/// able to use a [`Scrollable`] in your user interface. /// able to use a [`Scrollable`] in your user interface.
/// ///
/// [renderer]: crate::renderer /// [renderer]: crate::renderer
pub trait Renderer: column::Renderer + Sized { pub trait Renderer: crate::Renderer + Sized {
/// The style supported by this renderer. /// The style supported by this renderer.
type Style: Default; type Style: Default;
@ -650,30 +637,6 @@ pub trait Renderer: column::Renderer + Sized {
scrollbar_margin: u16, scrollbar_margin: u16,
scroller_width: u16, scroller_width: u16,
) -> Option<Scrollbar>; ) -> Option<Scrollbar>;
/// Draws the [`Scrollable`].
///
/// It receives:
/// - the [`State`] of the [`Scrollable`]
/// - the bounds of the [`Scrollable`] widget
/// - the bounds of the [`Scrollable`] content
/// - whether the mouse is over the [`Scrollable`] or not
/// - whether the mouse is over the [`Scrollbar`] or not
/// - a optional [`Scrollbar`] to be rendered
/// - the scrolling offset
/// - the drawn content
fn draw(
&mut self,
scrollable: &State,
bounds: Rectangle,
content_bounds: Rectangle,
is_mouse_over: bool,
is_mouse_over_scrollbar: bool,
scrollbar: Option<Scrollbar>,
offset: u32,
style: &Self::Style,
content: Self::Output,
) -> Self::Output;
} }
impl<'a, Message, Renderer> From<Scrollable<'a, Message, Renderer>> impl<'a, Message, Renderer> From<Scrollable<'a, Message, Renderer>>

View file

@ -250,18 +250,19 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
let start = *self.range.start(); // TODO
let end = *self.range.end(); // let start = *self.range.start();
// let end = *self.range.end();
renderer.draw( // renderer.draw(
layout.bounds(), // layout.bounds(),
cursor_position, // cursor_position,
start.into() as f32..=end.into() as f32, // start.into() as f32..=end.into() as f32,
self.value.into() as f32, // self.value.into() as f32,
self.state.is_dragging, // self.state.is_dragging,
&self.style, // &self.style,
) // )
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -284,24 +285,6 @@ pub trait Renderer: crate::Renderer {
/// The default height of a [`Slider`]. /// The default height of a [`Slider`].
const DEFAULT_HEIGHT: u16; const DEFAULT_HEIGHT: u16;
/// Draws a [`Slider`].
///
/// It receives:
/// * the current cursor position
/// * the bounds of the [`Slider`]
/// * the local state of the [`Slider`]
/// * the range of values of the [`Slider`]
/// * the current value of the [`Slider`]
fn draw(
&mut self,
bounds: Rectangle,
cursor_position: Point,
range: RangeInclusive<f32>,
value: f32,
is_dragging: bool,
style: &Self::Style,
) -> Self::Output;
} }
impl<'a, T, Message, Renderer> From<Slider<'a, T, Message, Renderer>> impl<'a, T, Message, Renderer> From<Slider<'a, T, Message, Renderer>>

View file

@ -39,7 +39,7 @@ impl Space {
impl<Message, Renderer> Widget<Message, Renderer> for Space impl<Message, Renderer> Widget<Message, Renderer> for Space
where where
Renderer: self::Renderer, Renderer: crate::Renderer,
{ {
fn width(&self) -> Length { fn width(&self) -> Length {
self.width self.width
@ -66,8 +66,7 @@ where
layout: Layout<'_>, layout: Layout<'_>,
_cursor_position: Point, _cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
renderer.draw(layout.bounds())
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -78,17 +77,9 @@ where
} }
} }
/// The renderer of an amount of [`Space`].
pub trait Renderer: crate::Renderer {
/// Draws an amount of empty [`Space`].
///
/// You should most likely return an empty primitive here.
fn draw(&mut self, bounds: Rectangle) -> Self::Output;
}
impl<'a, Message, Renderer> From<Space> for Element<'a, Message, Renderer> impl<'a, Message, Renderer> From<Space> for Element<'a, Message, Renderer>
where where
Renderer: self::Renderer, Renderer: crate::Renderer,
Message: 'a, Message: 'a,
{ {
fn from(space: Space) -> Element<'a, Message, Renderer> { fn from(space: Space) -> Element<'a, Message, Renderer> {

View file

@ -94,8 +94,9 @@ where
layout: Layout<'_>, layout: Layout<'_>,
_cursor_position: Point, _cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
renderer.draw(self.handle.clone(), layout) // TODO
// renderer.draw(self.handle.clone(), layout)
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -187,9 +188,6 @@ impl std::fmt::Debug for Data {
pub trait Renderer: crate::Renderer { pub trait Renderer: crate::Renderer {
/// Returns the default dimensions of an [`Svg`] for the given [`Handle`]. /// Returns the default dimensions of an [`Svg`] for the given [`Handle`].
fn dimensions(&self, handle: &Handle) -> (u32, u32); fn dimensions(&self, handle: &Handle) -> (u32, u32);
/// Draws an [`Svg`].
fn draw(&mut self, handle: Handle, layout: Layout<'_>) -> Self::Output;
} }
impl<'a, Message, Renderer> From<Svg> for Element<'a, Message, Renderer> impl<'a, Message, Renderer> From<Svg> for Element<'a, Message, Renderer>

View file

@ -133,22 +133,13 @@ where
fn draw( fn draw(
&self, &self,
renderer: &mut Renderer, _renderer: &mut Renderer,
defaults: &Renderer::Defaults, _defaults: &Renderer::Defaults,
layout: Layout<'_>, _layout: Layout<'_>,
_cursor_position: Point, _cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
renderer.draw( // TODO
defaults,
layout.bounds(),
&self.content,
self.size.unwrap_or(renderer.default_size()),
self.font,
self.color,
self.horizontal_alignment,
self.vertical_alignment,
)
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -201,27 +192,6 @@ pub trait Renderer: crate::Renderer {
point: Point, point: Point,
nearest_only: bool, nearest_only: bool,
) -> Option<Hit>; ) -> Option<Hit>;
/// Draws a [`Text`] fragment.
///
/// It receives:
/// * the bounds of the [`Text`]
/// * the contents of the [`Text`]
/// * the size of the [`Text`]
/// * the color of the [`Text`]
/// * the [`HorizontalAlignment`] of the [`Text`]
/// * the [`VerticalAlignment`] of the [`Text`]
fn draw(
&mut self,
defaults: &Self::Defaults,
bounds: Rectangle,
content: &str,
size: u16,
font: Self::Font,
color: Option<Color>,
horizontal_alignment: alignment::Horizontal,
vertical_alignment: alignment::Vertical,
) -> Self::Output;
} }
impl<'a, Message, Renderer> From<Text<Renderer>> impl<'a, Message, Renderer> From<Text<Renderer>>

View file

@ -170,38 +170,39 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
value: Option<&Value>, value: Option<&Value>,
) -> Renderer::Output { ) {
let value = value.unwrap_or(&self.value); // TODO
let bounds = layout.bounds(); // let value = value.unwrap_or(&self.value);
let text_bounds = layout.children().next().unwrap().bounds(); // let bounds = layout.bounds();
// let text_bounds = layout.children().next().unwrap().bounds();
if self.is_secure { // if self.is_secure {
self::Renderer::draw( // self::Renderer::draw(
renderer, // renderer,
bounds, // bounds,
text_bounds, // text_bounds,
cursor_position, // cursor_position,
self.font, // self.font,
self.size.unwrap_or(renderer.default_size()), // self.size.unwrap_or(renderer.default_size()),
&self.placeholder, // &self.placeholder,
&value.secure(), // &value.secure(),
&self.state, // &self.state,
&self.style, // &self.style,
) // )
} else { // } else {
self::Renderer::draw( // self::Renderer::draw(
renderer, // renderer,
bounds, // bounds,
text_bounds, // text_bounds,
cursor_position, // cursor_position,
self.font, // self.font,
self.size.unwrap_or(renderer.default_size()), // self.size.unwrap_or(renderer.default_size()),
&self.placeholder, // &self.placeholder,
value, // value,
&self.state, // &self.state,
&self.style, // &self.style,
) // )
} // }
} }
} }
@ -630,7 +631,7 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
self.draw(renderer, layout, cursor_position, None) self.draw(renderer, layout, cursor_position, None)
} }
@ -673,28 +674,6 @@ pub trait Renderer: text::Renderer + Sized {
state: &State, state: &State,
) -> f32; ) -> f32;
/// Draws a [`TextInput`].
///
/// It receives:
/// - the bounds of the [`TextInput`]
/// - the bounds of the text (i.e. the current value)
/// - the cursor position
/// - the placeholder to show when the value is empty
/// - the current [`Value`]
/// - the current [`State`]
fn draw(
&mut self,
bounds: Rectangle,
text_bounds: Rectangle,
cursor_position: Point,
font: Self::Font,
size: u16,
placeholder: &str,
value: &Value,
state: &State,
style: &Self::Style,
) -> Self::Output;
/// Computes the position of the text cursor at the given X coordinate of /// Computes the position of the text cursor at the given X coordinate of
/// a [`TextInput`]. /// a [`TextInput`].
fn find_cursor_position( fn find_cursor_position(

View file

@ -5,7 +5,6 @@ use crate::alignment;
use crate::event; use crate::event;
use crate::layout; use crate::layout;
use crate::mouse; use crate::mouse;
use crate::row;
use crate::text; use crate::text;
use crate::{ use crate::{
Alignment, Clipboard, Element, Event, Hasher, Layout, Length, Point, Alignment, Clipboard, Element, Event, Hasher, Layout, Length, Point,
@ -119,7 +118,7 @@ impl<Message, Renderer: self::Renderer + text::Renderer>
impl<Message, Renderer> Widget<Message, Renderer> for Toggler<Message, Renderer> impl<Message, Renderer> Widget<Message, Renderer> for Toggler<Message, Renderer>
where where
Renderer: self::Renderer + text::Renderer + row::Renderer, Renderer: self::Renderer + text::Renderer,
{ {
fn width(&self) -> Length { fn width(&self) -> Length {
self.width self.width
@ -190,43 +189,35 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
let bounds = layout.bounds(); // TODO
let mut children = layout.children(); // let bounds = layout.bounds();
// let mut children = layout.children();
let label = match &self.label { // let label = match &self.label {
Some(label) => { // Some(label) => {
let label_layout = children.next().unwrap(); // let label_layout = children.next().unwrap();
Some(text::Renderer::draw( // Some(text::Renderer::draw(
renderer, // renderer,
defaults, // defaults,
label_layout.bounds(), // label_layout.bounds(),
&label, // &label,
self.text_size.unwrap_or(renderer.default_size()), // self.text_size.unwrap_or(renderer.default_size()),
self.font, // self.font,
None, // None,
self.text_alignment, // self.text_alignment,
alignment::Vertical::Center, // alignment::Vertical::Center,
)) // ))
} // }
None => None, // None => None,
}; // };
let toggler_layout = children.next().unwrap(); // let toggler_layout = children.next().unwrap();
let toggler_bounds = toggler_layout.bounds(); // let toggler_bounds = toggler_layout.bounds();
let is_mouse_over = bounds.contains(cursor_position); // let is_mouse_over = bounds.contains(cursor_position);
self::Renderer::draw(
renderer,
toggler_bounds,
self.is_active,
is_mouse_over,
label,
&self.style,
)
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -249,29 +240,12 @@ pub trait Renderer: crate::Renderer {
/// The default size of a [`Toggler`]. /// The default size of a [`Toggler`].
const DEFAULT_SIZE: u16; const DEFAULT_SIZE: u16;
/// Draws a [`Toggler`].
///
/// It receives:
/// * the bounds of the [`Toggler`]
/// * whether the [`Toggler`] is activated or not
/// * whether the mouse is over the [`Toggler`] or not
/// * the drawn label of the [`Toggler`]
/// * the style of the [`Toggler`]
fn draw(
&mut self,
bounds: Rectangle,
is_active: bool,
is_mouse_over: bool,
label: Option<Self::Output>,
style: &Self::Style,
) -> Self::Output;
} }
impl<'a, Message, Renderer> From<Toggler<Message, Renderer>> impl<'a, Message, Renderer> From<Toggler<Message, Renderer>>
for Element<'a, Message, Renderer> for Element<'a, Message, Renderer>
where where
Renderer: 'a + self::Renderer + text::Renderer + row::Renderer, Renderer: 'a + self::Renderer + text::Renderer,
Message: 'a, Message: 'a,
{ {
fn from( fn from(

View file

@ -136,25 +136,13 @@ where
fn draw( fn draw(
&self, &self,
renderer: &mut Renderer, _renderer: &mut Renderer,
defaults: &Renderer::Defaults, _defaults: &Renderer::Defaults,
layout: Layout<'_>, _layout: Layout<'_>,
cursor_position: Point, _cursor_position: Point,
viewport: &Rectangle, _viewport: &Rectangle,
) -> Renderer::Output { ) {
self::Renderer::draw( // TODO
renderer,
defaults,
cursor_position,
layout,
viewport,
&self.content,
&self.tooltip,
self.position,
&self.style,
self.gap,
self.padding,
)
} }
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
@ -177,23 +165,6 @@ pub trait Renderer:
{ {
/// The default padding of a [`Tooltip`] drawn by this renderer. /// The default padding of a [`Tooltip`] drawn by this renderer.
const DEFAULT_PADDING: u16; const DEFAULT_PADDING: u16;
/// Draws a [`Tooltip`].
///
/// [`Tooltip`]: struct.Tooltip.html
fn draw<Message>(
&mut self,
defaults: &Self::Defaults,
cursor_position: Point,
content_layout: Layout<'_>,
viewport: &Rectangle,
content: &Element<'_, Message, Self>,
tooltip: &Text<Self>,
position: Position,
style: &<Self as container::Renderer>::Style,
gap: u16,
padding: u16,
) -> Self::Output;
} }
impl<'a, Message, Renderer> From<Tooltip<'a, Message, Renderer>> impl<'a, Message, Renderer> From<Tooltip<'a, Message, Renderer>>

View file

@ -8,7 +8,6 @@ use iced_graphics::font;
use iced_graphics::layer::Layer; use iced_graphics::layer::Layer;
use iced_graphics::{Primitive, Viewport}; use iced_graphics::{Primitive, Viewport};
use iced_native::alignment; use iced_native::alignment;
use iced_native::mouse;
use iced_native::{Font, Size}; use iced_native::{Font, Size};
#[cfg(any(feature = "image_rs", feature = "svg"))] #[cfg(any(feature = "image_rs", feature = "svg"))]
@ -28,6 +27,7 @@ pub struct Backend {
image_pipeline: image::Pipeline, image_pipeline: image::Pipeline,
default_text_size: u16, default_text_size: u16,
primitive: Primitive,
} }
impl Backend { impl Backend {
@ -60,6 +60,7 @@ impl Backend {
image_pipeline, image_pipeline,
default_text_size: settings.default_text_size, default_text_size: settings.default_text_size,
primitive: Primitive::None,
} }
} }
@ -67,16 +68,16 @@ impl Backend {
/// ///
/// The text provided as overlay will be rendered on top of the primitives. /// The text provided as overlay will be rendered on top of the primitives.
/// This is useful for rendering debug information. /// This is useful for rendering debug information.
pub fn draw<T: AsRef<str>>( pub fn present<T: AsRef<str>>(
&mut self, &mut self,
device: &wgpu::Device, device: &wgpu::Device,
staging_belt: &mut wgpu::util::StagingBelt, staging_belt: &mut wgpu::util::StagingBelt,
encoder: &mut wgpu::CommandEncoder, encoder: &mut wgpu::CommandEncoder,
frame: &wgpu::TextureView, frame: &wgpu::TextureView,
primitive: &Primitive,
viewport: &Viewport, viewport: &Viewport,
(primitive, mouse_interaction): &(Primitive, mouse::Interaction),
overlay_text: &[T], overlay_text: &[T],
) -> mouse::Interaction { ) {
log::debug!("Drawing"); log::debug!("Drawing");
let target_size = viewport.physical_size(); let target_size = viewport.physical_size();
@ -102,8 +103,6 @@ impl Backend {
#[cfg(any(feature = "image_rs", feature = "svg"))] #[cfg(any(feature = "image_rs", feature = "svg"))]
self.image_pipeline.trim_cache(); self.image_pipeline.trim_cache();
*mouse_interaction
} }
fn flush( fn flush(

View file

@ -1,7 +1,7 @@
use crate::{Backend, Color, Error, Renderer, Settings, Viewport}; use crate::{Backend, Color, Error, Renderer, Settings, Viewport};
use futures::task::SpawnExt; use futures::task::SpawnExt;
use iced_native::{futures, mouse}; use iced_native::futures;
use raw_window_handle::HasRawWindowHandle; use raw_window_handle::HasRawWindowHandle;
/// A window graphics backend for iced powered by `wgpu`. /// A window graphics backend for iced powered by `wgpu`.
@ -132,15 +132,14 @@ impl iced_graphics::window::Compositor for Compositor {
); );
} }
fn draw<T: AsRef<str>>( fn present<T: AsRef<str>>(
&mut self, &mut self,
renderer: &mut Self::Renderer, renderer: &mut Self::Renderer,
surface: &mut Self::Surface, surface: &mut Self::Surface,
viewport: &Viewport, viewport: &Viewport,
background_color: Color, background_color: Color,
output: &<Self::Renderer as iced_native::Renderer>::Output,
overlay: &[T], overlay: &[T],
) -> Result<mouse::Interaction, iced_graphics::window::SurfaceError> { ) -> Result<(), iced_graphics::window::SurfaceError> {
match surface.get_current_frame() { match surface.get_current_frame() {
Ok(frame) => { Ok(frame) => {
let mut encoder = self.device.create_command_encoder( let mut encoder = self.device.create_command_encoder(
@ -180,15 +179,17 @@ impl iced_graphics::window::Compositor for Compositor {
depth_stencil_attachment: None, depth_stencil_attachment: None,
}); });
let mouse_interaction = renderer.backend_mut().draw( renderer.present(|backend, primitive| {
&mut self.device, backend.present(
&mut self.staging_belt, &mut self.device,
&mut encoder, &mut self.staging_belt,
view, &mut encoder,
viewport, view,
output, primitive,
overlay, viewport,
); overlay,
);
});
// Submit work // Submit work
self.staging_belt.finish(); self.staging_belt.finish();
@ -202,7 +203,7 @@ impl iced_graphics::window::Compositor for Compositor {
self.local_pool.run_until_stalled(); self.local_pool.run_until_stalled();
Ok(mouse_interaction) Ok(())
} }
Err(error) => match error { Err(error) => match error {
wgpu::SurfaceError::Timeout => { wgpu::SurfaceError::Timeout => {

View file

@ -5,7 +5,6 @@ pub use state::State;
use crate::clipboard::{self, Clipboard}; use crate::clipboard::{self, Clipboard};
use crate::conversion; use crate::conversion;
use crate::mouse;
use crate::{ use crate::{
Color, Command, Debug, Error, Executor, Mode, Proxy, Runtime, Settings, Color, Command, Debug, Error, Executor, Mode, Proxy, Runtime, Settings,
Size, Subscription, Size, Subscription,
@ -253,9 +252,8 @@ async fn run_instance<A, E, C>(
&mut debug, &mut debug,
)); ));
let mut primitive = // TODO
user_interface.draw(&mut renderer, state.cursor_position()); // let mut mouse_interaction = mouse::Interaction::default();
let mut mouse_interaction = mouse::Interaction::default();
let mut events = Vec::new(); let mut events = Vec::new();
let mut messages = Vec::new(); let mut messages = Vec::new();
@ -319,8 +317,7 @@ async fn run_instance<A, E, C>(
} }
debug.draw_started(); debug.draw_started();
primitive = user_interface.draw(&mut renderer, state.cursor_position());
user_interface.draw(&mut renderer, state.cursor_position());
debug.draw_finished(); debug.draw_finished();
window.request_redraw(); window.request_redraw();
@ -359,8 +356,7 @@ async fn run_instance<A, E, C>(
debug.layout_finished(); debug.layout_finished();
debug.draw_started(); debug.draw_started();
primitive = user_interface user_interface.draw(&mut renderer, state.cursor_position());
.draw(&mut renderer, state.cursor_position());
debug.draw_finished(); debug.draw_finished();
compositor.configure_surface( compositor.configure_surface(
@ -372,27 +368,16 @@ async fn run_instance<A, E, C>(
viewport_version = current_viewport_version; viewport_version = current_viewport_version;
} }
match compositor.draw( match compositor.present(
&mut renderer, &mut renderer,
&mut surface, &mut surface,
state.viewport(), state.viewport(),
state.background_color(), state.background_color(),
&primitive,
&debug.overlay(), &debug.overlay(),
) { ) {
Ok(new_mouse_interaction) => { Ok(()) => {
debug.render_finished(); debug.render_finished();
if new_mouse_interaction != mouse_interaction {
window.set_cursor_icon(
conversion::mouse_interaction(
new_mouse_interaction,
),
);
mouse_interaction = new_mouse_interaction;
}
// TODO: Handle animations! // TODO: Handle animations!
// Maybe we can use `ControlFlow::WaitUntil` for this. // Maybe we can use `ControlFlow::WaitUntil` for this.
} }