summaryrefslogtreecommitdiffstats
path: root/wgpu/src/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'wgpu/src/renderer')
-rw-r--r--wgpu/src/renderer/target.rs90
-rw-r--r--wgpu/src/renderer/widget.rs10
-rw-r--r--wgpu/src/renderer/widget/button.rs104
-rw-r--r--wgpu/src/renderer/widget/checkbox.rs58
-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/image.rs12
-rw-r--r--wgpu/src/renderer/widget/progress_bar.rs54
-rw-r--r--wgpu/src/renderer/widget/radio.rs52
-rw-r--r--wgpu/src/renderer/widget/row.rs3
-rw-r--r--wgpu/src/renderer/widget/scrollable.rs132
-rw-r--r--wgpu/src/renderer/widget/slider.rs81
-rw-r--r--wgpu/src/renderer/widget/space.rs8
-rw-r--r--wgpu/src/renderer/widget/svg.rs22
-rw-r--r--wgpu/src/renderer/widget/text.rs10
-rw-r--r--wgpu/src/renderer/widget/text_input.rs139
16 files changed, 488 insertions, 339 deletions
diff --git a/wgpu/src/renderer/target.rs b/wgpu/src/renderer/target.rs
deleted file mode 100644
index 569f3c62..00000000
--- a/wgpu/src/renderer/target.rs
+++ /dev/null
@@ -1,90 +0,0 @@
-use crate::{Renderer, Transformation};
-
-use raw_window_handle::HasRawWindowHandle;
-
-/// A rendering target.
-#[derive(Debug)]
-pub struct Target {
- surface: wgpu::Surface,
- width: u16,
- height: u16,
- dpi: f32,
- transformation: Transformation,
- swap_chain: wgpu::SwapChain,
-}
-
-impl Target {
- pub(crate) fn dimensions(&self) -> (u16, u16) {
- (self.width, self.height)
- }
-
- pub(crate) fn dpi(&self) -> f32 {
- self.dpi
- }
-
- pub(crate) fn transformation(&self) -> Transformation {
- self.transformation
- }
-
- pub(crate) fn next_frame(&mut self) -> wgpu::SwapChainOutput<'_> {
- self.swap_chain.get_next_texture()
- }
-}
-
-impl iced_native::renderer::Target for Target {
- type Renderer = Renderer;
-
- fn new<W: HasRawWindowHandle>(
- window: &W,
- width: u16,
- height: u16,
- dpi: f32,
- renderer: &Renderer,
- ) -> Target {
- let surface = wgpu::Surface::create(window);
- let swap_chain =
- new_swap_chain(&surface, width, height, &renderer.device);
-
- Target {
- surface,
- width,
- height,
- dpi,
- transformation: Transformation::orthographic(width, height),
- swap_chain,
- }
- }
-
- fn resize(
- &mut self,
- width: u16,
- height: u16,
- dpi: f32,
- renderer: &Renderer,
- ) {
- self.width = width;
- self.height = height;
- self.dpi = dpi;
- self.transformation = Transformation::orthographic(width, height);
- self.swap_chain =
- new_swap_chain(&self.surface, width, height, &renderer.device);
- }
-}
-
-fn new_swap_chain(
- surface: &wgpu::Surface,
- width: u16,
- height: u16,
- device: &wgpu::Device,
-) -> wgpu::SwapChain {
- device.create_swap_chain(
- &surface,
- &wgpu::SwapChainDescriptor {
- usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
- format: wgpu::TextureFormat::Bgra8UnormSrgb,
- width: u32::from(width),
- height: u32::from(height),
- present_mode: wgpu::PresentMode::Vsync,
- },
- )
-}
diff --git a/wgpu/src/renderer/widget.rs b/wgpu/src/renderer/widget.rs
index 52410bee..84f908e7 100644
--- a/wgpu/src/renderer/widget.rs
+++ b/wgpu/src/renderer/widget.rs
@@ -1,10 +1,18 @@
mod button;
mod checkbox;
mod column;
-mod image;
+mod container;
+mod progress_bar;
mod radio;
mod row;
mod scrollable;
mod slider;
+mod space;
mod text;
mod text_input;
+
+#[cfg(feature = "svg")]
+mod svg;
+
+#[cfg(feature = "image")]
+mod image;
diff --git a/wgpu/src/renderer/widget/button.rs b/wgpu/src/renderer/widget/button.rs
index 86963053..0de5bf5c 100644
--- a/wgpu/src/renderer/widget/button.rs
+++ b/wgpu/src/renderer/widget/button.rs
@@ -1,54 +1,88 @@
-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 {
+ const DEFAULT_PADDING: u16 = 5;
+
+ 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..1a0585d3 100644
--- a/wgpu/src/renderer/widget/checkbox.rs
+++ b/wgpu/src/renderer/widget/checkbox.rs
@@ -1,15 +1,13 @@
-use crate::{Primitive, Renderer};
+use crate::{checkbox::StyleSheet, Primitive, Renderer};
use iced_native::{
- checkbox, Background, HorizontalAlignment, MouseCursor, Rectangle,
- VerticalAlignment,
+ checkbox, HorizontalAlignment, MouseCursor, Rectangle, VerticalAlignment,
};
-const SIZE: f32 = 28.0;
-
impl checkbox::Renderer for Renderer {
- fn default_size(&self) -> u32 {
- SIZE as u32
- }
+ type Style = Box<dyn StyleSheet>;
+
+ const DEFAULT_SIZE: u16 = 20;
+ const DEFAULT_SPACING: u16 = 15;
fn draw(
&mut self,
@@ -17,31 +15,21 @@ impl checkbox::Renderer for Renderer {
is_checked: bool,
is_mouse_over: bool,
(label, _): Self::Output,
+ style_sheet: &Self::Style,
) -> 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 style = if is_mouse_over {
+ style_sheet.hovered(is_checked)
+ } else {
+ style_sheet.active(is_checked)
+ };
+
+ let checkbox = Primitive::Quad {
+ bounds,
+ background: style.background,
+ border_radius: style.border_radius,
+ border_width: style.border_width,
+ border_color: style.border_color,
+ };
(
Primitive::Group {
@@ -51,14 +39,14 @@ impl checkbox::Renderer for Renderer {
font: crate::text::BUILTIN_ICONS,
size: bounds.height * 0.7,
bounds: bounds,
- color: [0.3, 0.3, 0.3].into(),
+ color: style.checkmark_color,
horizontal_alignment: HorizontalAlignment::Center,
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/image.rs b/wgpu/src/renderer/widget/image.rs
index 0006dde1..70dc5d97 100644
--- a/wgpu/src/renderer/widget/image.rs
+++ b/wgpu/src/renderer/widget/image.rs
@@ -2,14 +2,18 @@ use crate::{Primitive, Renderer};
use iced_native::{image, Layout, MouseCursor};
impl image::Renderer for Renderer {
- fn dimensions(&self, path: &str) -> (u32, u32) {
- self.image_pipeline.dimensions(path)
+ fn dimensions(&self, handle: &image::Handle) -> (u32, u32) {
+ self.image_pipeline.dimensions(handle)
}
- fn draw(&mut self, path: &str, layout: Layout<'_>) -> Self::Output {
+ fn draw(
+ &mut self,
+ handle: image::Handle,
+ layout: Layout<'_>,
+ ) -> Self::Output {
(
Primitive::Image {
- path: String::from(path),
+ handle,
bounds: layout.bounds(),
},
MouseCursor::OutOfBounds,
diff --git a/wgpu/src/renderer/widget/progress_bar.rs b/wgpu/src/renderer/widget/progress_bar.rs
new file mode 100644
index 00000000..34e33276
--- /dev/null
+++ b/wgpu/src/renderer/widget/progress_bar.rs
@@ -0,0 +1,54 @@
+use crate::{progress_bar::StyleSheet, Primitive, Renderer};
+use iced_native::{progress_bar, Color, MouseCursor, Rectangle};
+
+impl progress_bar::Renderer for Renderer {
+ type Style = Box<dyn StyleSheet>;
+
+ const DEFAULT_HEIGHT: u16 = 30;
+
+ fn draw(
+ &self,
+ bounds: Rectangle,
+ range: std::ops::RangeInclusive<f32>,
+ value: f32,
+ style_sheet: &Self::Style,
+ ) -> Self::Output {
+ let style = style_sheet.style();
+
+ let (range_start, range_end) = range.into_inner();
+ let active_progress_width = bounds.width
+ * ((value - range_start) / (range_end - range_start).max(1.0));
+
+ let background = Primitive::Group {
+ primitives: vec![Primitive::Quad {
+ bounds: Rectangle { ..bounds },
+ background: style.background,
+ border_radius: style.border_radius,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
+ }],
+ };
+
+ (
+ if active_progress_width > 0.0 {
+ let bar = Primitive::Quad {
+ bounds: Rectangle {
+ width: active_progress_width,
+ ..bounds
+ },
+ background: style.bar,
+ border_radius: style.border_radius,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
+ };
+
+ Primitive::Group {
+ primitives: vec![background, bar],
+ }
+ } else {
+ background
+ },
+ MouseCursor::OutOfBounds,
+ )
+ }
+}
diff --git a/wgpu/src/renderer/widget/radio.rs b/wgpu/src/renderer/widget/radio.rs
index 3c00a4c2..564f066b 100644
--- a/wgpu/src/renderer/widget/radio.rs
+++ b/wgpu/src/renderer/widget/radio.rs
@@ -1,10 +1,12 @@
-use crate::{Primitive, Renderer};
-use iced_native::{radio, Background, MouseCursor, Rectangle};
+use crate::{radio::StyleSheet, Primitive, Renderer};
+use iced_native::{radio, Background, Color, MouseCursor, Rectangle};
const SIZE: f32 = 28.0;
const DOT_SIZE: f32 = SIZE / 2.0;
impl radio::Renderer for Renderer {
+ type Style = Box<dyn StyleSheet>;
+
fn default_size(&self) -> u32 {
SIZE as u32
}
@@ -15,31 +17,21 @@ impl radio::Renderer for Renderer {
is_selected: bool,
is_mouse_over: bool,
(label, _): Self::Output,
+ style_sheet: &Self::Style,
) -> 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 style = if is_mouse_over {
+ style_sheet.hovered()
+ } else {
+ style_sheet.active()
+ };
+
+ let radio = Primitive::Quad {
+ bounds,
+ background: style.background,
+ border_radius: (SIZE / 2.0) as u16,
+ border_width: style.border_width,
+ border_color: style.border_color,
+ };
(
Primitive::Group {
@@ -51,13 +43,15 @@ impl radio::Renderer for Renderer {
width: bounds.width - DOT_SIZE,
height: bounds.height - DOT_SIZE,
},
- background: Background::Color([0.3, 0.3, 0.3].into()),
+ background: Background::Color(style.dot_color),
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 58dc3df9..bfee7411 100644
--- a/wgpu/src/renderer/widget/scrollable.rs
+++ b/wgpu/src/renderer/widget/scrollable.rs
@@ -1,45 +1,63 @@
use crate::{Primitive, Renderer};
use iced_native::{
- scrollable, Background, MouseCursor, Point, Rectangle, Vector,
+ scrollable, Background, Color, MouseCursor, Rectangle, Vector,
};
const SCROLLBAR_WIDTH: u16 = 10;
const SCROLLBAR_MARGIN: u16 = 2;
-fn scrollbar_bounds(bounds: Rectangle) -> Rectangle {
- Rectangle {
- x: bounds.x + bounds.width
- - f32::from(SCROLLBAR_WIDTH + 2 * SCROLLBAR_MARGIN),
- y: bounds.y,
- width: f32::from(SCROLLBAR_WIDTH + 2 * SCROLLBAR_MARGIN),
- height: bounds.height,
- }
-}
-
impl scrollable::Renderer for Renderer {
- fn is_mouse_over_scrollbar(
+ type Style = Box<dyn iced_style::scrollable::StyleSheet>;
+
+ fn scrollbar(
&self,
bounds: Rectangle,
content_bounds: Rectangle,
- cursor_position: Point,
- ) -> bool {
- content_bounds.height > bounds.height
- && scrollbar_bounds(bounds).contains(cursor_position)
+ offset: u32,
+ ) -> Option<scrollable::Scrollbar> {
+ if content_bounds.height > bounds.height {
+ let scrollbar_bounds = Rectangle {
+ x: bounds.x + bounds.width
+ - f32::from(SCROLLBAR_WIDTH + 2 * SCROLLBAR_MARGIN),
+ y: bounds.y,
+ width: f32::from(SCROLLBAR_WIDTH + 2 * SCROLLBAR_MARGIN),
+ height: bounds.height,
+ };
+
+ let ratio = bounds.height / content_bounds.height;
+ let scrollbar_height = bounds.height * ratio;
+ let y_offset = offset as f32 * ratio;
+
+ let scroller_bounds = Rectangle {
+ x: scrollbar_bounds.x + f32::from(SCROLLBAR_MARGIN),
+ y: scrollbar_bounds.y + y_offset,
+ width: scrollbar_bounds.width - f32::from(2 * SCROLLBAR_MARGIN),
+ height: scrollbar_height,
+ };
+
+ Some(scrollable::Scrollbar {
+ bounds: scrollbar_bounds,
+ scroller: scrollable::Scroller {
+ bounds: scroller_bounds,
+ },
+ })
+ } else {
+ None
+ }
}
fn draw(
&mut self,
state: &scrollable::State,
bounds: Rectangle,
- content_bounds: Rectangle,
+ _content_bounds: Rectangle,
is_mouse_over: bool,
is_mouse_over_scrollbar: bool,
+ scrollbar: Option<scrollable::Scrollbar>,
offset: u32,
+ style_sheet: &Self::Style,
(content, mouse_cursor): Self::Output,
) -> Self::Output {
- let is_content_overflowing = content_bounds.height > bounds.height;
- let scrollbar_bounds = scrollbar_bounds(bounds);
-
let clip = Primitive::Clip {
bounds,
offset: Vector::new(0, offset),
@@ -47,51 +65,59 @@ impl scrollable::Renderer for Renderer {
};
(
- if is_content_overflowing
- && (is_mouse_over || state.is_scrollbar_grabbed())
- {
- let ratio = bounds.height / content_bounds.height;
- let scrollbar_height = bounds.height * ratio;
- let y_offset = offset as f32 * ratio;
+ if let Some(scrollbar) = scrollbar {
+ let style = if state.is_scroller_grabbed() {
+ style_sheet.dragging()
+ } else if is_mouse_over_scrollbar {
+ style_sheet.hovered()
+ } else {
+ style_sheet.active()
+ };
+
+ let is_scrollbar_visible =
+ style.background.is_some() || style.border_width > 0;
- let scrollbar = Primitive::Quad {
- bounds: Rectangle {
- x: scrollbar_bounds.x + f32::from(SCROLLBAR_MARGIN),
- y: scrollbar_bounds.y + y_offset,
- width: scrollbar_bounds.width
- - f32::from(2 * SCROLLBAR_MARGIN),
- height: scrollbar_height,
- },
- background: Background::Color([0.0, 0.0, 0.0, 0.7].into()),
- border_radius: 5,
+ let scroller = if is_mouse_over
+ || state.is_scroller_grabbed()
+ || is_scrollbar_visible
+ {
+ Primitive::Quad {
+ bounds: scrollbar.scroller.bounds,
+ background: Background::Color(style.scroller.color),
+ border_radius: style.scroller.border_radius,
+ border_width: style.scroller.border_width,
+ border_color: style.scroller.border_color,
+ }
+ } else {
+ Primitive::None
};
- if is_mouse_over_scrollbar || state.is_scrollbar_grabbed() {
- let scrollbar_background = Primitive::Quad {
+ let scrollbar = if is_scrollbar_visible {
+ Primitive::Quad {
bounds: Rectangle {
- x: scrollbar_bounds.x + f32::from(SCROLLBAR_MARGIN),
- width: scrollbar_bounds.width
+ x: scrollbar.bounds.x + f32::from(SCROLLBAR_MARGIN),
+ width: scrollbar.bounds.width
- f32::from(2 * SCROLLBAR_MARGIN),
- ..scrollbar_bounds
+ ..scrollbar.bounds
},
- background: Background::Color(
- [0.0, 0.0, 0.0, 0.3].into(),
- ),
- border_radius: 5,
- };
-
- Primitive::Group {
- primitives: vec![clip, scrollbar_background, scrollbar],
+ background: style
+ .background
+ .unwrap_or(Background::Color(Color::TRANSPARENT)),
+ border_radius: style.border_radius,
+ border_width: style.border_width,
+ border_color: style.border_color,
}
} else {
- Primitive::Group {
- primitives: vec![clip, scrollbar],
- }
+ Primitive::None
+ };
+
+ Primitive::Group {
+ primitives: vec![clip, scrollbar, scroller],
}
} else {
clip
},
- if is_mouse_over_scrollbar || state.is_scrollbar_grabbed() {
+ if is_mouse_over_scrollbar || state.is_scroller_grabbed() {
MouseCursor::Idle
} else {
mouse_cursor
diff --git a/wgpu/src/renderer/widget/slider.rs b/wgpu/src/renderer/widget/slider.rs
index f561be0a..c8ebd0da 100644
--- a/wgpu/src/renderer/widget/slider.rs
+++ b/wgpu/src/renderer/widget/slider.rs
@@ -1,10 +1,14 @@
-use crate::{Primitive, Renderer};
+use crate::{
+ slider::{HandleShape, StyleSheet},
+ Primitive, Renderer,
+};
use iced_native::{slider, Background, Color, MouseCursor, Point, Rectangle};
-const HANDLE_WIDTH: f32 = 8.0;
const HANDLE_HEIGHT: f32 = 22.0;
impl slider::Renderer for Renderer {
+ type Style = Box<dyn StyleSheet>;
+
fn height(&self) -> u32 {
30
}
@@ -16,9 +20,18 @@ impl slider::Renderer for Renderer {
range: std::ops::RangeInclusive<f32>,
value: f32,
is_dragging: bool,
+ style_sheet: &Self::Style,
) -> Self::Output {
let is_mouse_over = bounds.contains(cursor_position);
+ let style = if is_dragging {
+ style_sheet.dragging()
+ } else if is_mouse_over {
+ style_sheet.hovered()
+ } else {
+ style_sheet.active()
+ };
+
let rail_y = bounds.y + (bounds.height / 2.0).round();
let (rail_top, rail_bottom) = (
@@ -29,8 +42,10 @@ impl slider::Renderer for Renderer {
width: bounds.width,
height: 2.0,
},
- background: Background::Color([0.6, 0.6, 0.6].into()),
+ background: Background::Color(style.rail_colors.0),
border_radius: 0,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
},
Primitive::Quad {
bounds: Rectangle {
@@ -39,51 +54,45 @@ impl slider::Renderer for Renderer {
width: bounds.width,
height: 2.0,
},
- background: Background::Color(Color::WHITE),
+ background: Background::Color(style.rail_colors.1),
border_radius: 0,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
},
);
let (range_start, range_end) = range.into_inner();
- let handle_offset = (bounds.width - HANDLE_WIDTH)
+ let (handle_width, handle_height, handle_border_radius) =
+ match style.handle.shape {
+ HandleShape::Circle { radius } => {
+ (f32::from(radius * 2), f32::from(radius * 2), radius)
+ }
+ HandleShape::Rectangle {
+ width,
+ border_radius,
+ } => (f32::from(width), HANDLE_HEIGHT, border_radius),
+ };
+
+ 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: Background::Color([0.6, 0.6, 0.6].into()),
- border_radius: 5,
+ 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,
},
- 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,
- },
- );
+ background: Background::Color(style.handle.color),
+ border_radius: handle_border_radius,
+ border_width: style.handle.border_width,
+ border_color: style.handle.border_color,
+ };
(
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/space.rs b/wgpu/src/renderer/widget/space.rs
new file mode 100644
index 00000000..28e05437
--- /dev/null
+++ b/wgpu/src/renderer/widget/space.rs
@@ -0,0 +1,8 @@
+use crate::{Primitive, Renderer};
+use iced_native::{space, MouseCursor, Rectangle};
+
+impl space::Renderer for Renderer {
+ fn draw(&mut self, _bounds: Rectangle) -> Self::Output {
+ (Primitive::None, MouseCursor::OutOfBounds)
+ }
+}
diff --git a/wgpu/src/renderer/widget/svg.rs b/wgpu/src/renderer/widget/svg.rs
new file mode 100644
index 00000000..67bc3fe1
--- /dev/null
+++ b/wgpu/src/renderer/widget/svg.rs
@@ -0,0 +1,22 @@
+use crate::{Primitive, Renderer};
+use iced_native::{svg, Layout, MouseCursor};
+
+impl svg::Renderer for Renderer {
+ fn dimensions(&self, handle: &svg::Handle) -> (u32, u32) {
+ self.image_pipeline.viewport_dimensions(handle)
+ }
+
+ fn draw(
+ &mut self,
+ handle: svg::Handle,
+ layout: Layout<'_>,
+ ) -> Self::Output {
+ (
+ Primitive::Svg {
+ handle,
+ bounds: layout.bounds(),
+ },
+ MouseCursor::OutOfBounds,
+ )
+ }
+}
diff --git a/wgpu/src/renderer/widget/text.rs b/wgpu/src/renderer/widget/text.rs
index 08a162ba..33e549cd 100644
--- a/wgpu/src/renderer/widget/text.rs
+++ b/wgpu/src/renderer/widget/text.rs
@@ -6,13 +6,8 @@ use iced_native::{
use std::f32;
-// TODO: Obtain from renderer configuration
-const DEFAULT_TEXT_SIZE: f32 = 20.0;
-
impl text::Renderer for Renderer {
- fn default_size(&self) -> u16 {
- DEFAULT_TEXT_SIZE as u16
- }
+ const DEFAULT_SIZE: u16 = 20;
fn measure(
&self,
@@ -27,6 +22,7 @@ impl text::Renderer for Renderer {
fn draw(
&mut self,
+ defaults: &Self::Defaults,
bounds: Rectangle,
content: &str,
size: u16,
@@ -40,7 +36,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 9ed3b415..e2a1b3a9 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,48 +7,85 @@ 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
}
+ fn measure_value(&self, value: &str, size: u16, font: Font) -> f32 {
+ let (mut width, _) = self.text_pipeline.measure(
+ value,
+ f32::from(size),
+ font,
+ Size::INFINITY,
+ );
+
+ let spaces_at_the_end = value.len() - value.trim_end().len();
+
+ if spaces_at_the_end > 0 {
+ let space_width = self.text_pipeline.space_width(size as f32);
+ width += spaces_at_the_end as f32 * space_width;
+ }
+
+ width
+ }
+
+ fn offset(
+ &self,
+ text_bounds: Rectangle,
+ size: u16,
+ value: &text_input::Value,
+ state: &text_input::State,
+ font: Font,
+ ) -> f32 {
+ if state.is_focused() {
+ let (_, offset) = measure_cursor_and_scroll_offset(
+ self,
+ text_bounds,
+ value,
+ size,
+ state.cursor_position(value),
+ font,
+ );
+
+ offset
+ } else {
+ 0.0
+ }
+ }
+
fn draw(
&mut self,
bounds: Rectangle,
text_bounds: Rectangle,
cursor_position: Point,
size: u16,
+ font: Font,
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: 5,
+ bounds,
+ background: style.background,
+ border_radius: style.border_radius,
+ border_width: style.border_width,
+ border_color: style.border_color,
};
- let size = f32::from(size);
let text = value.to_string();
let text_value = Primitive::Text {
@@ -58,40 +95,31 @@ 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,
+ font,
bounds: Rectangle {
width: f32::INFINITY,
..text_bounds
},
- size,
+ size: f32::from(size),
horizontal_alignment: HorizontalAlignment::Left,
vertical_alignment: VerticalAlignment::Center,
};
let (contents_primitive, offset) = if state.is_focused() {
- let text_before_cursor =
- value.until(state.cursor_position(value)).to_string();
-
- let (mut text_value_width, _) = self.text_pipeline.measure(
- &text_before_cursor,
+ let (text_value_width, offset) = measure_cursor_and_scroll_offset(
+ self,
+ text_bounds,
+ value,
size,
- Font::Default,
- Size::new(f32::INFINITY, text_bounds.height),
+ state.cursor_position(value),
+ font,
);
- let spaces_at_the_end =
- text_before_cursor.len() - text_before_cursor.trim_end().len();
-
- if spaces_at_the_end > 0 {
- let space_width = self.text_pipeline.space_width(size);
- text_value_width += spaces_at_the_end as f32 * space_width;
- }
-
let cursor = Primitive::Quad {
bounds: Rectangle {
x: text_bounds.x + text_value_width,
@@ -99,19 +127,17 @@ 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,
};
(
Primitive::Group {
primitives: vec![text_value, cursor],
},
- Vector::new(
- ((text_value_width + 5.0) - text_bounds.width).max(0.0)
- as u32,
- 0,
- ),
+ Vector::new(offset as u32, 0),
)
} else {
(text_value, Vector::new(0, 0))
@@ -125,7 +151,7 @@ impl text_input::Renderer for Renderer {
(
Primitive::Group {
- primitives: vec![border, input, contents],
+ primitives: vec![input, contents],
},
if is_mouse_over {
MouseCursor::Text
@@ -135,3 +161,22 @@ impl text_input::Renderer for Renderer {
)
}
}
+
+fn measure_cursor_and_scroll_offset(
+ renderer: &Renderer,
+ text_bounds: Rectangle,
+ value: &text_input::Value,
+ size: u16,
+ cursor_index: usize,
+ font: Font,
+) -> (f32, f32) {
+ use iced_native::text_input::Renderer;
+
+ let text_before_cursor = value.until(cursor_index).to_string();
+
+ let text_value_width =
+ renderer.measure_value(&text_before_cursor, size, font);
+ let offset = ((text_value_width + 5.0) - text_bounds.width).max(0.0);
+
+ (text_value_width, offset)
+}