diff options
Diffstat (limited to 'graphics/src/renderer.rs')
-rw-r--r-- | graphics/src/renderer.rs | 201 |
1 files changed, 125 insertions, 76 deletions
diff --git a/graphics/src/renderer.rs b/graphics/src/renderer.rs index 8f234f1f..c32eb471 100644 --- a/graphics/src/renderer.rs +++ b/graphics/src/renderer.rs @@ -1,30 +1,43 @@ -use crate::{Backend, Defaults, Primitive}; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::{ - Background, Color, Element, Point, Rectangle, Vector, Widget, -}; +//! Create a renderer from a [`Backend`]. +use crate::backend::{self, Backend}; +use crate::{Primitive, Vector}; +use iced_native::layout; +use iced_native::renderer; +use iced_native::text::{self, Text}; +use iced_native::{Background, Element, Font, Point, Rectangle, Size}; + +pub use iced_native::renderer::Style; /// A backend-agnostic renderer that supports all the built-in widgets. #[derive(Debug)] pub struct Renderer<B: Backend> { backend: B, + primitives: Vec<Primitive>, } impl<B: Backend> Renderer<B> { /// Creates a new [`Renderer`] from the given [`Backend`]. pub fn new(backend: B) -> Self { - Self { backend } + Self { + backend, + primitives: Vec::new(), + } } - /// Returns a reference to the [`Backend`] of the [`Renderer`]. + /// Returns the [`Backend`] of the [`Renderer`]. pub fn backend(&self) -> &B { &self.backend } - /// Returns a mutable reference to the [`Backend`] of the [`Renderer`]. - pub fn backend_mut(&mut self) -> &mut B { - &mut self.backend + /// Enqueues the given [`Primitive`] in the [`Renderer`] for drawing. + pub fn draw_primitive(&mut self, primitive: Primitive) { + self.primitives.push(primitive); + } + + /// Runs the given closure with the [`Backend`] and the recorded primitives + /// of the [`Renderer`]. + pub fn with_primitives(&mut self, f: impl FnOnce(&mut B, &[Primitive])) { + f(&mut self.backend, &self.primitives); } } @@ -32,9 +45,6 @@ impl<B> iced_native::Renderer for Renderer<B> where B: Backend, { - type Output = (Primitive, mouse::Interaction); - type Defaults = Defaults; - fn layout<'a, Message>( &mut self, element: &Element<'a, Message, Self>, @@ -47,75 +57,114 @@ where layout } - fn overlay( + fn with_layer(&mut self, bounds: Rectangle, f: impl FnOnce(&mut Self)) { + let current_primitives = std::mem::take(&mut self.primitives); + + f(self); + + let layer_primitives = + std::mem::replace(&mut self.primitives, current_primitives); + + self.primitives.push(Primitive::Clip { + bounds, + content: Box::new(Primitive::Group { + primitives: layer_primitives, + }), + }); + } + + fn with_translation( &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 - }, - ) + translation: Vector, + f: impl FnOnce(&mut Self), + ) { + let current_primitives = std::mem::take(&mut self.primitives); + + f(self); + + let layer_primitives = + std::mem::replace(&mut self.primitives, current_primitives); + + self.primitives.push(Primitive::Translate { + translation, + content: Box::new(Primitive::Group { + primitives: layer_primitives, + }), + }); + } + + fn fill_quad( + &mut self, + quad: renderer::Quad, + background: impl Into<Background>, + ) { + self.primitives.push(Primitive::Quad { + bounds: quad.bounds, + background: background.into(), + border_radius: quad.border_radius, + border_width: quad.border_width, + border_color: quad.border_color, + }); + } + + fn clear(&mut self) { + self.primitives.clear(); } } -impl<B> layout::Debugger for Renderer<B> +impl<B> text::Renderer for Renderer<B> where - B: Backend, + B: Backend + backend::Text, { - 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) + type Font = Font; + + const ICON_FONT: Font = B::ICON_FONT; + const CHECKMARK_ICON: char = B::CHECKMARK_ICON; + const ARROW_DOWN_ICON: char = B::ARROW_DOWN_ICON; + + fn default_size(&self) -> u16 { + self.backend().default_size() + } + + fn measure( + &self, + content: &str, + size: u16, + font: Font, + bounds: Size, + ) -> (f32, f32) { + self.backend() + .measure(content, f32::from(size), font, bounds) + } + + fn hit_test( + &self, + content: &str, + size: f32, + font: Font, + bounds: Size, + point: Point, + nearest_only: bool, + ) -> Option<text::Hit> { + self.backend().hit_test( + content, + size, + font, + bounds, + point, + nearest_only, + ) } -} -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: color, - }); - - for child in layout.children() { - explain_layout(child, color, primitives); + fn fill_text(&mut self, text: Text<'_, Self::Font>) { + self.primitives.push(Primitive::Text { + content: text.content.to_string(), + bounds: text.bounds, + size: text.size, + color: text.color, + font: text.font, + horizontal_alignment: text.horizontal_alignment, + vertical_alignment: text.vertical_alignment, + }); } } |