summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2019-12-31 21:35:42 +0100
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2019-12-31 21:38:52 +0100
commit9ab7c47dc7d834ee73bc068f9f34eea4d6946436 (patch)
treeea52e51ffef12208a47fe29299c70095ad403957
parent649d72e7de88e593255075957e65414ed1b4d0d6 (diff)
downloadiced-9ab7c47dc7d834ee73bc068f9f34eea4d6946436.tar.gz
iced-9ab7c47dc7d834ee73bc068f9f34eea4d6946436.tar.bz2
iced-9ab7c47dc7d834ee73bc068f9f34eea4d6946436.zip
Add `border_width` and `border_color` to `Quad`
-rw-r--r--core/src/color.rs8
-rw-r--r--examples/custom_widget.rs2
-rw-r--r--examples/tour.rs2
-rw-r--r--wgpu/src/primitive.rs4
-rw-r--r--wgpu/src/quad.rs17
-rw-r--r--wgpu/src/renderer.rs9
-rw-r--r--wgpu/src/renderer/widget/button.rs8
-rw-r--r--wgpu/src/renderer/widget/checkbox.rs44
-rw-r--r--wgpu/src/renderer/widget/container.rs4
-rw-r--r--wgpu/src/renderer/widget/radio.rs46
-rw-r--r--wgpu/src/renderer/widget/scrollable.rs8
-rw-r--r--wgpu/src/renderer/widget/slider.rs58
-rw-r--r--wgpu/src/renderer/widget/text_input.rs33
-rw-r--r--wgpu/src/shader/quad.frag51
-rw-r--r--wgpu/src/shader/quad.frag.spvbin3044 -> 4212 bytes
-rw-r--r--wgpu/src/shader/quad.vert14
-rw-r--r--wgpu/src/shader/quad.vert.spvbin3020 -> 3372 bytes
17 files changed, 180 insertions, 128 deletions
diff --git a/core/src/color.rs b/core/src/color.rs
index c28e784f..d72651d9 100644
--- a/core/src/color.rs
+++ b/core/src/color.rs
@@ -25,6 +25,14 @@ impl Color {
a: 1.0,
};
+ /// A color with no opacity.
+ pub const TRANSPARENT: Color = Color {
+ r: 0.0,
+ g: 0.0,
+ b: 0.0,
+ a: 0.0,
+ };
+
/// Creates a [`Color`] from its RGB8 components.
///
/// [`Color`]: struct.Color.html
diff --git a/examples/custom_widget.rs b/examples/custom_widget.rs
index ca562ead..1f51ee54 100644
--- a/examples/custom_widget.rs
+++ b/examples/custom_widget.rs
@@ -63,6 +63,8 @@ mod circle {
bounds: layout.bounds(),
background: Background::Color(Color::BLACK),
border_radius: self.radius,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
},
MouseCursor::OutOfBounds,
)
diff --git a/examples/tour.rs b/examples/tour.rs
index c7f866e8..d006d397 100644
--- a/examples/tour.rs
+++ b/examples/tour.rs
@@ -27,7 +27,7 @@ impl Sandbox for Tour {
scroll: scrollable::State::new(),
back_button: button::State::new(),
next_button: button::State::new(),
- debug: false,
+ debug: true,
}
}
diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs
index 6c61f800..f4609151 100644
--- a/wgpu/src/primitive.rs
+++ b/wgpu/src/primitive.rs
@@ -38,6 +38,10 @@ pub enum Primitive {
background: Background,
/// The border radius of the quad
border_radius: u16,
+ /// The border width of the quad
+ border_width: u16,
+ /// The border color of the quad
+ border_color: Color,
},
/// An image primitive
Image {
diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs
index c292dec3..fe3276a3 100644
--- a/wgpu/src/quad.rs
+++ b/wgpu/src/quad.rs
@@ -125,9 +125,19 @@ impl Pipeline {
},
wgpu::VertexAttributeDescriptor {
shader_location: 4,
- format: wgpu::VertexFormat::Float,
+ format: wgpu::VertexFormat::Float4,
offset: 4 * (2 + 2 + 4),
},
+ wgpu::VertexAttributeDescriptor {
+ shader_location: 5,
+ format: wgpu::VertexFormat::Float,
+ offset: 4 * (2 + 2 + 4 + 4),
+ },
+ wgpu::VertexAttributeDescriptor {
+ shader_location: 6,
+ format: wgpu::VertexFormat::Float,
+ offset: 4 * (2 + 2 + 4 + 4 + 1),
+ },
],
},
],
@@ -233,7 +243,8 @@ impl Pipeline {
bounds.x,
bounds.y,
bounds.width,
- bounds.height,
+ // TODO: Address anti-aliasing adjustments properly
+ bounds.height + 1,
);
render_pass.draw_indexed(
@@ -277,7 +288,9 @@ pub struct Quad {
pub position: [f32; 2],
pub scale: [f32; 2],
pub color: [f32; 4],
+ pub border_color: [f32; 4],
pub border_radius: f32,
+ pub border_width: f32,
}
impl Quad {
diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs
index 1b143d90..efda046b 100644
--- a/wgpu/src/renderer.rs
+++ b/wgpu/src/renderer.rs
@@ -223,6 +223,8 @@ impl Renderer {
bounds,
background,
border_radius,
+ border_width,
+ border_color,
} => {
// TODO: Move some of this computations to the GPU (?)
layer.quads.push(Quad {
@@ -235,6 +237,8 @@ impl Renderer {
Background::Color(color) => color.into_linear(),
},
border_radius: *border_radius as f32,
+ border_width: *border_width as f32,
+ border_color: border_color.into_linear(),
});
}
Primitive::Image { handle, bounds } => {
@@ -470,11 +474,12 @@ fn explain_layout(
color: Color,
primitives: &mut Vec<Primitive>,
) {
- // TODO: Draw borders instead
primitives.push(Primitive::Quad {
bounds: layout.bounds(),
- background: Background::Color([0.0, 0.0, 0.0, 0.05].into()),
+ background: Background::Color(Color::TRANSPARENT),
border_radius: 0,
+ border_width: 1,
+ border_color: [0.6, 0.6, 0.6, 0.5].into(),
});
for child in layout.children() {
diff --git a/wgpu/src/renderer/widget/button.rs b/wgpu/src/renderer/widget/button.rs
index 4fbd90d7..d00a43a5 100644
--- a/wgpu/src/renderer/widget/button.rs
+++ b/wgpu/src/renderer/widget/button.rs
@@ -1,5 +1,7 @@
use crate::{button::StyleSheet, defaults, Defaults, Primitive, Renderer};
-use iced_native::{Background, Element, Layout, MouseCursor, Point, Rectangle};
+use iced_native::{
+ Background, Color, Element, Layout, MouseCursor, Point, Rectangle,
+};
impl iced_native::button::Renderer for Renderer {
type Style = Box<dyn StyleSheet>;
@@ -57,11 +59,15 @@ impl iced_native::button::Renderer for Renderer {
[0.0, 0.0, 0.0, 0.5].into(),
),
border_radius: styling.border_radius,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
},
Primitive::Quad {
bounds,
background,
border_radius: styling.border_radius,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
},
content,
],
diff --git a/wgpu/src/renderer/widget/checkbox.rs b/wgpu/src/renderer/widget/checkbox.rs
index 54b4b1cc..1ed27ff7 100644
--- a/wgpu/src/renderer/widget/checkbox.rs
+++ b/wgpu/src/renderer/widget/checkbox.rs
@@ -1,6 +1,6 @@
use crate::{Primitive, Renderer};
use iced_native::{
- checkbox, Background, HorizontalAlignment, MouseCursor, Rectangle,
+ checkbox, Background, Color, HorizontalAlignment, MouseCursor, Rectangle,
VerticalAlignment,
};
@@ -18,30 +18,20 @@ impl checkbox::Renderer for Renderer {
is_mouse_over: bool,
(label, _): Self::Output,
) -> Self::Output {
- let (checkbox_border, checkbox_box) = (
- Primitive::Quad {
- bounds,
- background: Background::Color([0.6, 0.6, 0.6].into()),
- border_radius: 6,
- },
- Primitive::Quad {
- bounds: Rectangle {
- x: bounds.x + 1.0,
- y: bounds.y + 1.0,
- width: bounds.width - 2.0,
- height: bounds.height - 2.0,
- },
- background: Background::Color(
- if is_mouse_over {
- [0.90, 0.90, 0.90]
- } else {
- [0.95, 0.95, 0.95]
- }
- .into(),
- ),
- border_radius: 5,
- },
- );
+ let checkbox = Primitive::Quad {
+ bounds,
+ background: Background::Color(
+ if is_mouse_over {
+ [0.90, 0.90, 0.90]
+ } else {
+ [0.95, 0.95, 0.95]
+ }
+ .into(),
+ ),
+ border_radius: 5,
+ border_width: 1,
+ border_color: Color::from_rgb(0.6, 0.6, 0.6),
+ };
(
Primitive::Group {
@@ -56,9 +46,9 @@ impl checkbox::Renderer for Renderer {
vertical_alignment: VerticalAlignment::Center,
};
- vec![checkbox_border, checkbox_box, check, label]
+ vec![checkbox, check, label]
} else {
- vec![checkbox_border, checkbox_box, label]
+ vec![checkbox, label]
},
},
if is_mouse_over {
diff --git a/wgpu/src/renderer/widget/container.rs b/wgpu/src/renderer/widget/container.rs
index 29c709f8..18908571 100644
--- a/wgpu/src/renderer/widget/container.rs
+++ b/wgpu/src/renderer/widget/container.rs
@@ -1,5 +1,5 @@
use crate::{container, defaults, Defaults, Primitive, Renderer};
-use iced_native::{Element, Layout, Point, Rectangle};
+use iced_native::{Color, Element, Layout, Point, Rectangle};
impl iced_native::container::Renderer for Renderer {
type Style = Box<dyn container::StyleSheet>;
@@ -31,6 +31,8 @@ impl iced_native::container::Renderer for Renderer {
bounds,
background,
border_radius: style.border_radius,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
};
(
diff --git a/wgpu/src/renderer/widget/radio.rs b/wgpu/src/renderer/widget/radio.rs
index 3c00a4c2..aa1dbadc 100644
--- a/wgpu/src/renderer/widget/radio.rs
+++ b/wgpu/src/renderer/widget/radio.rs
@@ -1,5 +1,5 @@
use crate::{Primitive, Renderer};
-use iced_native::{radio, Background, MouseCursor, Rectangle};
+use iced_native::{radio, Background, Color, MouseCursor, Rectangle};
const SIZE: f32 = 28.0;
const DOT_SIZE: f32 = SIZE / 2.0;
@@ -16,30 +16,20 @@ impl radio::Renderer for Renderer {
is_mouse_over: bool,
(label, _): Self::Output,
) -> Self::Output {
- let (radio_border, radio_box) = (
- Primitive::Quad {
- bounds,
- background: Background::Color([0.6, 0.6, 0.6].into()),
- border_radius: (SIZE / 2.0) as u16,
- },
- Primitive::Quad {
- bounds: Rectangle {
- x: bounds.x + 1.0,
- y: bounds.y + 1.0,
- width: bounds.width - 2.0,
- height: bounds.height - 2.0,
- },
- background: Background::Color(
- if is_mouse_over {
- [0.90, 0.90, 0.90]
- } else {
- [0.95, 0.95, 0.95]
- }
- .into(),
- ),
- border_radius: (SIZE / 2.0 - 1.0) as u16,
- },
- );
+ let radio = Primitive::Quad {
+ bounds,
+ background: Background::Color(
+ if is_mouse_over {
+ [0.90, 0.90, 0.90]
+ } else {
+ [0.95, 0.95, 0.95]
+ }
+ .into(),
+ ),
+ border_radius: (SIZE / 2.0) as u16,
+ border_width: 1,
+ border_color: Color::from_rgb(0.6, 0.6, 0.6),
+ };
(
Primitive::Group {
@@ -53,11 +43,13 @@ impl radio::Renderer for Renderer {
},
background: Background::Color([0.3, 0.3, 0.3].into()),
border_radius: (DOT_SIZE / 2.0) as u16,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
};
- vec![radio_border, radio_box, radio_circle, label]
+ vec![radio, radio_circle, label]
} else {
- vec![radio_border, radio_box, label]
+ vec![radio, label]
},
},
if is_mouse_over {
diff --git a/wgpu/src/renderer/widget/scrollable.rs b/wgpu/src/renderer/widget/scrollable.rs
index 6ef57185..42a4a743 100644
--- a/wgpu/src/renderer/widget/scrollable.rs
+++ b/wgpu/src/renderer/widget/scrollable.rs
@@ -1,5 +1,7 @@
use crate::{Primitive, Renderer};
-use iced_native::{scrollable, Background, MouseCursor, Rectangle, Vector};
+use iced_native::{
+ scrollable, Background, Color, MouseCursor, Rectangle, Vector,
+};
const SCROLLBAR_WIDTH: u16 = 10;
const SCROLLBAR_MARGIN: u16 = 2;
@@ -68,6 +70,8 @@ impl scrollable::Renderer for Renderer {
[0.0, 0.0, 0.0, 0.7].into(),
),
border_radius: 5,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
};
if is_mouse_over_scrollbar || state.is_scroller_grabbed() {
@@ -83,6 +87,8 @@ impl scrollable::Renderer for Renderer {
[0.0, 0.0, 0.0, 0.3].into(),
),
border_radius: 5,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
};
Primitive::Group {
diff --git a/wgpu/src/renderer/widget/slider.rs b/wgpu/src/renderer/widget/slider.rs
index c73a4e56..386decb5 100644
--- a/wgpu/src/renderer/widget/slider.rs
+++ b/wgpu/src/renderer/widget/slider.rs
@@ -29,8 +29,10 @@ impl slider::Renderer for Renderer {
width: bounds.width,
height: 2.0,
},
- background: Color::from_rgb(0.6, 0.6, 0.6).into(),
+ background: Background::Color([0.6, 0.6, 0.6, 0.5].into()),
border_radius: 0,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
},
Primitive::Quad {
bounds: Rectangle {
@@ -41,6 +43,8 @@ impl slider::Renderer for Renderer {
},
background: Background::Color(Color::WHITE),
border_radius: 0,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
},
);
@@ -49,41 +53,31 @@ impl slider::Renderer for Renderer {
let handle_offset = (bounds.width - HANDLE_WIDTH)
* ((value - range_start) / (range_end - range_start).max(1.0));
- let (handle_border, handle) = (
- Primitive::Quad {
- bounds: Rectangle {
- x: bounds.x + handle_offset.round() - 1.0,
- y: rail_y - HANDLE_HEIGHT / 2.0 - 1.0,
- width: HANDLE_WIDTH + 2.0,
- height: HANDLE_HEIGHT + 2.0,
- },
- background: Color::from_rgb(0.6, 0.6, 0.6).into(),
- border_radius: 5,
- },
- 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(
- if is_dragging {
- [0.85, 0.85, 0.85]
- } else if is_mouse_over {
- [0.90, 0.90, 0.90]
- } else {
- [0.95, 0.95, 0.95]
- }
- .into(),
- ),
- border_radius: 4,
+ 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(
+ if is_dragging {
+ [0.85, 0.85, 0.85]
+ } else if is_mouse_over {
+ [0.90, 0.90, 0.90]
+ } else {
+ [0.95, 0.95, 0.95]
+ }
+ .into(),
+ ),
+ border_radius: 4,
+ border_width: 1,
+ border_color: Color::from_rgb(0.6, 0.6, 0.6),
+ };
(
Primitive::Group {
- primitives: vec![rail_top, rail_bottom, handle_border, handle],
+ primitives: vec![rail_top, rail_bottom, handle],
},
if is_dragging {
MouseCursor::Grabbing
diff --git a/wgpu/src/renderer/widget/text_input.rs b/wgpu/src/renderer/widget/text_input.rs
index 929f94db..cf3a31ab 100644
--- a/wgpu/src/renderer/widget/text_input.rs
+++ b/wgpu/src/renderer/widget/text_input.rs
@@ -64,28 +64,17 @@ impl text_input::Renderer for Renderer {
) -> Self::Output {
let is_mouse_over = bounds.contains(cursor_position);
- let border = Primitive::Quad {
- bounds,
- background: Background::Color(
- if is_mouse_over || state.is_focused() {
- [0.5, 0.5, 0.5]
- } else {
- [0.7, 0.7, 0.7]
- }
- .into(),
- ),
- border_radius: 5,
- };
-
let input = Primitive::Quad {
- bounds: Rectangle {
- x: bounds.x + 1.0,
- y: bounds.y + 1.0,
- width: bounds.width - 2.0,
- height: bounds.height - 2.0,
- },
+ bounds,
background: Background::Color(Color::WHITE),
- border_radius: 4,
+ border_radius: 5,
+ border_width: 1,
+ border_color: if is_mouse_over || state.is_focused() {
+ [0.5, 0.5, 0.5]
+ } else {
+ [0.7, 0.7, 0.7]
+ }
+ .into(),
};
let text = value.to_string();
@@ -130,6 +119,8 @@ impl text_input::Renderer for Renderer {
},
background: Background::Color(Color::BLACK),
border_radius: 0,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
};
(
@@ -150,7 +141,7 @@ impl text_input::Renderer for Renderer {
(
Primitive::Group {
- primitives: vec![border, input, contents],
+ primitives: vec![input, contents],
},
if is_mouse_over {
MouseCursor::Text
diff --git a/wgpu/src/shader/quad.frag b/wgpu/src/shader/quad.frag
index 2ee77e71..ad1af1ad 100644
--- a/wgpu/src/shader/quad.frag
+++ b/wgpu/src/shader/quad.frag
@@ -1,14 +1,17 @@
#version 450
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 float v_BorderRadius;
+layout(location = 1) in vec4 v_BorderColor;
+layout(location = 2) in vec2 v_Pos;
+layout(location = 3) in vec2 v_Scale;
+layout(location = 4) in float v_BorderRadius;
+layout(location = 5) in float v_BorderWidth;
layout(location = 0) out vec4 o_Color;
-float rounded(in vec2 frag_coord, in vec2 position, in vec2 size, float radius, float s)
+float distance(in vec2 frag_coord, in vec2 position, in vec2 size, float radius)
{
+ // TODO: Try SDF approach: https://www.shadertoy.com/view/wd3XRN
vec2 inner_size = size - vec2(radius, radius) * 2.0;
vec2 top_left = position + vec2(radius, radius);
vec2 bottom_right = top_left + inner_size;
@@ -21,13 +24,43 @@ float rounded(in vec2 frag_coord, in vec2 position, in vec2 size, float radius,
max(max(top_left_distance.y, bottom_right_distance.y), 0)
);
- float d = sqrt(distance.x * distance.x + distance.y * distance.y);
-
- return 1.0 - smoothstep(radius - s, radius + s, d);
+ return sqrt(distance.x * distance.x + distance.y * distance.y);
}
void main() {
- float radius_alpha = rounded(gl_FragCoord.xy, v_Pos, v_Scale, v_BorderRadius, 0.5);
+ vec4 mixed_color;
+
+ // TODO: Remove branching (?)
+ if(v_BorderWidth > 0) {
+ float internal_border = max(v_BorderRadius - v_BorderWidth, 0);
+
+ float internal_distance = distance(
+ gl_FragCoord.xy,
+ v_Pos + vec2(v_BorderWidth),
+ v_Scale - vec2(v_BorderWidth * 2.0),
+ internal_border
+ );
+
+ float border_mix = smoothstep(
+ max(internal_border - 0.5, 0.0),
+ internal_border + 0.5,
+ internal_distance
+ );
+
+ mixed_color = mix(v_Color, v_BorderColor, border_mix);
+ } else {
+ mixed_color = v_Color;
+ }
+
+ float d = distance(
+ gl_FragCoord.xy,
+ v_Pos,
+ v_Scale,
+ v_BorderRadius
+ );
+
+ float radius_alpha =
+ 1.0 - smoothstep(max(v_BorderRadius - 0.5, 0), v_BorderRadius + 0.5, d);
- o_Color = vec4(v_Color.xyz, v_Color.w * radius_alpha);
+ o_Color = vec4(mixed_color.xyz, mixed_color.w * radius_alpha);
}
diff --git a/wgpu/src/shader/quad.frag.spv b/wgpu/src/shader/quad.frag.spv
index 17bd8f46..519f5f01 100644
--- a/wgpu/src/shader/quad.frag.spv
+++ b/wgpu/src/shader/quad.frag.spv
Binary files differ
diff --git a/wgpu/src/shader/quad.vert b/wgpu/src/shader/quad.vert
index 539755cb..1d9a4fd2 100644
--- a/wgpu/src/shader/quad.vert
+++ b/wgpu/src/shader/quad.vert
@@ -4,7 +4,9 @@ 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 float i_BorderRadius;
+layout(location = 4) in vec4 i_BorderColor;
+layout(location = 5) in float i_BorderRadius;
+layout(location = 6) in float i_BorderWidth;
layout (set = 0, binding = 0) uniform Globals {
mat4 u_Transform;
@@ -12,9 +14,11 @@ 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 float o_BorderRadius;
+layout(location = 1) out vec4 o_BorderColor;
+layout(location = 2) out vec2 o_Pos;
+layout(location = 3) out vec2 o_Scale;
+layout(location = 4) out float o_BorderRadius;
+layout(location = 5) out float o_BorderWidth;
void main() {
vec2 p_Pos = i_Pos * u_Scale;
@@ -28,9 +32,11 @@ void main() {
);
o_Color = i_Color;
+ o_BorderColor = i_BorderColor;
o_Pos = p_Pos;
o_Scale = p_Scale;
o_BorderRadius = i_BorderRadius * u_Scale;
+ o_BorderWidth = i_BorderWidth * u_Scale;
gl_Position = u_Transform * i_Transform * vec4(v_Pos, 0.0, 1.0);
}
diff --git a/wgpu/src/shader/quad.vert.spv b/wgpu/src/shader/quad.vert.spv
index 9050adfb..7059b51b 100644
--- a/wgpu/src/shader/quad.vert.spv
+++ b/wgpu/src/shader/quad.vert.spv
Binary files differ