summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-06-11 20:41:11 +0200
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-07-08 11:19:56 +0200
commit61f22b1db23f3495145a9a4f7255311fe8381998 (patch)
tree925db905f29c3df13cf6e7480672d2a294ce10c7
parent0ff5a02550e5d5de8fb5fd0643ea424d9e508888 (diff)
downloadiced-61f22b1db23f3495145a9a4f7255311fe8381998.tar.gz
iced-61f22b1db23f3495145a9a4f7255311fe8381998.tar.bz2
iced-61f22b1db23f3495145a9a4f7255311fe8381998.zip
Add styling support for `ComboBox` and `Menu`
-rw-r--r--glow/src/widget/combo_box.rs7
-rw-r--r--graphics/src/lib.rs4
-rw-r--r--graphics/src/overlay.rs2
-rw-r--r--graphics/src/overlay/menu.rs24
-rw-r--r--graphics/src/widget/combo_box.rs42
-rw-r--r--native/src/overlay/menu.rs31
-rw-r--r--native/src/widget/combo_box.rs33
-rw-r--r--style/src/combo_box.rs70
-rw-r--r--style/src/lib.rs2
-rw-r--r--style/src/menu.rs25
-rw-r--r--wgpu/src/widget/combo_box.rs7
11 files changed, 206 insertions, 41 deletions
diff --git a/glow/src/widget/combo_box.rs b/glow/src/widget/combo_box.rs
index bb3931ef..bfface29 100644
--- a/glow/src/widget/combo_box.rs
+++ b/glow/src/widget/combo_box.rs
@@ -1,3 +1,8 @@
pub use iced_native::combo_box::State;
-pub type ComboBox<'a, T, Message> = iced_native::ComboBox<'a, T, Message>;
+pub use iced_graphics::combo_box::{Style, StyleSheet};
+pub use iced_graphics::overlay::menu::Style as Menu;
+
+/// A widget allowing the selection of a single value from a list of options.
+pub type ComboBox<'a, T, Message> =
+ iced_native::ComboBox<'a, T, Message, crate::Renderer>;
diff --git a/graphics/src/lib.rs b/graphics/src/lib.rs
index 92e8432e..0c427634 100644
--- a/graphics/src/lib.rs
+++ b/graphics/src/lib.rs
@@ -9,18 +9,18 @@
#![forbid(rust_2018_idioms)]
#![cfg_attr(docsrs, feature(doc_cfg))]
mod antialiasing;
-mod overlay;
mod primitive;
mod renderer;
mod transformation;
mod viewport;
-mod widget;
pub mod backend;
pub mod defaults;
pub mod font;
pub mod layer;
+pub mod overlay;
pub mod triangle;
+pub mod widget;
pub mod window;
#[doc(no_inline)]
diff --git a/graphics/src/overlay.rs b/graphics/src/overlay.rs
index c57668d4..b9a0e3e0 100644
--- a/graphics/src/overlay.rs
+++ b/graphics/src/overlay.rs
@@ -1 +1 @@
-mod menu;
+pub mod menu;
diff --git a/graphics/src/overlay/menu.rs b/graphics/src/overlay/menu.rs
index f4204f25..13065645 100644
--- a/graphics/src/overlay/menu.rs
+++ b/graphics/src/overlay/menu.rs
@@ -1,18 +1,23 @@
use crate::backend::Backend;
use crate::{Primitive, Renderer};
use iced_native::{
- mouse, overlay, Background, Color, Font, HorizontalAlignment, Point,
- Rectangle, VerticalAlignment,
+ mouse, overlay, Color, Font, HorizontalAlignment, Point, Rectangle,
+ VerticalAlignment,
};
+pub use iced_style::menu::Style;
+
impl<B> overlay::menu::Renderer for Renderer<B>
where
B: Backend,
{
+ type Style = Style;
+
fn decorate(
&mut self,
bounds: Rectangle,
_cursor_position: Point,
+ style: &Style,
(primitives, mouse_cursor): Self::Output,
) -> Self::Output {
(
@@ -20,11 +25,9 @@ where
primitives: vec![
Primitive::Quad {
bounds,
- background: Background::Color(
- [0.87, 0.87, 0.87].into(),
- ),
- border_color: [0.7, 0.7, 0.7].into(),
- border_width: 1,
+ background: style.background,
+ border_color: style.border_color,
+ border_width: style.border_width,
border_radius: 0,
},
primitives,
@@ -42,6 +45,7 @@ where
hovered_option: Option<usize>,
text_size: u16,
padding: u16,
+ style: &Style,
) -> Self::Output {
use std::f32;
@@ -63,7 +67,7 @@ where
if is_selected {
primitives.push(Primitive::Quad {
bounds,
- background: Background::Color([0.4, 0.4, 1.0].into()),
+ background: style.selected_background,
border_color: Color::TRANSPARENT,
border_width: 0,
border_radius: 0,
@@ -81,9 +85,9 @@ where
size: f32::from(text_size),
font: Font::Default,
color: if is_selected {
- Color::WHITE
+ style.selected_text_color
} else {
- Color::BLACK
+ style.text_color
},
horizontal_alignment: HorizontalAlignment::Left,
vertical_alignment: VerticalAlignment::Center,
diff --git a/graphics/src/widget/combo_box.rs b/graphics/src/widget/combo_box.rs
index 92024c6c..078b5def 100644
--- a/graphics/src/widget/combo_box.rs
+++ b/graphics/src/widget/combo_box.rs
@@ -1,18 +1,29 @@
use crate::backend::{self, Backend};
use crate::{Primitive, Renderer};
use iced_native::{
- mouse, Background, Color, Font, HorizontalAlignment, Point, Rectangle,
- VerticalAlignment,
+ mouse, Font, HorizontalAlignment, Point, Rectangle, VerticalAlignment,
};
+use iced_style::menu;
-pub use iced_native::ComboBox;
+pub use iced_native::combo_box::State;
+pub use iced_style::combo_box::{Style, StyleSheet};
+
+/// A widget allowing the selection of a single value from a list of options.
+pub type ComboBox<'a, T, Message, Backend> =
+ iced_native::ComboBox<'a, T, Message, Renderer<Backend>>;
impl<B> iced_native::combo_box::Renderer for Renderer<B>
where
B: Backend + backend::Text,
{
+ type Style = Box<dyn StyleSheet>;
+
const DEFAULT_PADDING: u16 = 5;
+ fn menu_style(style: &Box<dyn StyleSheet>) -> menu::Style {
+ style.menu()
+ }
+
fn draw(
&mut self,
bounds: Rectangle,
@@ -20,31 +31,34 @@ where
selected: Option<String>,
text_size: u16,
padding: u16,
+ style: &Box<dyn StyleSheet>,
) -> Self::Output {
let is_mouse_over = bounds.contains(cursor_position);
+ let style = if is_mouse_over {
+ style.hovered()
+ } else {
+ style.active()
+ };
+
let background = Primitive::Quad {
bounds,
- background: Background::Color([0.87, 0.87, 0.87].into()),
- border_color: if is_mouse_over {
- Color::BLACK
- } else {
- [0.7, 0.7, 0.7].into()
- },
- border_width: 1,
- border_radius: 0,
+ background: style.background,
+ border_color: style.border_color,
+ border_width: style.border_width,
+ border_radius: style.border_radius,
};
let arrow_down = Primitive::Text {
content: B::ARROW_DOWN_ICON.to_string(),
font: B::ICON_FONT,
- size: bounds.height * 0.7,
+ size: bounds.height * style.icon_size,
bounds: Rectangle {
x: bounds.x + bounds.width - f32::from(padding) * 2.0,
y: bounds.center_y(),
..bounds
},
- color: Color::BLACK,
+ color: style.text_color,
horizontal_alignment: HorizontalAlignment::Right,
vertical_alignment: VerticalAlignment::Center,
};
@@ -56,7 +70,7 @@ where
content: label,
size: f32::from(text_size),
font: Font::Default,
- color: Color::BLACK,
+ color: style.text_color,
bounds: Rectangle {
x: bounds.x + f32::from(padding),
y: bounds.center_y(),
diff --git a/native/src/overlay/menu.rs b/native/src/overlay/menu.rs
index 05c41181..9c180671 100644
--- a/native/src/overlay/menu.rs
+++ b/native/src/overlay/menu.rs
@@ -10,6 +10,7 @@ pub struct Menu<'a, Message, Renderer: self::Renderer> {
is_open: &'a mut bool,
width: u16,
target_height: f32,
+ style: <Renderer as self::Renderer>::Style,
}
#[derive(Default)]
@@ -43,6 +44,7 @@ where
target_height: f32,
text_size: u16,
padding: u16,
+ style: <Renderer as self::Renderer>::Style,
) -> Self
where
T: Clone + ToString,
@@ -55,6 +57,7 @@ where
on_selected,
text_size,
padding,
+ style.clone(),
)),
)
.padding(1);
@@ -64,6 +67,7 @@ where
is_open: &mut state.is_open,
width,
target_height,
+ style,
}
}
}
@@ -156,11 +160,16 @@ where
self.container
.draw(renderer, defaults, layout, cursor_position);
- renderer.decorate(layout.bounds(), cursor_position, primitives)
+ renderer.decorate(
+ layout.bounds(),
+ cursor_position,
+ &self.style,
+ primitives,
+ )
}
}
-struct List<'a, T, Message>
+struct List<'a, T, Message, Renderer: self::Renderer>
where
[T]: ToOwned,
{
@@ -169,9 +178,10 @@ where
on_selected: Box<dyn Fn(T) -> Message>,
text_size: u16,
padding: u16,
+ style: <Renderer as self::Renderer>::Style,
}
-impl<'a, T, Message> List<'a, T, Message>
+impl<'a, T, Message, Renderer: self::Renderer> List<'a, T, Message, Renderer>
where
[T]: ToOwned,
{
@@ -181,6 +191,7 @@ where
on_selected: Box<dyn Fn(T) -> Message>,
text_size: u16,
padding: u16,
+ style: <Renderer as self::Renderer>::Style,
) -> Self {
List {
hovered_option,
@@ -188,12 +199,13 @@ where
on_selected,
text_size,
padding,
+ style,
}
}
}
-impl<'a, T, Message, Renderer> Widget<'a, Message, Renderer>
- for List<'a, T, Message>
+impl<'a, T, Message, Renderer: self::Renderer> Widget<'a, Message, Renderer>
+ for List<'a, T, Message, Renderer>
where
T: ToString + Clone,
[T]: ToOwned,
@@ -286,15 +298,19 @@ where
*self.hovered_option,
self.text_size,
self.padding,
+ &self.style,
)
}
}
pub trait Renderer: scrollable::Renderer + container::Renderer {
+ type Style: Default + Clone;
+
fn decorate(
&mut self,
bounds: Rectangle,
cursor_position: Point,
+ style: &<Self as Renderer>::Style,
primitive: Self::Output,
) -> Self::Output;
@@ -306,16 +322,17 @@ pub trait Renderer: scrollable::Renderer + container::Renderer {
hovered_option: Option<usize>,
text_size: u16,
padding: u16,
+ style: &<Self as Renderer>::Style,
) -> Self::Output;
}
impl<'a, T, Message, Renderer> Into<Element<'a, Message, Renderer>>
- for List<'a, T, Message>
+ for List<'a, T, Message, Renderer>
where
T: ToString + Clone,
[T]: ToOwned,
Message: 'static,
- Renderer: self::Renderer,
+ Renderer: 'a + self::Renderer,
{
fn into(self) -> Element<'a, Message, Renderer> {
Element::new(self)
diff --git a/native/src/widget/combo_box.rs b/native/src/widget/combo_box.rs
index 2adee884..df2a530a 100644
--- a/native/src/widget/combo_box.rs
+++ b/native/src/widget/combo_box.rs
@@ -6,7 +6,7 @@ use crate::{
};
use std::borrow::Cow;
-pub struct ComboBox<'a, T, Message>
+pub struct ComboBox<'a, T, Message, Renderer: self::Renderer>
where
[T]: ToOwned<Owned = Vec<T>>,
{
@@ -16,6 +16,7 @@ where
width: Length,
padding: u16,
text_size: Option<u16>,
+ style: <Renderer as self::Renderer>::Style,
}
#[derive(Default)]
@@ -28,7 +29,8 @@ pub struct Internal<'a, T, Message> {
on_selected: Box<dyn Fn(T) -> Message>,
}
-impl<'a, T: 'a, Message> ComboBox<'a, T, Message>
+impl<'a, T: 'a, Message, Renderer: self::Renderer>
+ ComboBox<'a, T, Message, Renderer>
where
T: ToString,
[T]: ToOwned<Owned = Vec<T>>,
@@ -48,7 +50,8 @@ where
selected,
width: Length::Shrink,
text_size: None,
- padding: 5,
+ padding: Renderer::DEFAULT_PADDING,
+ style: <Renderer as self::Renderer>::Style::default(),
}
}
@@ -72,10 +75,21 @@ where
self.text_size = Some(size);
self
}
+
+ /// Sets the style of the [`ComboBox`].
+ ///
+ /// [`ComboBox`]: struct.ComboBox.html
+ pub fn style(
+ mut self,
+ style: impl Into<<Renderer as self::Renderer>::Style>,
+ ) -> Self {
+ self.style = style.into();
+ self
+ }
}
impl<'a, T: 'a, Message, Renderer> Widget<'a, Message, Renderer>
- for ComboBox<'a, T, Message>
+ for ComboBox<'a, T, Message, Renderer>
where
T: Clone + ToString + Eq,
[T]: ToOwned<Owned = Vec<T>>,
@@ -196,6 +210,7 @@ where
self.selected.as_ref().map(ToString::to_string),
self.text_size.unwrap_or(renderer.default_size()),
self.padding,
+ &self.style,
)
}
@@ -223,6 +238,7 @@ where
bounds.height,
self.text_size.unwrap_or(20),
self.padding,
+ Renderer::menu_style(&self.style),
)),
))
} else {
@@ -235,8 +251,14 @@ where
}
pub trait Renderer: text::Renderer + menu::Renderer {
+ type Style: Default;
+
const DEFAULT_PADDING: u16;
+ fn menu_style(
+ style: &<Self as Renderer>::Style,
+ ) -> <Self as menu::Renderer>::Style;
+
fn draw(
&mut self,
bounds: Rectangle,
@@ -244,11 +266,12 @@ pub trait Renderer: text::Renderer + menu::Renderer {
selected: Option<String>,
text_size: u16,
padding: u16,
+ style: &<Self as Renderer>::Style,
) -> Self::Output;
}
impl<'a, T: 'a, Message, Renderer> Into<Element<'a, Message, Renderer>>
- for ComboBox<'a, T, Message>
+ for ComboBox<'a, T, Message, Renderer>
where
T: Clone + ToString + Eq,
[T]: ToOwned<Owned = Vec<T>>,
diff --git a/style/src/combo_box.rs b/style/src/combo_box.rs
new file mode 100644
index 00000000..4d0c4e46
--- /dev/null
+++ b/style/src/combo_box.rs
@@ -0,0 +1,70 @@
+use crate::menu;
+use iced_core::{Background, Color};
+
+/// The appearance of a combo box.
+#[derive(Debug, Clone, Copy)]
+pub struct Style {
+ pub text_color: Color,
+ pub background: Background,
+ pub border_radius: u16,
+ pub border_width: u16,
+ pub border_color: Color,
+ pub icon_size: f32,
+}
+
+impl std::default::Default for Style {
+ fn default() -> Self {
+ Self {
+ text_color: Color::BLACK,
+ background: Background::Color([0.87, 0.87, 0.87].into()),
+ border_radius: 0,
+ border_width: 1,
+ border_color: [0.7, 0.7, 0.7].into(),
+ icon_size: 0.7,
+ }
+ }
+}
+
+/// A set of rules that dictate the style of a container.
+pub trait StyleSheet {
+ fn menu(&self) -> menu::Style;
+
+ fn active(&self) -> Style;
+
+ /// Produces the style of a container.
+ fn hovered(&self) -> Style;
+}
+
+struct Default;
+
+impl StyleSheet for Default {
+ fn menu(&self) -> menu::Style {
+ menu::Style::default()
+ }
+
+ fn active(&self) -> Style {
+ Style::default()
+ }
+
+ fn hovered(&self) -> Style {
+ Style {
+ border_color: Color::BLACK,
+ ..self.active()
+ }
+ }
+}
+
+impl std::default::Default for Box<dyn StyleSheet> {
+ fn default() -> Self {
+ Box::new(Default)
+ }
+}
+
+impl<T> From<T> for Box<dyn StyleSheet>
+where
+ T: 'static + StyleSheet,
+{
+ fn from(style: T) -> Self {
+ Box::new(style)
+ }
+}
diff --git a/style/src/lib.rs b/style/src/lib.rs
index 72d83aec..b19d6600 100644
--- a/style/src/lib.rs
+++ b/style/src/lib.rs
@@ -6,7 +6,9 @@ pub use iced_core::{Background, Color};
pub mod button;
pub mod checkbox;
+pub mod combo_box;
pub mod container;
+pub mod menu;
pub mod progress_bar;
pub mod radio;
pub mod scrollable;
diff --git a/style/src/menu.rs b/style/src/menu.rs
new file mode 100644
index 00000000..e8321dc7
--- /dev/null
+++ b/style/src/menu.rs
@@ -0,0 +1,25 @@
+use iced_core::{Background, Color};
+
+/// The appearance of a menu.
+#[derive(Debug, Clone, Copy)]
+pub struct Style {
+ pub text_color: Color,
+ pub background: Background,
+ pub border_width: u16,
+ pub border_color: Color,
+ pub selected_text_color: Color,
+ pub selected_background: Background,
+}
+
+impl std::default::Default for Style {
+ fn default() -> Self {
+ Self {
+ text_color: Color::BLACK,
+ background: Background::Color([0.87, 0.87, 0.87].into()),
+ border_width: 1,
+ border_color: [0.7, 0.7, 0.7].into(),
+ selected_text_color: Color::WHITE,
+ selected_background: Background::Color([0.4, 0.4, 1.0].into()),
+ }
+ }
+}
diff --git a/wgpu/src/widget/combo_box.rs b/wgpu/src/widget/combo_box.rs
index bb3931ef..bfface29 100644
--- a/wgpu/src/widget/combo_box.rs
+++ b/wgpu/src/widget/combo_box.rs
@@ -1,3 +1,8 @@
pub use iced_native::combo_box::State;
-pub type ComboBox<'a, T, Message> = iced_native::ComboBox<'a, T, Message>;
+pub use iced_graphics::combo_box::{Style, StyleSheet};
+pub use iced_graphics::overlay::menu::Style as Menu;
+
+/// A widget allowing the selection of a single value from a list of options.
+pub type ComboBox<'a, T, Message> =
+ iced_native::ComboBox<'a, T, Message, crate::Renderer>;