Make iced_core::Button customizable

Now it supports:
  - Any kind of content
  - Custom border radius
  - Custom background
This commit is contained in:
Héctor Ramón Jiménez 2019-10-08 03:13:41 +02:00
parent a0234d5bce
commit 10e10e5e06
35 changed files with 288 additions and 160 deletions

View file

@ -8,5 +8,5 @@ pub(crate) use quad::Quad;
pub(crate) use transformation::Transformation;
pub use mouse_cursor::MouseCursor;
pub use primitive::{Background, Primitive};
pub use primitive::Primitive;
pub use renderer::{Renderer, Target};

View file

@ -1,4 +1,4 @@
use iced_native::{Color, Rectangle};
use iced_native::{text, Background, Color, Rectangle};
#[derive(Debug, Clone)]
pub enum Primitive {
@ -9,16 +9,14 @@ pub enum Primitive {
Text {
content: String,
bounds: Rectangle,
color: Color,
size: f32,
horizontal_alignment: text::HorizontalAlignment,
vertical_alignment: text::VerticalAlignment,
},
Quad {
bounds: Rectangle,
background: Background,
border_radius: u16,
},
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Background {
Color(Color),
// TODO: Add gradient and image variants
}

View file

@ -123,6 +123,11 @@ impl Pipeline {
format: wgpu::VertexFormat::Float4,
offset: 4 * (2 + 2),
},
wgpu::VertexAttributeDescriptor {
shader_location: 4,
format: wgpu::VertexFormat::Uint,
offset: 4 * (2 + 2 + 4),
},
],
},
],
@ -262,6 +267,7 @@ pub struct Quad {
pub position: [f32; 2],
pub scale: [f32; 2],
pub color: [f32; 4],
pub border_radius: u32,
}
impl Quad {

View file

@ -1,5 +1,7 @@
use crate::{quad, Background, Primitive, Quad, Transformation};
use iced_native::{renderer::Debugger, Color, Layout, Point, Widget};
use crate::{quad, Primitive, Quad, Transformation};
use iced_native::{
renderer::Debugger, Background, Color, Layout, Point, Widget,
};
use raw_window_handle::HasRawWindowHandle;
use wgpu::{
@ -159,20 +161,74 @@ impl Renderer {
content,
bounds,
size,
} => self.glyph_brush.borrow_mut().queue(Section {
text: &content,
screen_position: (bounds.x, bounds.y),
bounds: (bounds.width, bounds.height),
scale: wgpu_glyph::Scale { x: *size, y: *size },
..Default::default()
}),
Primitive::Quad { bounds, background } => {
color,
horizontal_alignment,
vertical_alignment,
} => {
let x = match horizontal_alignment {
iced_native::text::HorizontalAlignment::Left => bounds.x,
iced_native::text::HorizontalAlignment::Center => {
bounds.x + bounds.width / 2.0
}
iced_native::text::HorizontalAlignment::Right => {
bounds.x + bounds.width
}
};
let y = match vertical_alignment {
iced_native::text::VerticalAlignment::Top => bounds.y,
iced_native::text::VerticalAlignment::Center => {
bounds.y + bounds.height / 2.0
}
iced_native::text::VerticalAlignment::Bottom => {
bounds.y + bounds.height
}
};
self.glyph_brush.borrow_mut().queue(Section {
text: &content,
screen_position: (x, y),
bounds: (bounds.width, bounds.height),
scale: wgpu_glyph::Scale { x: *size, y: *size },
color: color.into_linear(),
layout: wgpu_glyph::Layout::default()
.h_align(match horizontal_alignment {
iced_native::text::HorizontalAlignment::Left => {
wgpu_glyph::HorizontalAlign::Left
}
iced_native::text::HorizontalAlignment::Center => {
wgpu_glyph::HorizontalAlign::Center
}
iced_native::text::HorizontalAlignment::Right => {
wgpu_glyph::HorizontalAlign::Right
}
})
.v_align(match vertical_alignment {
iced_native::text::VerticalAlignment::Top => {
wgpu_glyph::VerticalAlign::Top
}
iced_native::text::VerticalAlignment::Center => {
wgpu_glyph::VerticalAlign::Center
}
iced_native::text::VerticalAlignment::Bottom => {
wgpu_glyph::VerticalAlign::Bottom
}
}),
..Default::default()
})
}
Primitive::Quad {
bounds,
background,
border_radius,
} => {
self.quads.push(Quad {
position: [bounds.x, bounds.y],
scale: [bounds.width, bounds.height],
color: match background {
Background::Color(color) => color.into_linear(),
},
border_radius: u32::from(*border_radius),
});
}
}

View file

@ -1,22 +1,26 @@
use crate::{Background, Primitive, Renderer};
use iced_native::{button, Button, Color, Layout, Length, Node, Point, Style};
use crate::{Primitive, Renderer};
use iced_native::{
button, Align, Background, Button, Color, Layout, Length, Node, Point,
Style,
};
impl button::Renderer for Renderer {
fn node<Message>(&self, button: &Button<Message>) -> Node {
fn node<Message>(&self, button: &Button<Message, Self>) -> Node {
let style = Style::default()
.width(button.width)
.min_height(Length::Units(30))
.padding(button.padding)
.min_width(Length::Units(100))
.align_self(button.align_self);
.align_self(button.align_self)
.align_items(Align::Stretch);
Node::new(style)
Node::with_children(style, vec![button.content.node(self)])
}
fn draw<Message>(
&mut self,
button: &Button<Message>,
button: &Button<Message, Self>,
layout: Layout<'_>,
_cursor_position: Point,
cursor_position: Point,
) -> Self::Primitive {
let bounds = layout.bounds();
@ -24,18 +28,21 @@ impl button::Renderer for Renderer {
primitives: vec![
Primitive::Quad {
bounds,
background: Background::Color(Color {
r: 0.8,
b: 0.8,
g: 0.8,
a: 1.0,
}),
},
Primitive::Text {
content: button.label.clone(),
size: 20.0,
bounds: layout.bounds(),
background: button.background.unwrap_or(Background::Color(
Color {
r: 0.8,
b: 0.8,
g: 0.8,
a: 1.0,
},
)),
border_radius: button.border_radius,
},
button.content.draw(
self,
layout.children().next().unwrap(),
cursor_position,
),
],
}
}

View file

@ -2,7 +2,7 @@ use crate::{Primitive, Renderer};
use iced_native::{checkbox, Checkbox, Layout, Node, Point, Style};
impl checkbox::Renderer for Renderer {
fn node<Message>(&mut self, _checkbox: &Checkbox<Message>) -> Node {
fn node<Message>(&self, _checkbox: &Checkbox<Message>) -> Node {
Node::new(Style::default())
}

View file

@ -2,7 +2,7 @@ use crate::{Primitive, Renderer};
use iced_native::{image, Image, Layout, Node, Style};
impl image::Renderer<&str> for Renderer {
fn node(&mut self, _image: &Image<&str>) -> Node {
fn node(&self, _image: &Image<&str>) -> Node {
Node::new(Style::default())
}

View file

@ -2,7 +2,7 @@ use crate::{Primitive, Renderer};
use iced_native::{radio, Layout, Node, Point, Radio, Style};
impl radio::Renderer for Renderer {
fn node<Message>(&mut self, _checkbox: &Radio<Message>) -> Node {
fn node<Message>(&self, _checkbox: &Radio<Message>) -> Node {
Node::new(Style::default())
}

View file

@ -1,5 +1,5 @@
use crate::{Primitive, Renderer};
use iced_native::{text, Layout, Node, Style, Text};
use iced_native::{text, Color, Layout, Node, Style, Text};
use wgpu_glyph::{GlyphCruncher, Section};
@ -72,6 +72,9 @@ impl text::Renderer for Renderer {
content: text.content.clone(),
size: f32::from(text.size.unwrap_or(20)),
bounds: layout.bounds(),
color: text.color.unwrap_or(Color::BLACK),
horizontal_alignment: text.horizontal_alignment,
vertical_alignment: text.vertical_alignment,
}
}
}

View file

@ -3,6 +3,7 @@
layout(location = 0) in vec4 v_Color;
layout(location = 1) in vec2 v_Pos;
layout(location = 2) in vec2 v_Scale;
layout(location = 3) in flat uint v_BorderRadius;
layout(location = 0) out vec4 o_Color;
@ -26,8 +27,11 @@ float rounded(in vec2 frag_coord, in vec2 position, in vec2 size, float radius,
}
void main() {
o_Color = vec4(
v_Color.xyz,
v_Color.w * rounded(gl_FragCoord.xy, v_Pos, v_Scale, 5.0, 1.0)
);
float radius_alpha = 1.0;
if(v_BorderRadius > 0.0) {
radius_alpha = rounded(gl_FragCoord.xy, v_Pos, v_Scale, v_BorderRadius, 1.0);
}
o_Color = vec4(v_Color.xyz, v_Color.w * radius_alpha);
}

Binary file not shown.

View file

@ -4,6 +4,7 @@ layout(location = 0) in vec2 v_Pos;
layout(location = 1) in vec2 i_Pos;
layout(location = 2) in vec2 i_Scale;
layout(location = 3) in vec4 i_Color;
layout(location = 4) in uint i_BorderRadius;
layout (set = 0, binding = 0) uniform Globals {
mat4 u_Transform;
@ -12,6 +13,7 @@ layout (set = 0, binding = 0) uniform Globals {
layout(location = 0) out vec4 o_Color;
layout(location = 1) out vec2 o_Pos;
layout(location = 2) out vec2 o_Scale;
layout(location = 3) out uint o_BorderRadius;
void main() {
mat4 i_Transform = mat4(
@ -24,6 +26,7 @@ void main() {
o_Color = i_Color;
o_Pos = i_Pos;
o_Scale = i_Scale;
o_BorderRadius = i_BorderRadius;
gl_Position = u_Transform * i_Transform * vec4(v_Pos, 0.0, 1.0);
}

Binary file not shown.