Draft custom layout engine based on druid

This commit is contained in:
Héctor Ramón Jiménez 2019-11-10 06:05:20 +01:00
parent 2303111e09
commit 0240c3981b
38 changed files with 974 additions and 249 deletions

View file

@ -9,9 +9,8 @@ use wgpu::{
Extensions, Limits, PowerPreference, Queue, RequestAdapterOptions,
TextureFormat,
};
use wgpu_glyph::{GlyphBrush, GlyphBrushBuilder, Section};
use std::{cell::RefCell, rc::Rc};
use std::cell::RefCell;
mod target;
mod widget;
@ -24,7 +23,7 @@ pub struct Renderer {
quad_pipeline: quad::Pipeline,
image_pipeline: crate::image::Pipeline,
glyph_brush: Rc<RefCell<GlyphBrush<'static, ()>>>,
glyph_brush: RefCell<wgpu_glyph::GlyphBrush<'static, ()>>,
}
pub struct Layer<'a> {
@ -72,8 +71,10 @@ impl Renderer {
.load(&[font::Family::Monospace])
.expect("Find monospace font");
let fonts = vec![default_font, mono_font];
let glyph_brush =
GlyphBrushBuilder::using_fonts_bytes(vec![default_font, mono_font])
wgpu_glyph::GlyphBrushBuilder::using_fonts_bytes(fonts)
.initial_cache_size((2048, 2048))
.build(&mut device, TextureFormat::Bgra8UnormSrgb);
@ -86,7 +87,7 @@ impl Renderer {
quad_pipeline,
image_pipeline,
glyph_brush: Rc::new(RefCell::new(glyph_brush)),
glyph_brush: RefCell::new(glyph_brush),
}
}
@ -190,7 +191,7 @@ impl Renderer {
}
};
layer.text.push(Section {
layer.text.push(wgpu_glyph::Section {
text: &content,
screen_position: (
x - layer.offset.x as f32,
@ -297,22 +298,22 @@ impl Renderer {
let scale = wgpu_glyph::Scale { x: 20.0, y: 20.0 };
for (i, line) in lines.iter().enumerate() {
overlay.text.push(Section {
overlay.text.push(wgpu_glyph::Section {
text: line.as_ref(),
screen_position: (11.0, 11.0 + 25.0 * i as f32),
color: [0.9, 0.9, 0.9, 1.0],
scale,
font_id,
..Section::default()
..wgpu_glyph::Section::default()
});
overlay.text.push(Section {
overlay.text.push(wgpu_glyph::Section {
text: line.as_ref(),
screen_position: (10.0, 10.0 + 25.0 * i as f32),
color: [0.0, 0.0, 0.0, 1.0],
scale,
font_id,
..Section::default()
..wgpu_glyph::Section::default()
});
}
@ -364,7 +365,7 @@ impl Renderer {
for text in layer.text.iter() {
// Target physical coordinates directly to avoid blurry text
let text = Section {
let text = wgpu_glyph::Section {
screen_position: (
(text.screen_position.0 * dpi).round(),
(text.screen_position.1 * dpi).round(),
@ -423,7 +424,7 @@ impl Debugger for Renderer {
fn explain<Message>(
&mut self,
widget: &dyn Widget<Message, Self>,
layout: &Layout,
layout: Layout<'_>,
cursor_position: Point,
color: Color,
) -> Self::Output {
@ -438,7 +439,7 @@ impl Debugger for Renderer {
}
fn explain_layout(
layout: &Layout,
layout: Layout<'_>,
color: Color,
primitives: &mut Vec<Primitive>,
) {

View file

@ -1,6 +1,7 @@
use crate::{Primitive, Renderer};
use iced_native::{
button, layout, Background, Button, Layout, MouseCursor, Point, Rectangle,
button, layout, Background, Button, Layout, Length, MouseCursor, Point,
Rectangle,
};
impl button::Renderer for Renderer {
@ -8,20 +9,28 @@ impl button::Renderer for Renderer {
&self,
button: &Button<Message, Self>,
limits: &layout::Limits,
) -> Layout {
// TODO
Layout::new(Rectangle {
x: 0.0,
y: 0.0,
width: 0.0,
height: 0.0,
})
) -> layout::Node {
let padding = f32::from(button.padding);
let limits = limits
.min_width(100)
.width(button.width)
.height(Length::Shrink)
.pad(padding);
let mut content = button.content.layout(self, &limits);
content.bounds.x = padding;
content.bounds.y = padding;
let size = limits.resolve(content.size()).pad(padding);
layout::Node::with_children(size, vec![content])
}
fn draw<Message>(
&mut self,
button: &Button<Message, Self>,
layout: &Layout,
layout: Layout<'_>,
cursor_position: Point,
) -> Self::Output {
let bounds = layout.bounds();

View file

@ -1,7 +1,8 @@
use crate::{Primitive, Renderer};
use iced_native::{
checkbox, layout, text, text::HorizontalAlignment, text::VerticalAlignment,
Background, Checkbox, Layout, MouseCursor, Point, Rectangle, Text,
Align, Background, Checkbox, Column, Layout, Length, MouseCursor, Point,
Rectangle, Row, Text, Widget,
};
const SIZE: f32 = 28.0;
@ -11,20 +12,23 @@ impl checkbox::Renderer for Renderer {
&self,
checkbox: &Checkbox<Message>,
limits: &layout::Limits,
) -> Layout {
// TODO
Layout::new(Rectangle {
x: 0.0,
y: 0.0,
width: 0.0,
height: 0.0,
})
) -> layout::Node {
Row::<(), Self>::new()
.spacing(15)
.align_items(Align::Center)
.push(
Column::new()
.width(Length::Units(SIZE as u16))
.height(Length::Units(SIZE as u16)),
)
.push(Text::new(&checkbox.label))
.layout(self, limits)
}
fn draw<Message>(
&mut self,
checkbox: &Checkbox<Message>,
layout: &Layout,
layout: Layout<'_>,
cursor_position: Point,
) -> Self::Output {
let bounds = layout.bounds();

View file

@ -5,7 +5,7 @@ impl column::Renderer for Renderer {
fn draw<Message>(
&mut self,
column: &Column<'_, Message, Self>,
layout: &Layout,
layout: Layout<'_>,
cursor_position: Point,
) -> Self::Output {
let mut mouse_cursor = MouseCursor::OutOfBounds;

View file

@ -1,18 +1,31 @@
use crate::{Primitive, Renderer};
use iced_native::{image, layout, Image, Layout, MouseCursor, Rectangle};
use iced_native::{image, layout, Image, Layout, Length, MouseCursor, Size};
impl image::Renderer for Renderer {
fn layout(&self, image: &Image, limits: &layout::Limits) -> Layout {
// TODO
Layout::new(Rectangle {
x: 0.0,
y: 0.0,
width: 0.0,
height: 0.0,
})
fn layout(&self, image: &Image, limits: &layout::Limits) -> layout::Node {
let (width, height) = self.image_pipeline.dimensions(&image.path);
let aspect_ratio = width as f32 / height as f32;
// TODO: Deal with additional cases
let (width, height) = match (image.width, image.height) {
(Length::Units(width), _) => (
image.width,
Length::Units((width as f32 / aspect_ratio).round() as u16),
),
(_, _) => {
(Length::Units(width as u16), Length::Units(height as u16))
}
};
let mut size = limits.width(width).height(height).resolve(Size::ZERO);
size.height = size.width / aspect_ratio;
layout::Node::new(size)
}
fn draw(&mut self, image: &Image, layout: &Layout) -> Self::Output {
fn draw(&mut self, image: &Image, layout: Layout<'_>) -> Self::Output {
(
Primitive::Image {
path: image.path.clone(),

View file

@ -1,7 +1,7 @@
use crate::{Primitive, Renderer};
use iced_native::{
layout, radio, text, Background, Layout, MouseCursor, Point, Radio,
Rectangle, Text,
layout, radio, text, Align, Background, Column, Layout, Length,
MouseCursor, Point, Radio, Rectangle, Row, Text, Widget,
};
const SIZE: f32 = 28.0;
@ -12,20 +12,23 @@ impl radio::Renderer for Renderer {
&self,
radio: &Radio<Message>,
limits: &layout::Limits,
) -> Layout {
// TODO
Layout::new(Rectangle {
x: 0.0,
y: 0.0,
width: 0.0,
height: 0.0,
})
) -> layout::Node {
Row::<(), Self>::new()
.spacing(15)
.align_items(Align::Center)
.push(
Column::new()
.width(Length::Units(SIZE as u16))
.height(Length::Units(SIZE as u16)),
)
.push(Text::new(&radio.label))
.layout(self, limits)
}
fn draw<Message>(
&mut self,
radio: &Radio<Message>,
layout: &Layout,
layout: Layout<'_>,
cursor_position: Point,
) -> Self::Output {
let bounds = layout.bounds();

View file

@ -5,7 +5,7 @@ impl row::Renderer for Renderer {
fn draw<Message>(
&mut self,
row: &Row<'_, Message, Self>,
layout: &Layout,
layout: Layout<'_>,
cursor_position: Point,
) -> Self::Output {
let mut mouse_cursor = MouseCursor::OutOfBounds;

View file

@ -32,7 +32,7 @@ impl scrollable::Renderer for Renderer {
&mut self,
scrollable: &Scrollable<'_, Message, Self>,
bounds: Rectangle,
content: &Layout,
content: Layout<'_>,
cursor_position: Point,
) -> Self::Output {
let is_mouse_over = bounds.contains(cursor_position);

View file

@ -1,7 +1,7 @@
use crate::{Primitive, Renderer};
use iced_native::{
layout, slider, Background, Color, Layout, MouseCursor, Point, Rectangle,
Slider,
layout, slider, Background, Color, Layout, Length, MouseCursor, Point,
Rectangle, Size, Slider,
};
const HANDLE_WIDTH: f32 = 8.0;
@ -12,20 +12,17 @@ impl slider::Renderer for Renderer {
&self,
slider: &Slider<Message>,
limits: &layout::Limits,
) -> Layout {
// TODO
Layout::new(Rectangle {
x: 0.0,
y: 0.0,
width: 0.0,
height: 0.0,
})
) -> layout::Node {
let limits = limits.width(slider.width).height(Length::Units(30));
let size = limits.resolve(Size::ZERO);
layout::Node::new(size)
}
fn draw<Message>(
&mut self,
slider: &Slider<Message>,
layout: &Layout,
layout: Layout<'_>,
cursor_position: Point,
) -> Self::Output {
let bounds = layout.bounds();

View file

@ -1,7 +1,7 @@
use crate::{Primitive, Renderer};
use iced_native::{layout, text, Color, Layout, MouseCursor, Rectangle, Text};
use iced_native::{layout, text, Color, Layout, MouseCursor, Size, Text};
//use wgpu_glyph::{GlyphCruncher, Section};
use wgpu_glyph::{GlyphCruncher, Section};
use std::f32;
@ -9,17 +9,32 @@ use std::f32;
const DEFAULT_TEXT_SIZE: f32 = 20.0;
impl text::Renderer for Renderer {
fn layout(&self, text: &Text, limits: &layout::Limits) -> Layout {
// TODO
Layout::new(Rectangle {
x: 0.0,
y: 0.0,
width: 0.0,
height: 0.0,
})
fn layout(&self, text: &Text, limits: &layout::Limits) -> layout::Node {
let limits = limits.width(text.width).height(text.height);
let size = text.size.map(f32::from).unwrap_or(DEFAULT_TEXT_SIZE);
let bounds = limits.max();
let section = Section {
text: &text.content,
scale: wgpu_glyph::Scale { x: size, y: size },
bounds: (bounds.width, bounds.height),
..Default::default()
};
let (width, height) = if let Some(bounds) =
self.glyph_brush.borrow_mut().glyph_bounds(&section)
{
(bounds.width().ceil(), bounds.height().ceil())
} else {
(0.0, 0.0)
};
let size = limits.resolve(Size::new(width, height));
layout::Node::new(size)
}
fn draw(&mut self, text: &Text, layout: &Layout) -> Self::Output {
fn draw(&mut self, text: &Text, layout: Layout<'_>) -> Self::Output {
(
Primitive::Text {
content: text.content.clone(),