summaryrefslogtreecommitdiffstats
path: root/wgpu
diff options
context:
space:
mode:
Diffstat (limited to 'wgpu')
-rw-r--r--wgpu/Cargo.toml1
-rw-r--r--wgpu/src/defaults.rs27
-rw-r--r--wgpu/src/lib.rs17
-rw-r--r--wgpu/src/primitive.rs4
-rw-r--r--wgpu/src/quad.rs17
-rw-r--r--wgpu/src/renderer.rs29
-rw-r--r--wgpu/src/renderer/widget.rs1
-rw-r--r--wgpu/src/renderer/widget/button.rs101
-rw-r--r--wgpu/src/renderer/widget/checkbox.rs44
-rw-r--r--wgpu/src/renderer/widget/column.rs3
-rw-r--r--wgpu/src/renderer/widget/container.rs49
-rw-r--r--wgpu/src/renderer/widget/progress_bar.rs4
-rw-r--r--wgpu/src/renderer/widget/radio.rs46
-rw-r--r--wgpu/src/renderer/widget/row.rs3
-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.rs3
-rw-r--r--wgpu/src/renderer/widget/text_input.rs45
-rw-r--r--wgpu/src/settings.rs4
-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
-rw-r--r--wgpu/src/text.rs11
-rw-r--r--wgpu/src/widget.rs3
-rw-r--r--wgpu/src/widget/button.rs15
-rw-r--r--wgpu/src/widget/container.rs10
-rw-r--r--wgpu/src/widget/text_input.rs15
28 files changed, 402 insertions, 181 deletions
diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml
index bb241914..19d41bba 100644
--- a/wgpu/Cargo.toml
+++ b/wgpu/Cargo.toml
@@ -12,6 +12,7 @@ svg = ["resvg"]
[dependencies]
iced_native = { version = "0.1.0", path = "../native" }
+iced_style = { version = "0.1.0-alpha", path = "../style" }
wgpu = "0.4"
glyph_brush = "0.6"
wgpu_glyph = { version = "0.7", git = "https://github.com/hecrj/wgpu_glyph", branch = "fix/font-load-panic" }
diff --git a/wgpu/src/defaults.rs b/wgpu/src/defaults.rs
new file mode 100644
index 00000000..8de8258b
--- /dev/null
+++ b/wgpu/src/defaults.rs
@@ -0,0 +1,27 @@
+use iced_native::Color;
+
+#[derive(Debug, Clone, Copy)]
+pub struct Defaults {
+ pub text: Text,
+}
+
+impl Default for Defaults {
+ fn default() -> Defaults {
+ Defaults {
+ text: Text::default(),
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct Text {
+ pub color: Color,
+}
+
+impl Default for Text {
+ fn default() -> Text {
+ Text {
+ color: Color::BLACK,
+ }
+ }
+}
diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs
index 972f56af..dda4f322 100644
--- a/wgpu/src/lib.rs
+++ b/wgpu/src/lib.rs
@@ -19,23 +19,30 @@
//! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
//! [WebGPU API]: https://gpuweb.github.io/gpuweb/
//! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph
-#![deny(missing_docs)]
+//#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![deny(unused_results)]
#![deny(unsafe_code)]
#![deny(rust_2018_idioms)]
+pub mod defaults;
pub mod triangle;
+pub mod widget;
mod image;
mod primitive;
mod quad;
mod renderer;
+mod settings;
mod text;
mod transformation;
-pub(crate) use crate::image::Image;
-pub(crate) use quad::Quad;
-pub(crate) use transformation::Transformation;
-
+pub use defaults::Defaults;
pub use primitive::Primitive;
pub use renderer::{Renderer, Target};
+pub use settings::Settings;
+#[doc(no_inline)]
+pub use widget::*;
+
+pub(crate) use self::image::Image;
+pub(crate) use quad::Quad;
+pub(crate) use transformation::Transformation;
diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs
index 815ba3b0..481252ef 100644
--- a/wgpu/src/primitive.rs
+++ b/wgpu/src/primitive.rs
@@ -41,6 +41,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 050daca9..9757904c 100644
--- a/wgpu/src/renderer.rs
+++ b/wgpu/src/renderer.rs
@@ -1,5 +1,6 @@
use crate::{
- image, quad, text, triangle, Image, Primitive, Quad, Transformation,
+ image, quad, text, triangle, Defaults, Image, Primitive, Quad, Settings,
+ Transformation,
};
use iced_native::{
renderer::{Debugger, Windowed},
@@ -24,7 +25,7 @@ pub struct Renderer {
device: Device,
queue: Queue,
quad_pipeline: quad::Pipeline,
- image_pipeline: crate::image::Pipeline,
+ image_pipeline: image::Pipeline,
text_pipeline: text::Pipeline,
triangle_pipeline: crate::triangle::Pipeline,
}
@@ -52,7 +53,7 @@ impl<'a> Layer<'a> {
}
impl Renderer {
- fn new() -> Self {
+ fn new(settings: Settings) -> Self {
let adapter = Adapter::request(&RequestAdapterOptions {
power_preference: PowerPreference::Default,
backends: BackendBit::all(),
@@ -66,7 +67,8 @@ impl Renderer {
limits: Limits { max_bind_groups: 2 },
});
- let text_pipeline = text::Pipeline::new(&mut device);
+ let text_pipeline =
+ text::Pipeline::new(&mut device, settings.default_font);
let quad_pipeline = quad::Pipeline::new(&mut device);
let image_pipeline = crate::image::Pipeline::new(&mut device);
let triangle_pipeline = triangle::Pipeline::new(&mut device);
@@ -223,6 +225,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 +239,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 } => {
@@ -434,6 +440,7 @@ impl Renderer {
impl iced_native::Renderer for Renderer {
type Output = (Primitive, MouseCursor);
+ type Defaults = Defaults;
fn layout<'a, Message>(
&mut self,
@@ -448,10 +455,11 @@ impl iced_native::Renderer for Renderer {
}
impl Windowed for Renderer {
+ type Settings = Settings;
type Target = Target;
- fn new() -> Self {
- Self::new()
+ fn new(settings: Settings) -> Self {
+ Self::new(settings)
}
fn draw<T: AsRef<str>>(
@@ -467,13 +475,15 @@ impl Windowed for Renderer {
impl Debugger for Renderer {
fn explain<Message>(
&mut self,
+ defaults: &Defaults,
widget: &dyn Widget<Message, Self>,
layout: Layout<'_>,
cursor_position: Point,
color: Color,
) -> Self::Output {
let mut primitives = Vec::new();
- let (primitive, cursor) = widget.draw(self, layout, cursor_position);
+ let (primitive, cursor) =
+ widget.draw(self, defaults, layout, cursor_position);
explain_layout(layout, color, &mut primitives);
primitives.push(primitive);
@@ -487,11 +497,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.rs b/wgpu/src/renderer/widget.rs
index 32187c10..2c75413f 100644
--- a/wgpu/src/renderer/widget.rs
+++ b/wgpu/src/renderer/widget.rs
@@ -1,6 +1,7 @@
mod button;
mod checkbox;
mod column;
+mod container;
mod image;
mod progress_bar;
mod radio;
diff --git a/wgpu/src/renderer/widget/button.rs b/wgpu/src/renderer/widget/button.rs
index 86963053..eb5d7c09 100644
--- a/wgpu/src/renderer/widget/button.rs
+++ b/wgpu/src/renderer/widget/button.rs
@@ -1,54 +1,87 @@
-use crate::{Primitive, Renderer};
-use iced_native::{button, Background, MouseCursor, Point, Rectangle};
+use crate::{button::StyleSheet, defaults, Defaults, Primitive, Renderer};
+use iced_native::{
+ Background, Color, Element, Layout, MouseCursor, Point, Rectangle, Vector,
+};
-impl button::Renderer for Renderer {
- fn draw(
+impl iced_native::button::Renderer for Renderer {
+ type Style = Box<dyn StyleSheet>;
+
+ fn draw<Message>(
&mut self,
+ defaults: &Defaults,
bounds: Rectangle,
cursor_position: Point,
+ is_disabled: bool,
is_pressed: bool,
- background: Option<Background>,
- border_radius: u16,
- (content, _): Self::Output,
+ style: &Box<dyn StyleSheet>,
+ content: &Element<'_, Message, Self>,
+ content_layout: Layout<'_>,
) -> Self::Output {
let is_mouse_over = bounds.contains(cursor_position);
// TODO: Render proper shadows
- // TODO: Make hovering and pressed styles configurable
- let shadow_offset = if is_mouse_over {
+ let styling = if is_disabled {
+ style.disabled()
+ } else if is_mouse_over {
if is_pressed {
- 0.0
+ style.pressed()
} else {
- 2.0
+ style.hovered()
}
} else {
- 1.0
+ style.active()
};
+ let (content, _) = content.draw(
+ self,
+ &Defaults {
+ text: defaults::Text {
+ color: styling.text_color,
+ },
+ ..*defaults
+ },
+ content_layout,
+ cursor_position,
+ );
+
(
- match background {
- None => content,
- Some(background) => Primitive::Group {
- primitives: vec![
- Primitive::Quad {
- bounds: Rectangle {
- x: bounds.x + 1.0,
- y: bounds.y + shadow_offset,
- ..bounds
- },
- background: Background::Color(
- [0.0, 0.0, 0.0, 0.5].into(),
- ),
- border_radius,
- },
- Primitive::Quad {
- bounds,
- background,
- border_radius,
+ if styling.background.is_some() || styling.border_width > 0 {
+ let background = Primitive::Quad {
+ bounds,
+ background: styling
+ .background
+ .unwrap_or(Background::Color(Color::TRANSPARENT)),
+ border_radius: styling.border_radius,
+ border_width: styling.border_width,
+ border_color: styling.border_color,
+ };
+
+ if styling.shadow_offset == Vector::default() {
+ Primitive::Group {
+ primitives: vec![background, content],
+ }
+ } else {
+ // TODO: Implement proper shadow support
+ let shadow = Primitive::Quad {
+ bounds: Rectangle {
+ x: bounds.x + styling.shadow_offset.x,
+ y: bounds.y + styling.shadow_offset.y,
+ ..bounds
},
- content,
- ],
- },
+ background: Background::Color(
+ [0.0, 0.0, 0.0, 0.5].into(),
+ ),
+ border_radius: styling.border_radius,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
+ };
+
+ Primitive::Group {
+ primitives: vec![shadow, background, content],
+ }
+ }
+ } else {
+ content
},
if is_mouse_over {
MouseCursor::Pointer
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/column.rs b/wgpu/src/renderer/widget/column.rs
index 6c31af90..95a7463a 100644
--- a/wgpu/src/renderer/widget/column.rs
+++ b/wgpu/src/renderer/widget/column.rs
@@ -4,6 +4,7 @@ use iced_native::{column, Element, Layout, MouseCursor, Point};
impl column::Renderer for Renderer {
fn draw<Message>(
&mut self,
+ defaults: &Self::Defaults,
content: &[Element<'_, Message, Self>],
layout: Layout<'_>,
cursor_position: Point,
@@ -17,7 +18,7 @@ impl column::Renderer for Renderer {
.zip(layout.children())
.map(|(child, layout)| {
let (primitive, new_mouse_cursor) =
- child.draw(self, layout, cursor_position);
+ child.draw(self, defaults, layout, cursor_position);
if new_mouse_cursor > mouse_cursor {
mouse_cursor = new_mouse_cursor;
diff --git a/wgpu/src/renderer/widget/container.rs b/wgpu/src/renderer/widget/container.rs
new file mode 100644
index 00000000..2d4d1db8
--- /dev/null
+++ b/wgpu/src/renderer/widget/container.rs
@@ -0,0 +1,49 @@
+use crate::{container, defaults, Defaults, Primitive, Renderer};
+use iced_native::{Background, Color, Element, Layout, Point, Rectangle};
+
+impl iced_native::container::Renderer for Renderer {
+ type Style = Box<dyn container::StyleSheet>;
+
+ fn draw<Message>(
+ &mut self,
+ defaults: &Defaults,
+ bounds: Rectangle,
+ cursor_position: Point,
+ style_sheet: &Self::Style,
+ content: &Element<'_, Message, Self>,
+ content_layout: Layout<'_>,
+ ) -> Self::Output {
+ let style = style_sheet.style();
+
+ let defaults = Defaults {
+ text: defaults::Text {
+ color: style.text_color.unwrap_or(defaults.text.color),
+ },
+ ..*defaults
+ };
+
+ let (content, mouse_cursor) =
+ content.draw(self, &defaults, content_layout, cursor_position);
+
+ if style.background.is_some() || style.border_width > 0 {
+ let quad = Primitive::Quad {
+ bounds,
+ background: style
+ .background
+ .unwrap_or(Background::Color(Color::TRANSPARENT)),
+ border_radius: style.border_radius,
+ border_width: style.border_width,
+ border_color: style.border_color,
+ };
+
+ (
+ Primitive::Group {
+ primitives: vec![quad, content],
+ },
+ mouse_cursor,
+ )
+ } else {
+ (content, mouse_cursor)
+ }
+ }
+}
diff --git a/wgpu/src/renderer/widget/progress_bar.rs b/wgpu/src/renderer/widget/progress_bar.rs
index 8ed4bab7..e9346fda 100644
--- a/wgpu/src/renderer/widget/progress_bar.rs
+++ b/wgpu/src/renderer/widget/progress_bar.rs
@@ -23,6 +23,8 @@ impl progress_bar::Renderer for Renderer {
.unwrap_or(Background::Color([0.6, 0.6, 0.6].into()))
.into(),
border_radius: 5,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
}],
};
@@ -35,6 +37,8 @@ impl progress_bar::Renderer for Renderer {
active_color.unwrap_or([0.0, 0.95, 0.0].into()),
),
border_radius: 5,
+ 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/row.rs b/wgpu/src/renderer/widget/row.rs
index f082dc61..bd9f1a04 100644
--- a/wgpu/src/renderer/widget/row.rs
+++ b/wgpu/src/renderer/widget/row.rs
@@ -4,6 +4,7 @@ use iced_native::{row, Element, Layout, MouseCursor, Point};
impl row::Renderer for Renderer {
fn draw<Message>(
&mut self,
+ defaults: &Self::Defaults,
children: &[Element<'_, Message, Self>],
layout: Layout<'_>,
cursor_position: Point,
@@ -17,7 +18,7 @@ impl row::Renderer for Renderer {
.zip(layout.children())
.map(|(child, layout)| {
let (primitive, new_mouse_cursor) =
- child.draw(self, layout, cursor_position);
+ child.draw(self, defaults, layout, cursor_position);
if new_mouse_cursor > mouse_cursor {
mouse_cursor = new_mouse_cursor;
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.rs b/wgpu/src/renderer/widget/text.rs
index 08a162ba..d61c5523 100644
--- a/wgpu/src/renderer/widget/text.rs
+++ b/wgpu/src/renderer/widget/text.rs
@@ -27,6 +27,7 @@ impl text::Renderer for Renderer {
fn draw(
&mut self,
+ defaults: &Self::Defaults,
bounds: Rectangle,
content: &str,
size: u16,
@@ -40,7 +41,7 @@ impl text::Renderer for Renderer {
content: content.to_string(),
size: f32::from(size),
bounds,
- color: color.unwrap_or(Color::BLACK),
+ color: color.unwrap_or(defaults.text.color),
font,
horizontal_alignment,
vertical_alignment,
diff --git a/wgpu/src/renderer/widget/text_input.rs b/wgpu/src/renderer/widget/text_input.rs
index 929f94db..8b774a48 100644
--- a/wgpu/src/renderer/widget/text_input.rs
+++ b/wgpu/src/renderer/widget/text_input.rs
@@ -1,4 +1,4 @@
-use crate::{Primitive, Renderer};
+use crate::{text_input::StyleSheet, Primitive, Renderer};
use iced_native::{
text_input, Background, Color, Font, HorizontalAlignment, MouseCursor,
@@ -7,6 +7,8 @@ use iced_native::{
use std::f32;
impl text_input::Renderer for Renderer {
+ type Style = Box<dyn StyleSheet>;
+
fn default_size(&self) -> u16 {
// TODO: Make this configurable
20
@@ -61,31 +63,24 @@ impl text_input::Renderer for Renderer {
placeholder: &str,
value: &text_input::Value,
state: &text_input::State,
+ style_sheet: &Self::Style,
) -> 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 style = if state.is_focused() {
+ style_sheet.focused()
+ } else if is_mouse_over {
+ style_sheet.hovered()
+ } else {
+ style_sheet.active()
};
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,
- },
- background: Background::Color(Color::WHITE),
- border_radius: 4,
+ bounds,
+ background: style.background,
+ border_radius: style.border_radius,
+ border_width: style.border_width,
+ border_color: style.border_color,
};
let text = value.to_string();
@@ -97,9 +92,9 @@ impl text_input::Renderer for Renderer {
text.clone()
},
color: if text.is_empty() {
- [0.7, 0.7, 0.7]
+ style_sheet.placeholder_color()
} else {
- [0.3, 0.3, 0.3]
+ style_sheet.value_color()
}
.into(),
font: Font::Default,
@@ -128,8 +123,10 @@ impl text_input::Renderer for Renderer {
width: 1.0,
height: text_bounds.height,
},
- background: Background::Color(Color::BLACK),
+ background: Background::Color(style_sheet.value_color()),
border_radius: 0,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
};
(
@@ -150,7 +147,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/settings.rs b/wgpu/src/settings.rs
new file mode 100644
index 00000000..c6d8369b
--- /dev/null
+++ b/wgpu/src/settings.rs
@@ -0,0 +1,4 @@
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+pub struct Settings {
+ pub default_font: Option<&'static [u8]>,
+}
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
diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs
index 880ad1a6..ab9a2f71 100644
--- a/wgpu/src/text.rs
+++ b/wgpu/src/text.rs
@@ -22,13 +22,16 @@ pub struct Pipeline {
}
impl Pipeline {
- pub fn new(device: &mut wgpu::Device) -> Self {
+ pub fn new(device: &mut wgpu::Device, default_font: Option<&[u8]>) -> Self {
// TODO: Font customization
let font_source = font::Source::new();
- let default_font = font_source
- .load(&[font::Family::SansSerif, font::Family::Serif])
- .unwrap_or_else(|_| FALLBACK_FONT.to_vec());
+ let default_font =
+ default_font.map(|slice| slice.to_vec()).unwrap_or_else(|| {
+ font_source
+ .load(&[font::Family::SansSerif, font::Family::Serif])
+ .unwrap_or_else(|_| FALLBACK_FONT.to_vec())
+ });
let load_glyph_brush = |font: Vec<u8>| {
let builder =
diff --git a/wgpu/src/widget.rs b/wgpu/src/widget.rs
new file mode 100644
index 00000000..1d7e57c4
--- /dev/null
+++ b/wgpu/src/widget.rs
@@ -0,0 +1,3 @@
+pub mod button;
+pub mod container;
+pub mod text_input;
diff --git a/wgpu/src/widget/button.rs b/wgpu/src/widget/button.rs
new file mode 100644
index 00000000..b738c55e
--- /dev/null
+++ b/wgpu/src/widget/button.rs
@@ -0,0 +1,15 @@
+//! Allow your users to perform actions by pressing a button.
+//!
+//! A [`Button`] has some local [`State`].
+//!
+//! [`Button`]: type.Button.html
+//! [`State`]: struct.State.html
+use crate::Renderer;
+
+pub use iced_native::button::State;
+pub use iced_style::button::{Style, StyleSheet};
+
+/// A widget that produces a message when clicked.
+///
+/// This is an alias of an `iced_native` button with an `iced_wgpu::Renderer`.
+pub type Button<'a, Message> = iced_native::Button<'a, Message, Renderer>;
diff --git a/wgpu/src/widget/container.rs b/wgpu/src/widget/container.rs
new file mode 100644
index 00000000..9a93a246
--- /dev/null
+++ b/wgpu/src/widget/container.rs
@@ -0,0 +1,10 @@
+//! Decorate content and apply alignment.
+use crate::Renderer;
+
+pub use iced_style::container::{Style, StyleSheet};
+
+/// An element decorating some content.
+///
+/// This is an alias of an `iced_native` container with a default
+/// `Renderer`.
+pub type Container<'a, Message> = iced_native::Container<'a, Message, Renderer>;
diff --git a/wgpu/src/widget/text_input.rs b/wgpu/src/widget/text_input.rs
new file mode 100644
index 00000000..260fe3a6
--- /dev/null
+++ b/wgpu/src/widget/text_input.rs
@@ -0,0 +1,15 @@
+//! Display fields that can be filled with text.
+//!
+//! A [`TextInput`] has some local [`State`].
+//!
+//! [`TextInput`]: struct.TextInput.html
+//! [`State`]: struct.State.html
+use crate::Renderer;
+
+pub use iced_native::text_input::State;
+pub use iced_style::text_input::{Style, StyleSheet};
+
+/// A field that can be filled with text.
+///
+/// This is an alias of an `iced_native` text input with an `iced_wgpu::Renderer`.
+pub type TextInput<'a, Message> = iced_native::TextInput<'a, Message, Renderer>;