summaryrefslogtreecommitdiffstats
path: root/graphics/src/renderer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/src/renderer.rs')
-rw-r--r--graphics/src/renderer.rs201
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,
+ });
}
}