Merge pull request #146 from hecrj/feature/custom-styling
Custom styling
This commit is contained in:
commit
0a83024505
@ -24,6 +24,7 @@ maintenance = { status = "actively-developed" }
|
||||
members = [
|
||||
"core",
|
||||
"native",
|
||||
"style",
|
||||
"web",
|
||||
"wgpu",
|
||||
"winit",
|
||||
|
@ -25,6 +25,21 @@ 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 RGB components.
|
||||
///
|
||||
/// [`Color`]: struct.Color.html
|
||||
pub const fn from_rgb(r: f32, g: f32, b: f32) -> Color {
|
||||
Color { r, g, b, a: 1.0 }
|
||||
}
|
||||
|
||||
/// Creates a [`Color`] from its RGB8 components.
|
||||
///
|
||||
/// [`Color`]: struct.Color.html
|
||||
@ -37,13 +52,6 @@ impl Color {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a [`Color`] from its RGB components.
|
||||
///
|
||||
/// [`Color`]: struct.Color.html
|
||||
pub fn from_rgb(r: f32, g: f32, b: f32) -> Color {
|
||||
Color { r, g, b, a: 1.0 }
|
||||
}
|
||||
|
||||
/// Converts the [`Color`] into its linear values.
|
||||
///
|
||||
/// [`Color`]: struct.Color.html
|
||||
|
@ -31,3 +31,15 @@ where
|
||||
Self::new(self.x + b.x, self.y + b.y)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Vector<T>
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
x: T::default(),
|
||||
y: T::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ mod circle {
|
||||
layout, Background, Color, Element, Hasher, Layout, Length,
|
||||
MouseCursor, Point, Size, Widget,
|
||||
};
|
||||
use iced_wgpu::{Primitive, Renderer};
|
||||
use iced_wgpu::{Defaults, Primitive, Renderer};
|
||||
|
||||
pub struct Circle {
|
||||
radius: u16,
|
||||
@ -54,6 +54,7 @@ mod circle {
|
||||
fn draw(
|
||||
&self,
|
||||
_renderer: &mut Renderer,
|
||||
_defaults: &Defaults,
|
||||
layout: Layout<'_>,
|
||||
_cursor_position: Point,
|
||||
) -> (Primitive, MouseCursor) {
|
||||
@ -62,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,
|
||||
)
|
||||
|
@ -16,7 +16,7 @@ mod rainbow {
|
||||
};
|
||||
use iced_wgpu::{
|
||||
triangle::{Mesh2D, Vertex2D},
|
||||
Primitive, Renderer,
|
||||
Defaults, Primitive, Renderer,
|
||||
};
|
||||
|
||||
pub struct Rainbow;
|
||||
@ -51,6 +51,7 @@ mod rainbow {
|
||||
fn draw(
|
||||
&self,
|
||||
_renderer: &mut Renderer,
|
||||
_defaults: &Defaults,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> (Primitive, MouseCursor) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use iced::{
|
||||
button, image, Align, Application, Button, Color, Column, Command,
|
||||
Container, Element, Image, Length, Row, Settings, Text,
|
||||
button, image, Align, Application, Button, Column, Command, Container,
|
||||
Element, Image, Length, Row, Settings, Text,
|
||||
};
|
||||
|
||||
pub fn main() {
|
||||
@ -214,8 +214,29 @@ impl From<surf::Exception> for Error {
|
||||
}
|
||||
|
||||
fn button<'a>(state: &'a mut button::State, text: &str) -> Button<'a, Message> {
|
||||
Button::new(state, Text::new(text).color(Color::WHITE))
|
||||
.background(Color::from_rgb(0.11, 0.42, 0.87))
|
||||
.border_radius(10)
|
||||
Button::new(state, Text::new(text))
|
||||
.padding(10)
|
||||
.style(style::Button::Primary)
|
||||
}
|
||||
|
||||
mod style {
|
||||
use iced::{button, Background, Color, Vector};
|
||||
|
||||
pub enum Button {
|
||||
Primary,
|
||||
}
|
||||
|
||||
impl button::StyleSheet for Button {
|
||||
fn active(&self) -> button::Style {
|
||||
button::Style {
|
||||
background: Some(Background::Color(match self {
|
||||
Button::Primary => Color::from_rgb(0.11, 0.42, 0.87),
|
||||
})),
|
||||
border_radius: 12,
|
||||
shadow_offset: Vector::new(1.0, 1.0),
|
||||
text_color: Color::WHITE,
|
||||
..button::Style::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,7 @@
|
||||
use iced::{
|
||||
settings::Window, slider, Background, Color, Column, Element, Length,
|
||||
ProgressBar, Sandbox, Settings, Slider,
|
||||
};
|
||||
use iced::{slider, Column, Element, ProgressBar, Sandbox, Settings, Slider};
|
||||
|
||||
pub fn main() {
|
||||
Progress::run(Settings {
|
||||
window: Window {
|
||||
size: (700, 300),
|
||||
resizable: true,
|
||||
decorations: true,
|
||||
},
|
||||
})
|
||||
Progress::run(Settings::default())
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@ -44,14 +35,7 @@ impl Sandbox for Progress {
|
||||
fn view(&mut self) -> Element<Message> {
|
||||
Column::new()
|
||||
.padding(20)
|
||||
.push(
|
||||
ProgressBar::new(0.0..=100.0, self.value)
|
||||
.background(Background::Color(Color::from_rgb(
|
||||
0.6, 0.6, 0.6,
|
||||
)))
|
||||
.active_color(Color::from_rgb(0.0, 0.95, 0.0))
|
||||
.height(Length::Units(30)),
|
||||
)
|
||||
.push(ProgressBar::new(0.0..=100.0, self.value))
|
||||
.push(Slider::new(
|
||||
&mut self.progress_bar_slider,
|
||||
0.0..=100.0,
|
||||
|
@ -1,7 +1,6 @@
|
||||
use iced::{
|
||||
button, Align, Application, Background, Button, Color, Column, Command,
|
||||
Container, Element, HorizontalAlignment, Length, Row, Settings,
|
||||
Subscription, Text,
|
||||
button, Align, Application, Button, Column, Command, Container, Element,
|
||||
HorizontalAlignment, Length, Row, Settings, Subscription, Text,
|
||||
};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
@ -98,30 +97,29 @@ impl Application for Stopwatch {
|
||||
))
|
||||
.size(40);
|
||||
|
||||
let button = |state, label, color: [f32; 3]| {
|
||||
let button = |state, label, style| {
|
||||
Button::new(
|
||||
state,
|
||||
Text::new(label)
|
||||
.color(Color::WHITE)
|
||||
.horizontal_alignment(HorizontalAlignment::Center),
|
||||
)
|
||||
.min_width(80)
|
||||
.background(Background::Color(color.into()))
|
||||
.border_radius(10)
|
||||
.padding(10)
|
||||
.style(style)
|
||||
};
|
||||
|
||||
let toggle_button = {
|
||||
let (label, color) = match self.state {
|
||||
State::Idle => ("Start", [0.11, 0.42, 0.87]),
|
||||
State::Ticking { .. } => ("Stop", [0.9, 0.4, 0.4]),
|
||||
State::Idle => ("Start", style::Button::Primary),
|
||||
State::Ticking { .. } => ("Stop", style::Button::Destructive),
|
||||
};
|
||||
|
||||
button(&mut self.toggle, label, color).on_press(Message::Toggle)
|
||||
};
|
||||
|
||||
let reset_button = button(&mut self.reset, "Reset", [0.7, 0.7, 0.7])
|
||||
.on_press(Message::Reset);
|
||||
let reset_button =
|
||||
button(&mut self.reset, "Reset", style::Button::Secondary)
|
||||
.on_press(Message::Reset);
|
||||
|
||||
let controls = Row::new()
|
||||
.spacing(20)
|
||||
@ -177,3 +175,29 @@ mod time {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod style {
|
||||
use iced::{button, Background, Color, Vector};
|
||||
|
||||
pub enum Button {
|
||||
Primary,
|
||||
Secondary,
|
||||
Destructive,
|
||||
}
|
||||
|
||||
impl button::StyleSheet for Button {
|
||||
fn active(&self) -> button::Style {
|
||||
button::Style {
|
||||
background: Some(Background::Color(match self {
|
||||
Button::Primary => Color::from_rgb(0.11, 0.42, 0.87),
|
||||
Button::Secondary => Color::from_rgb(0.5, 0.5, 0.5),
|
||||
Button::Destructive => Color::from_rgb(0.8, 0.2, 0.2),
|
||||
})),
|
||||
border_radius: 12,
|
||||
shadow_offset: Vector::new(1.0, 1.0),
|
||||
text_color: Color::WHITE,
|
||||
..button::Style::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
514
examples/styling.rs
Normal file
514
examples/styling.rs
Normal file
@ -0,0 +1,514 @@
|
||||
use iced::{
|
||||
button, scrollable, slider, text_input, Align, Button, Checkbox, Column,
|
||||
Container, Element, Length, ProgressBar, Radio, Row, Sandbox, Scrollable,
|
||||
Settings, Slider, Space, Text, TextInput,
|
||||
};
|
||||
|
||||
pub fn main() {
|
||||
Styling::run(Settings::default())
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Styling {
|
||||
theme: style::Theme,
|
||||
scroll: scrollable::State,
|
||||
input: text_input::State,
|
||||
input_value: String,
|
||||
button: button::State,
|
||||
slider: slider::State,
|
||||
slider_value: f32,
|
||||
toggle_value: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Message {
|
||||
ThemeChanged(style::Theme),
|
||||
InputChanged(String),
|
||||
ButtonPressed,
|
||||
SliderChanged(f32),
|
||||
CheckboxToggled(bool),
|
||||
}
|
||||
|
||||
impl Sandbox for Styling {
|
||||
type Message = Message;
|
||||
|
||||
fn new() -> Self {
|
||||
Styling::default()
|
||||
}
|
||||
|
||||
fn title(&self) -> String {
|
||||
String::from("Styling - Iced")
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Message) {
|
||||
match message {
|
||||
Message::ThemeChanged(theme) => self.theme = theme,
|
||||
Message::InputChanged(value) => self.input_value = value,
|
||||
Message::ButtonPressed => (),
|
||||
Message::SliderChanged(value) => self.slider_value = value,
|
||||
Message::CheckboxToggled(value) => self.toggle_value = value,
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&mut self) -> Element<Message> {
|
||||
let choose_theme = style::Theme::ALL.iter().fold(
|
||||
Column::new().spacing(10).push(Text::new("Choose a theme:")),
|
||||
|column, theme| {
|
||||
column.push(
|
||||
Radio::new(
|
||||
*theme,
|
||||
&format!("{:?}", theme),
|
||||
Some(self.theme),
|
||||
Message::ThemeChanged,
|
||||
)
|
||||
.style(self.theme),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
let text_input = TextInput::new(
|
||||
&mut self.input,
|
||||
"Type something...",
|
||||
&self.input_value,
|
||||
Message::InputChanged,
|
||||
)
|
||||
.padding(10)
|
||||
.size(20)
|
||||
.style(self.theme);
|
||||
|
||||
let button = Button::new(&mut self.button, Text::new("Submit"))
|
||||
.padding(10)
|
||||
.on_press(Message::ButtonPressed)
|
||||
.style(self.theme);
|
||||
|
||||
let slider = Slider::new(
|
||||
&mut self.slider,
|
||||
0.0..=100.0,
|
||||
self.slider_value,
|
||||
Message::SliderChanged,
|
||||
)
|
||||
.style(self.theme);
|
||||
|
||||
let progress_bar =
|
||||
ProgressBar::new(0.0..=100.0, self.slider_value).style(self.theme);
|
||||
|
||||
let scrollable = Scrollable::new(&mut self.scroll)
|
||||
.height(Length::Units(100))
|
||||
.style(self.theme)
|
||||
.push(Text::new("Scroll me!"))
|
||||
.push(Space::with_height(Length::Units(800)))
|
||||
.push(Text::new("You did it!"));
|
||||
|
||||
let checkbox = Checkbox::new(
|
||||
self.toggle_value,
|
||||
"Toggle me!",
|
||||
Message::CheckboxToggled,
|
||||
)
|
||||
.style(self.theme);
|
||||
|
||||
let content = Column::new()
|
||||
.spacing(20)
|
||||
.padding(20)
|
||||
.max_width(600)
|
||||
.push(choose_theme)
|
||||
.push(Row::new().spacing(10).push(text_input).push(button))
|
||||
.push(slider)
|
||||
.push(progress_bar)
|
||||
.push(
|
||||
Row::new()
|
||||
.spacing(10)
|
||||
.align_items(Align::Center)
|
||||
.push(scrollable)
|
||||
.push(checkbox),
|
||||
);
|
||||
|
||||
Container::new(content)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.center_x()
|
||||
.center_y()
|
||||
.style(self.theme)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
mod style {
|
||||
use iced::{
|
||||
button, checkbox, container, progress_bar, radio, scrollable, slider,
|
||||
text_input,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Theme {
|
||||
Light,
|
||||
Dark,
|
||||
}
|
||||
|
||||
impl Theme {
|
||||
pub const ALL: [Theme; 2] = [Theme::Light, Theme::Dark];
|
||||
}
|
||||
|
||||
impl Default for Theme {
|
||||
fn default() -> Theme {
|
||||
Theme::Light
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Theme> for Box<dyn container::StyleSheet> {
|
||||
fn from(theme: Theme) -> Self {
|
||||
match theme {
|
||||
Theme::Light => Default::default(),
|
||||
Theme::Dark => dark::Container.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Theme> for Box<dyn radio::StyleSheet> {
|
||||
fn from(theme: Theme) -> Self {
|
||||
match theme {
|
||||
Theme::Light => Default::default(),
|
||||
Theme::Dark => dark::Radio.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Theme> for Box<dyn text_input::StyleSheet> {
|
||||
fn from(theme: Theme) -> Self {
|
||||
match theme {
|
||||
Theme::Light => Default::default(),
|
||||
Theme::Dark => dark::TextInput.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Theme> for Box<dyn button::StyleSheet> {
|
||||
fn from(theme: Theme) -> Self {
|
||||
match theme {
|
||||
Theme::Light => light::Button.into(),
|
||||
Theme::Dark => dark::Button.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Theme> for Box<dyn scrollable::StyleSheet> {
|
||||
fn from(theme: Theme) -> Self {
|
||||
match theme {
|
||||
Theme::Light => Default::default(),
|
||||
Theme::Dark => dark::Scrollable.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Theme> for Box<dyn slider::StyleSheet> {
|
||||
fn from(theme: Theme) -> Self {
|
||||
match theme {
|
||||
Theme::Light => Default::default(),
|
||||
Theme::Dark => dark::Slider.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Theme> for Box<dyn progress_bar::StyleSheet> {
|
||||
fn from(theme: Theme) -> Self {
|
||||
match theme {
|
||||
Theme::Light => Default::default(),
|
||||
Theme::Dark => dark::ProgressBar.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Theme> for Box<dyn checkbox::StyleSheet> {
|
||||
fn from(theme: Theme) -> Self {
|
||||
match theme {
|
||||
Theme::Light => Default::default(),
|
||||
Theme::Dark => dark::Checkbox.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod light {
|
||||
use iced::{button, Background, Color, Vector};
|
||||
|
||||
pub struct Button;
|
||||
|
||||
impl button::StyleSheet for Button {
|
||||
fn active(&self) -> button::Style {
|
||||
button::Style {
|
||||
background: Some(Background::Color(Color::from_rgb(
|
||||
0.11, 0.42, 0.87,
|
||||
))),
|
||||
border_radius: 12,
|
||||
shadow_offset: Vector::new(1.0, 1.0),
|
||||
text_color: Color::from_rgb8(0xEE, 0xEE, 0xEE),
|
||||
..button::Style::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self) -> button::Style {
|
||||
button::Style {
|
||||
text_color: Color::WHITE,
|
||||
shadow_offset: Vector::new(1.0, 2.0),
|
||||
..self.active()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod dark {
|
||||
use iced::{
|
||||
button, checkbox, container, progress_bar, radio, scrollable,
|
||||
slider, text_input, Background, Color,
|
||||
};
|
||||
|
||||
const SURFACE: Color = Color::from_rgb(
|
||||
0x40 as f32 / 255.0,
|
||||
0x44 as f32 / 255.0,
|
||||
0x4B as f32 / 255.0,
|
||||
);
|
||||
|
||||
const ACCENT: Color = Color::from_rgb(
|
||||
0x6F as f32 / 255.0,
|
||||
0xFF as f32 / 255.0,
|
||||
0xE9 as f32 / 255.0,
|
||||
);
|
||||
|
||||
const ACTIVE: Color = Color::from_rgb(
|
||||
0x72 as f32 / 255.0,
|
||||
0x89 as f32 / 255.0,
|
||||
0xDA as f32 / 255.0,
|
||||
);
|
||||
|
||||
const HOVERED: Color = Color::from_rgb(
|
||||
0x67 as f32 / 255.0,
|
||||
0x7B as f32 / 255.0,
|
||||
0xC4 as f32 / 255.0,
|
||||
);
|
||||
|
||||
pub struct Container;
|
||||
|
||||
impl container::StyleSheet for Container {
|
||||
fn style(&self) -> container::Style {
|
||||
container::Style {
|
||||
background: Some(Background::Color(Color::from_rgb8(
|
||||
0x36, 0x39, 0x3F,
|
||||
))),
|
||||
text_color: Some(Color::WHITE),
|
||||
..container::Style::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Radio;
|
||||
|
||||
impl radio::StyleSheet for Radio {
|
||||
fn active(&self) -> radio::Style {
|
||||
radio::Style {
|
||||
background: Background::Color(SURFACE),
|
||||
dot_color: ACTIVE,
|
||||
border_width: 1,
|
||||
border_color: ACTIVE,
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self) -> radio::Style {
|
||||
radio::Style {
|
||||
background: Background::Color(Color { a: 0.5, ..SURFACE }),
|
||||
..self.active()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TextInput;
|
||||
|
||||
impl text_input::StyleSheet for TextInput {
|
||||
fn active(&self) -> text_input::Style {
|
||||
text_input::Style {
|
||||
background: Background::Color(SURFACE),
|
||||
border_radius: 2,
|
||||
border_width: 0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}
|
||||
}
|
||||
|
||||
fn focused(&self) -> text_input::Style {
|
||||
text_input::Style {
|
||||
border_width: 1,
|
||||
border_color: ACCENT,
|
||||
..self.active()
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self) -> text_input::Style {
|
||||
text_input::Style {
|
||||
border_width: 1,
|
||||
border_color: Color { a: 0.3, ..ACCENT },
|
||||
..self.focused()
|
||||
}
|
||||
}
|
||||
|
||||
fn placeholder_color(&self) -> Color {
|
||||
Color::from_rgb(0.4, 0.4, 0.4)
|
||||
}
|
||||
|
||||
fn value_color(&self) -> Color {
|
||||
Color::WHITE
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Button;
|
||||
|
||||
impl button::StyleSheet for Button {
|
||||
fn active(&self) -> button::Style {
|
||||
button::Style {
|
||||
background: Some(Background::Color(ACTIVE)),
|
||||
border_radius: 3,
|
||||
text_color: Color::WHITE,
|
||||
..button::Style::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self) -> button::Style {
|
||||
button::Style {
|
||||
background: Some(Background::Color(HOVERED)),
|
||||
text_color: Color::WHITE,
|
||||
..self.active()
|
||||
}
|
||||
}
|
||||
|
||||
fn pressed(&self) -> button::Style {
|
||||
button::Style {
|
||||
border_width: 1,
|
||||
border_color: Color::WHITE,
|
||||
..self.hovered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Scrollable;
|
||||
|
||||
impl scrollable::StyleSheet for Scrollable {
|
||||
fn active(&self) -> scrollable::Scrollbar {
|
||||
scrollable::Scrollbar {
|
||||
background: Some(Background::Color(SURFACE)),
|
||||
border_radius: 2,
|
||||
border_width: 0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
scroller: scrollable::Scroller {
|
||||
color: ACTIVE,
|
||||
border_radius: 2,
|
||||
border_width: 0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self) -> scrollable::Scrollbar {
|
||||
let active = self.active();
|
||||
|
||||
scrollable::Scrollbar {
|
||||
background: Some(Background::Color(Color {
|
||||
a: 0.5,
|
||||
..SURFACE
|
||||
})),
|
||||
scroller: scrollable::Scroller {
|
||||
color: HOVERED,
|
||||
..active.scroller
|
||||
},
|
||||
..active
|
||||
}
|
||||
}
|
||||
|
||||
fn dragging(&self) -> scrollable::Scrollbar {
|
||||
let hovered = self.hovered();
|
||||
|
||||
scrollable::Scrollbar {
|
||||
scroller: scrollable::Scroller {
|
||||
color: Color::from_rgb(0.85, 0.85, 0.85),
|
||||
..hovered.scroller
|
||||
},
|
||||
..hovered
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Slider;
|
||||
|
||||
impl slider::StyleSheet for Slider {
|
||||
fn active(&self) -> slider::Style {
|
||||
slider::Style {
|
||||
rail_colors: (ACTIVE, Color { a: 0.1, ..ACTIVE }),
|
||||
handle: slider::Handle {
|
||||
shape: slider::HandleShape::Circle { radius: 9 },
|
||||
color: ACTIVE,
|
||||
border_width: 0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self) -> slider::Style {
|
||||
let active = self.active();
|
||||
|
||||
slider::Style {
|
||||
handle: slider::Handle {
|
||||
color: HOVERED,
|
||||
..active.handle
|
||||
},
|
||||
..active
|
||||
}
|
||||
}
|
||||
|
||||
fn dragging(&self) -> slider::Style {
|
||||
let active = self.active();
|
||||
|
||||
slider::Style {
|
||||
handle: slider::Handle {
|
||||
color: Color::from_rgb(0.85, 0.85, 0.85),
|
||||
..active.handle
|
||||
},
|
||||
..active
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ProgressBar;
|
||||
|
||||
impl progress_bar::StyleSheet for ProgressBar {
|
||||
fn style(&self) -> progress_bar::Style {
|
||||
progress_bar::Style {
|
||||
background: Background::Color(SURFACE),
|
||||
bar: Background::Color(ACTIVE),
|
||||
border_radius: 10,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Checkbox;
|
||||
|
||||
impl checkbox::StyleSheet for Checkbox {
|
||||
fn active(&self, is_checked: bool) -> checkbox::Style {
|
||||
checkbox::Style {
|
||||
background: Background::Color(if is_checked {
|
||||
ACTIVE
|
||||
} else {
|
||||
SURFACE
|
||||
}),
|
||||
checkmark_color: Color::WHITE,
|
||||
border_radius: 2,
|
||||
border_width: 1,
|
||||
border_color: ACTIVE,
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self, is_checked: bool) -> checkbox::Style {
|
||||
checkbox::Style {
|
||||
background: Background::Color(Color {
|
||||
a: 0.8,
|
||||
..if is_checked { ACTIVE } else { SURFACE }
|
||||
}),
|
||||
..self.active(is_checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
use iced::{
|
||||
button, scrollable, text_input, Align, Application, Button, Checkbox,
|
||||
Color, Column, Command, Container, Element, Font, HorizontalAlignment,
|
||||
Length, Row, Scrollable, Settings, Text, TextInput,
|
||||
Column, Command, Container, Element, Font, HorizontalAlignment, Length,
|
||||
Row, Scrollable, Settings, Text, TextInput,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@ -293,12 +293,10 @@ impl Task {
|
||||
.align_items(Align::Center)
|
||||
.push(checkbox)
|
||||
.push(
|
||||
Button::new(
|
||||
edit_button,
|
||||
edit_icon().color([0.5, 0.5, 0.5]),
|
||||
)
|
||||
.on_press(TaskMessage::Edit)
|
||||
.padding(10),
|
||||
Button::new(edit_button, edit_icon())
|
||||
.on_press(TaskMessage::Edit)
|
||||
.padding(10)
|
||||
.style(style::Button::Icon),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
@ -324,13 +322,12 @@ impl Task {
|
||||
delete_button,
|
||||
Row::new()
|
||||
.spacing(10)
|
||||
.push(delete_icon().color(Color::WHITE))
|
||||
.push(Text::new("Delete").color(Color::WHITE)),
|
||||
.push(delete_icon())
|
||||
.push(Text::new("Delete")),
|
||||
)
|
||||
.on_press(TaskMessage::Delete)
|
||||
.padding(10)
|
||||
.border_radius(5)
|
||||
.background(Color::from_rgb(0.8, 0.2, 0.2)),
|
||||
.style(style::Button::Destructive),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
@ -357,17 +354,12 @@ impl Controls {
|
||||
|
||||
let filter_button = |state, label, filter, current_filter| {
|
||||
let label = Text::new(label).size(16);
|
||||
let button = if filter == current_filter {
|
||||
Button::new(state, label.color(Color::WHITE))
|
||||
.background(Color::from_rgb(0.2, 0.2, 0.7))
|
||||
} else {
|
||||
Button::new(state, label)
|
||||
};
|
||||
let button =
|
||||
Button::new(state, label).style(style::Button::Filter {
|
||||
selected: filter == current_filter,
|
||||
});
|
||||
|
||||
button
|
||||
.on_press(Message::FilterChanged(filter))
|
||||
.padding(8)
|
||||
.border_radius(10)
|
||||
button.on_press(Message::FilterChanged(filter)).padding(8)
|
||||
};
|
||||
|
||||
Row::new()
|
||||
@ -560,3 +552,63 @@ impl SavedState {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
mod style {
|
||||
use iced::{button, Background, Color, Vector};
|
||||
|
||||
pub enum Button {
|
||||
Filter { selected: bool },
|
||||
Icon,
|
||||
Destructive,
|
||||
}
|
||||
|
||||
impl button::StyleSheet for Button {
|
||||
fn active(&self) -> button::Style {
|
||||
match self {
|
||||
Button::Filter { selected } => {
|
||||
if *selected {
|
||||
button::Style {
|
||||
background: Some(Background::Color(
|
||||
Color::from_rgb(0.2, 0.2, 0.7),
|
||||
)),
|
||||
border_radius: 10,
|
||||
text_color: Color::WHITE,
|
||||
..button::Style::default()
|
||||
}
|
||||
} else {
|
||||
button::Style::default()
|
||||
}
|
||||
}
|
||||
Button::Icon => button::Style {
|
||||
text_color: Color::from_rgb(0.5, 0.5, 0.5),
|
||||
..button::Style::default()
|
||||
},
|
||||
Button::Destructive => button::Style {
|
||||
background: Some(Background::Color(Color::from_rgb(
|
||||
0.8, 0.2, 0.2,
|
||||
))),
|
||||
border_radius: 5,
|
||||
text_color: Color::WHITE,
|
||||
shadow_offset: Vector::new(1.0, 1.0),
|
||||
..button::Style::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self) -> button::Style {
|
||||
let active = self.active();
|
||||
|
||||
button::Style {
|
||||
text_color: match self {
|
||||
Button::Icon => Color::from_rgb(0.2, 0.2, 0.7),
|
||||
Button::Filter { selected } if !selected => {
|
||||
Color::from_rgb(0.2, 0.2, 0.7)
|
||||
}
|
||||
_ => active.text_color,
|
||||
},
|
||||
shadow_offset: active.shadow_offset + Vector::new(0.0, 1.0),
|
||||
..active
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,8 +62,9 @@ impl Sandbox for Tour {
|
||||
|
||||
if steps.has_previous() {
|
||||
controls = controls.push(
|
||||
secondary_button(back_button, "Back")
|
||||
.on_press(Message::BackPressed),
|
||||
button(back_button, "Back")
|
||||
.on_press(Message::BackPressed)
|
||||
.style(style::Button::Secondary),
|
||||
);
|
||||
}
|
||||
|
||||
@ -71,8 +72,9 @@ impl Sandbox for Tour {
|
||||
|
||||
if steps.can_continue() {
|
||||
controls = controls.push(
|
||||
primary_button(next_button, "Next")
|
||||
.on_press(Message::NextPressed),
|
||||
button(next_button, "Next")
|
||||
.on_press(Message::NextPressed)
|
||||
.style(style::Button::Primary),
|
||||
);
|
||||
}
|
||||
|
||||
@ -698,29 +700,12 @@ fn button<'a, Message>(
|
||||
) -> Button<'a, Message> {
|
||||
Button::new(
|
||||
state,
|
||||
Text::new(label)
|
||||
.color(Color::WHITE)
|
||||
.horizontal_alignment(HorizontalAlignment::Center),
|
||||
Text::new(label).horizontal_alignment(HorizontalAlignment::Center),
|
||||
)
|
||||
.padding(12)
|
||||
.border_radius(12)
|
||||
.min_width(100)
|
||||
}
|
||||
|
||||
fn primary_button<'a, Message>(
|
||||
state: &'a mut button::State,
|
||||
label: &str,
|
||||
) -> Button<'a, Message> {
|
||||
button(state, label).background(Color::from_rgb(0.11, 0.42, 0.87))
|
||||
}
|
||||
|
||||
fn secondary_button<'a, Message>(
|
||||
state: &'a mut button::State,
|
||||
label: &str,
|
||||
) -> Button<'a, Message> {
|
||||
button(state, label).background(Color::from_rgb(0.4, 0.4, 0.4))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Language {
|
||||
Rust,
|
||||
@ -763,6 +748,38 @@ pub enum Layout {
|
||||
Column,
|
||||
}
|
||||
|
||||
mod style {
|
||||
use iced::{button, Background, Color, Vector};
|
||||
|
||||
pub enum Button {
|
||||
Primary,
|
||||
Secondary,
|
||||
}
|
||||
|
||||
impl button::StyleSheet for Button {
|
||||
fn active(&self) -> button::Style {
|
||||
button::Style {
|
||||
background: Some(Background::Color(match self {
|
||||
Button::Primary => Color::from_rgb(0.11, 0.42, 0.87),
|
||||
Button::Secondary => Color::from_rgb(0.5, 0.5, 0.5),
|
||||
})),
|
||||
border_radius: 12,
|
||||
shadow_offset: Vector::new(1.0, 1.0),
|
||||
text_color: Color::from_rgb8(0xEE, 0xEE, 0xEE),
|
||||
..button::Style::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self) -> button::Style {
|
||||
button::Style {
|
||||
text_color: Color::WHITE,
|
||||
shadow_offset: Vector::new(1.0, 2.0),
|
||||
..self.active()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This should be gracefully handled by Iced in the future. Probably using our
|
||||
// own proc macro, or maybe the whole process is streamlined by `wasm-pack` at
|
||||
// some point.
|
||||
|
@ -235,10 +235,12 @@ where
|
||||
pub fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
self.widget.draw(renderer, layout, cursor_position)
|
||||
self.widget
|
||||
.draw(renderer, defaults, layout, cursor_position)
|
||||
}
|
||||
|
||||
pub(crate) fn hash_layout(&self, state: &mut Hasher) {
|
||||
@ -316,10 +318,12 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
self.widget.draw(renderer, layout, cursor_position)
|
||||
self.widget
|
||||
.draw(renderer, defaults, layout, cursor_position)
|
||||
}
|
||||
|
||||
fn hash_layout(&self, state: &mut Hasher) {
|
||||
@ -384,10 +388,12 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
renderer.explain(
|
||||
defaults,
|
||||
self.element.widget.as_ref(),
|
||||
layout,
|
||||
cursor_position,
|
||||
|
@ -21,14 +21,15 @@
|
||||
//! [`checkbox::Renderer`]: ../widget/checkbox/trait.Renderer.html
|
||||
|
||||
mod debugger;
|
||||
#[cfg(debug_assertions)]
|
||||
mod null;
|
||||
mod windowed;
|
||||
|
||||
pub use debugger::Debugger;
|
||||
pub use windowed::{Target, Windowed};
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
mod null;
|
||||
#[cfg(debug_assertions)]
|
||||
pub use null::Null;
|
||||
pub use windowed::{Target, Windowed};
|
||||
|
||||
use crate::{layout, Element};
|
||||
|
||||
@ -43,6 +44,13 @@ pub trait Renderer: Sized {
|
||||
/// [`Renderer`]: trait.Renderer.html
|
||||
type Output;
|
||||
|
||||
/// The default styling attributes of the [`Renderer`].
|
||||
///
|
||||
/// This type can be leveraged to implement style inheritance.
|
||||
///
|
||||
/// [`Renderer`]: trait.Renderer.html
|
||||
type Defaults: Default;
|
||||
|
||||
/// Lays out the elements of a user interface.
|
||||
///
|
||||
/// You should override this if you need to perform any operations before or
|
||||
|
@ -17,6 +17,7 @@ pub trait Debugger: super::Renderer {
|
||||
/// [`Element::explain`]: struct.Element.html#method.explain
|
||||
fn explain<Message>(
|
||||
&mut self,
|
||||
defaults: &Self::Defaults,
|
||||
widget: &dyn Widget<Message, Self>,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
|
@ -1,20 +1,33 @@
|
||||
use crate::{
|
||||
button, checkbox, column, radio, row, scrollable, text, text_input,
|
||||
Background, Color, Element, Font, HorizontalAlignment, Layout, Point,
|
||||
button, checkbox, column, progress_bar, radio, row, scrollable, slider,
|
||||
text, text_input, Color, Element, Font, HorizontalAlignment, Layout, Point,
|
||||
Rectangle, Renderer, Size, VerticalAlignment,
|
||||
};
|
||||
|
||||
/// A renderer that does nothing.
|
||||
///
|
||||
/// It can be useful if you are writing tests!
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Null;
|
||||
|
||||
impl Null {
|
||||
/// Creates a new [`Null`] renderer.
|
||||
///
|
||||
/// [`Null`]: struct.Null.html
|
||||
pub fn new() -> Null {
|
||||
Null
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer for Null {
|
||||
type Output = ();
|
||||
type Defaults = ();
|
||||
}
|
||||
|
||||
impl column::Renderer for Null {
|
||||
fn draw<Message>(
|
||||
&mut self,
|
||||
_defaults: &Self::Defaults,
|
||||
_content: &[Element<'_, Message, Self>],
|
||||
_layout: Layout<'_>,
|
||||
_cursor_position: Point,
|
||||
@ -25,6 +38,7 @@ impl column::Renderer for Null {
|
||||
impl row::Renderer for Null {
|
||||
fn draw<Message>(
|
||||
&mut self,
|
||||
_defaults: &Self::Defaults,
|
||||
_content: &[Element<'_, Message, Self>],
|
||||
_layout: Layout<'_>,
|
||||
_cursor_position: Point,
|
||||
@ -49,6 +63,7 @@ impl text::Renderer for Null {
|
||||
|
||||
fn draw(
|
||||
&mut self,
|
||||
_defaults: &Self::Defaults,
|
||||
_bounds: Rectangle,
|
||||
_content: &str,
|
||||
_size: u16,
|
||||
@ -61,6 +76,8 @@ impl text::Renderer for Null {
|
||||
}
|
||||
|
||||
impl scrollable::Renderer for Null {
|
||||
type Style = ();
|
||||
|
||||
fn scrollbar(
|
||||
&self,
|
||||
_bounds: Rectangle,
|
||||
@ -79,12 +96,15 @@ impl scrollable::Renderer for Null {
|
||||
_is_mouse_over_scrollbar: bool,
|
||||
_scrollbar: Option<scrollable::Scrollbar>,
|
||||
_offset: u32,
|
||||
_style: &Self::Style,
|
||||
_content: Self::Output,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl text_input::Renderer for Null {
|
||||
type Style = ();
|
||||
|
||||
fn default_size(&self) -> u16 {
|
||||
20
|
||||
}
|
||||
@ -112,24 +132,31 @@ impl text_input::Renderer for Null {
|
||||
_placeholder: &str,
|
||||
_value: &text_input::Value,
|
||||
_state: &text_input::State,
|
||||
_style: &Self::Style,
|
||||
) -> Self::Output {
|
||||
}
|
||||
}
|
||||
|
||||
impl button::Renderer for Null {
|
||||
fn draw(
|
||||
type Style = ();
|
||||
|
||||
fn draw<Message>(
|
||||
&mut self,
|
||||
_defaults: &Self::Defaults,
|
||||
_bounds: Rectangle,
|
||||
_cursor_position: Point,
|
||||
_is_disabled: bool,
|
||||
_is_pressed: bool,
|
||||
_background: Option<Background>,
|
||||
_border_radius: u16,
|
||||
_content: Self::Output,
|
||||
_style: &Self::Style,
|
||||
_content: &Element<'_, Message, Self>,
|
||||
_content_layout: Layout<'_>,
|
||||
) -> Self::Output {
|
||||
}
|
||||
}
|
||||
|
||||
impl radio::Renderer for Null {
|
||||
type Style = ();
|
||||
|
||||
fn default_size(&self) -> u32 {
|
||||
20
|
||||
}
|
||||
@ -140,11 +167,14 @@ impl radio::Renderer for Null {
|
||||
_is_selected: bool,
|
||||
_is_mouse_over: bool,
|
||||
_label: Self::Output,
|
||||
_style: &Self::Style,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl checkbox::Renderer for Null {
|
||||
type Style = ();
|
||||
|
||||
fn default_size(&self) -> u32 {
|
||||
20
|
||||
}
|
||||
@ -155,6 +185,41 @@ impl checkbox::Renderer for Null {
|
||||
_is_checked: bool,
|
||||
_is_mouse_over: bool,
|
||||
_label: Self::Output,
|
||||
_style: &Self::Style,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl slider::Renderer for Null {
|
||||
type Style = ();
|
||||
|
||||
fn height(&self) -> u32 {
|
||||
30
|
||||
}
|
||||
|
||||
fn draw(
|
||||
&mut self,
|
||||
_bounds: Rectangle,
|
||||
_cursor_position: Point,
|
||||
_range: std::ops::RangeInclusive<f32>,
|
||||
_value: f32,
|
||||
_is_dragging: bool,
|
||||
_style_sheet: &Self::Style,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl progress_bar::Renderer for Null {
|
||||
type Style = ();
|
||||
|
||||
const DEFAULT_HEIGHT: u16 = 30;
|
||||
|
||||
fn draw(
|
||||
&self,
|
||||
_bounds: Rectangle,
|
||||
_range: std::ops::RangeInclusive<f32>,
|
||||
_value: f32,
|
||||
_style: &Self::Style,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,16 @@ use raw_window_handle::HasRawWindowHandle;
|
||||
|
||||
/// A renderer that can target windows.
|
||||
pub trait Windowed: super::Renderer + Sized {
|
||||
/// The settings of the renderer.
|
||||
type Settings: Default;
|
||||
|
||||
/// The type of target.
|
||||
type Target: Target<Renderer = Self>;
|
||||
|
||||
/// Creates a new [`Windowed`] renderer.
|
||||
///
|
||||
/// [`Windowed`]: trait.Windowed.html
|
||||
fn new() -> Self;
|
||||
fn new(settings: Self::Settings) -> Self;
|
||||
|
||||
/// Performs the drawing operations described in the output on the given
|
||||
/// target.
|
||||
|
@ -43,24 +43,7 @@ where
|
||||
/// use iced_wgpu::Renderer;
|
||||
///
|
||||
/// # mod iced_wgpu {
|
||||
/// # pub struct Renderer;
|
||||
/// #
|
||||
/// # impl Renderer {
|
||||
/// # pub fn new() -> Self { Renderer }
|
||||
/// # }
|
||||
/// #
|
||||
/// # impl iced_native::Renderer for Renderer { type Output = (); }
|
||||
/// #
|
||||
/// # impl iced_native::column::Renderer for Renderer {
|
||||
/// # fn draw<Message>(
|
||||
/// # &mut self,
|
||||
/// # _children: &[iced_native::Element<'_, Message, Self>],
|
||||
/// # _layout: iced_native::Layout<'_>,
|
||||
/// # _cursor_position: iced_native::Point,
|
||||
/// # ) -> Self::Output {
|
||||
/// # ()
|
||||
/// # }
|
||||
/// # }
|
||||
/// # pub use iced_native::renderer::Null as Renderer;
|
||||
/// # }
|
||||
/// #
|
||||
/// # use iced_native::Column;
|
||||
@ -139,24 +122,7 @@ where
|
||||
/// use iced_wgpu::Renderer;
|
||||
///
|
||||
/// # mod iced_wgpu {
|
||||
/// # pub struct Renderer;
|
||||
/// #
|
||||
/// # impl Renderer {
|
||||
/// # pub fn new() -> Self { Renderer }
|
||||
/// # }
|
||||
/// #
|
||||
/// # impl iced_native::Renderer for Renderer { type Output = (); }
|
||||
/// #
|
||||
/// # impl iced_native::column::Renderer for Renderer {
|
||||
/// # fn draw<Message>(
|
||||
/// # &mut self,
|
||||
/// # _children: &[iced_native::Element<'_, Message, Self>],
|
||||
/// # _layout: iced_native::Layout<'_>,
|
||||
/// # _cursor_position: iced_native::Point,
|
||||
/// # ) -> Self::Output {
|
||||
/// # ()
|
||||
/// # }
|
||||
/// # }
|
||||
/// # pub use iced_native::renderer::Null as Renderer;
|
||||
/// # }
|
||||
/// #
|
||||
/// # use iced_native::Column;
|
||||
@ -241,24 +207,7 @@ where
|
||||
/// use iced_wgpu::Renderer;
|
||||
///
|
||||
/// # mod iced_wgpu {
|
||||
/// # pub struct Renderer;
|
||||
/// #
|
||||
/// # impl Renderer {
|
||||
/// # pub fn new() -> Self { Renderer }
|
||||
/// # }
|
||||
/// #
|
||||
/// # impl iced_native::Renderer for Renderer { type Output = (); }
|
||||
/// #
|
||||
/// # impl iced_native::column::Renderer for Renderer {
|
||||
/// # fn draw<Message>(
|
||||
/// # &mut self,
|
||||
/// # _children: &[iced_native::Element<'_, Message, Self>],
|
||||
/// # _layout: iced_native::Layout<'_>,
|
||||
/// # _cursor_position: iced_native::Point,
|
||||
/// # ) -> Self::Output {
|
||||
/// # ()
|
||||
/// # }
|
||||
/// # }
|
||||
/// # pub use iced_native::renderer::Null as Renderer;
|
||||
/// # }
|
||||
/// #
|
||||
/// # use iced_native::Column;
|
||||
@ -304,6 +253,7 @@ where
|
||||
pub fn draw(&self, renderer: &mut Renderer) -> Renderer::Output {
|
||||
self.root.widget.draw(
|
||||
renderer,
|
||||
&Renderer::Defaults::default(),
|
||||
Layout::new(&self.layout),
|
||||
self.cursor_position,
|
||||
)
|
||||
|
@ -107,6 +107,7 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Renderer::Output;
|
||||
|
@ -6,8 +6,8 @@
|
||||
//! [`State`]: struct.State.html
|
||||
use crate::{
|
||||
input::{mouse, ButtonState},
|
||||
layout, Background, Clipboard, Element, Event, Hasher, Layout, Length,
|
||||
Point, Rectangle, Widget,
|
||||
layout, Clipboard, Element, Event, Hasher, Layout, Length, Point,
|
||||
Rectangle, Widget,
|
||||
};
|
||||
use std::hash::Hash;
|
||||
|
||||
@ -28,7 +28,7 @@ use std::hash::Hash;
|
||||
/// .on_press(Message::ButtonPressed);
|
||||
/// ```
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Button<'a, Message, Renderer> {
|
||||
pub struct Button<'a, Message, Renderer: self::Renderer> {
|
||||
state: &'a mut State,
|
||||
content: Element<'a, Message, Renderer>,
|
||||
on_press: Option<Message>,
|
||||
@ -37,11 +37,13 @@ pub struct Button<'a, Message, Renderer> {
|
||||
min_width: u32,
|
||||
min_height: u32,
|
||||
padding: u16,
|
||||
background: Option<Background>,
|
||||
border_radius: u16,
|
||||
style: Renderer::Style,
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> Button<'a, Message, Renderer> {
|
||||
impl<'a, Message, Renderer> Button<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: self::Renderer,
|
||||
{
|
||||
/// Creates a new [`Button`] with some local [`State`] and the given
|
||||
/// content.
|
||||
///
|
||||
@ -60,8 +62,7 @@ impl<'a, Message, Renderer> Button<'a, Message, Renderer> {
|
||||
min_width: 0,
|
||||
min_height: 0,
|
||||
padding: 0,
|
||||
background: None,
|
||||
border_radius: 0,
|
||||
style: Renderer::Style::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,23 +106,6 @@ impl<'a, Message, Renderer> Button<'a, Message, Renderer> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the [`Background`] of the [`Button`].
|
||||
///
|
||||
/// [`Button`]: struct.Button.html
|
||||
/// [`Background`]: ../../struct.Background.html
|
||||
pub fn background<T: Into<Background>>(mut self, background: T) -> Self {
|
||||
self.background = Some(background.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the border radius of the [`Button`].
|
||||
///
|
||||
/// [`Button`]: struct.Button.html
|
||||
pub fn border_radius(mut self, border_radius: u16) -> Self {
|
||||
self.border_radius = border_radius;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the message that will be produced when the [`Button`] is pressed.
|
||||
///
|
||||
/// [`Button`]: struct.Button.html
|
||||
@ -129,6 +113,14 @@ impl<'a, Message, Renderer> Button<'a, Message, Renderer> {
|
||||
self.on_press = Some(msg);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the style of the [`Button`].
|
||||
///
|
||||
/// [`Button`]: struct.Button.html
|
||||
pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self {
|
||||
self.style = style.into();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// The local state of a [`Button`].
|
||||
@ -227,22 +219,19 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
let content = self.content.draw(
|
||||
renderer,
|
||||
layout.children().next().unwrap(),
|
||||
cursor_position,
|
||||
);
|
||||
|
||||
renderer.draw(
|
||||
defaults,
|
||||
layout.bounds(),
|
||||
cursor_position,
|
||||
self.on_press.is_none(),
|
||||
self.state.is_pressed,
|
||||
self.background,
|
||||
self.border_radius,
|
||||
content,
|
||||
&self.style,
|
||||
&self.content,
|
||||
layout.children().next().unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -260,17 +249,22 @@ where
|
||||
/// [`Button`]: struct.Button.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer + Sized {
|
||||
/// The style supported by this renderer.
|
||||
type Style: Default;
|
||||
|
||||
/// Draws a [`Button`].
|
||||
///
|
||||
/// [`Button`]: struct.Button.html
|
||||
fn draw(
|
||||
fn draw<Message>(
|
||||
&mut self,
|
||||
defaults: &Self::Defaults,
|
||||
bounds: Rectangle,
|
||||
cursor_position: Point,
|
||||
is_disabled: bool,
|
||||
is_pressed: bool,
|
||||
background: Option<Background>,
|
||||
border_radius: u16,
|
||||
content: Self::Output,
|
||||
style: &Self::Style,
|
||||
content: &Element<'_, Message, Self>,
|
||||
content_layout: Layout<'_>,
|
||||
) -> Self::Output;
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ use std::hash::Hash;
|
||||
|
||||
use crate::{
|
||||
input::{mouse, ButtonState},
|
||||
layout, row, text, Align, Clipboard, Color, Element, Event, Font, Hasher,
|
||||
layout, row, text, Align, Clipboard, Element, Event, Font, Hasher,
|
||||
HorizontalAlignment, Layout, Length, Point, Rectangle, Row, Text,
|
||||
VerticalAlignment, Widget,
|
||||
};
|
||||
@ -13,7 +13,7 @@ use crate::{
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use iced_native::Checkbox;
|
||||
/// # type Checkbox<Message> = iced_native::Checkbox<Message, iced_native::renderer::Null>;
|
||||
/// #
|
||||
/// pub enum Message {
|
||||
/// CheckboxToggled(bool),
|
||||
@ -26,15 +26,15 @@ use crate::{
|
||||
///
|
||||
/// 
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Checkbox<Message> {
|
||||
pub struct Checkbox<Message, Renderer: self::Renderer> {
|
||||
is_checked: bool,
|
||||
on_toggle: Box<dyn Fn(bool) -> Message>,
|
||||
label: String,
|
||||
label_color: Option<Color>,
|
||||
width: Length,
|
||||
style: Renderer::Style,
|
||||
}
|
||||
|
||||
impl<Message> Checkbox<Message> {
|
||||
impl<Message, Renderer: self::Renderer> Checkbox<Message, Renderer> {
|
||||
/// Creates a new [`Checkbox`].
|
||||
///
|
||||
/// It expects:
|
||||
@ -53,19 +53,11 @@ impl<Message> Checkbox<Message> {
|
||||
is_checked,
|
||||
on_toggle: Box::new(f),
|
||||
label: String::from(label),
|
||||
label_color: None,
|
||||
width: Length::Shrink,
|
||||
style: Renderer::Style::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the color of the label of the [`Checkbox`].
|
||||
///
|
||||
/// [`Checkbox`]: struct.Checkbox.html
|
||||
pub fn label_color<C: Into<Color>>(mut self, color: C) -> Self {
|
||||
self.label_color = Some(color.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the width of the [`Checkbox`].
|
||||
///
|
||||
/// [`Checkbox`]: struct.Checkbox.html
|
||||
@ -73,9 +65,18 @@ impl<Message> Checkbox<Message> {
|
||||
self.width = width;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the style of the [`Checkbox`].
|
||||
///
|
||||
/// [`Checkbox`]: struct.Checkbox.html
|
||||
pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self {
|
||||
self.style = style.into();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<Message, Renderer> Widget<Message, Renderer> for Checkbox<Message>
|
||||
impl<Message, Renderer> Widget<Message, Renderer>
|
||||
for Checkbox<Message, Renderer>
|
||||
where
|
||||
Renderer: self::Renderer + text::Renderer + row::Renderer,
|
||||
{
|
||||
@ -134,6 +135,7 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
@ -146,11 +148,12 @@ where
|
||||
|
||||
let label = text::Renderer::draw(
|
||||
renderer,
|
||||
defaults,
|
||||
label_layout.bounds(),
|
||||
&self.label,
|
||||
text::Renderer::default_size(renderer),
|
||||
Font::Default,
|
||||
self.label_color,
|
||||
None,
|
||||
HorizontalAlignment::Left,
|
||||
VerticalAlignment::Center,
|
||||
);
|
||||
@ -163,6 +166,7 @@ where
|
||||
self.is_checked,
|
||||
is_mouse_over,
|
||||
label,
|
||||
&self.style,
|
||||
)
|
||||
}
|
||||
|
||||
@ -179,6 +183,9 @@ where
|
||||
/// [`Checkbox`]: struct.Checkbox.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer {
|
||||
/// The style supported by this renderer.
|
||||
type Style: Default;
|
||||
|
||||
/// Returns the default size of a [`Checkbox`].
|
||||
///
|
||||
/// [`Checkbox`]: struct.Checkbox.html
|
||||
@ -199,16 +206,19 @@ pub trait Renderer: crate::Renderer {
|
||||
is_checked: bool,
|
||||
is_mouse_over: bool,
|
||||
label: Self::Output,
|
||||
style: &Self::Style,
|
||||
) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> From<Checkbox<Message>>
|
||||
impl<'a, Message, Renderer> From<Checkbox<Message, Renderer>>
|
||||
for Element<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: self::Renderer + text::Renderer + row::Renderer,
|
||||
Renderer: 'static + self::Renderer + text::Renderer + row::Renderer,
|
||||
Message: 'static,
|
||||
{
|
||||
fn from(checkbox: Checkbox<Message>) -> Element<'a, Message, Renderer> {
|
||||
fn from(
|
||||
checkbox: Checkbox<Message, Renderer>,
|
||||
) -> Element<'a, Message, Renderer> {
|
||||
Element::new(checkbox)
|
||||
}
|
||||
}
|
||||
|
@ -173,10 +173,11 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
renderer.draw(&self.children, layout, cursor_position)
|
||||
renderer.draw(defaults, &self.children, layout, cursor_position)
|
||||
}
|
||||
|
||||
fn hash_layout(&self, state: &mut Hasher) {
|
||||
@ -213,6 +214,7 @@ pub trait Renderer: crate::Renderer + Sized {
|
||||
/// [`Layout`]: ../layout/struct.Layout.html
|
||||
fn draw<Message>(
|
||||
&mut self,
|
||||
defaults: &Self::Defaults,
|
||||
content: &[Element<'_, Message, Self>],
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
|
@ -3,7 +3,7 @@ use std::hash::Hash;
|
||||
|
||||
use crate::{
|
||||
layout, Align, Clipboard, Element, Event, Hasher, Layout, Length, Point,
|
||||
Widget,
|
||||
Rectangle, Widget,
|
||||
};
|
||||
|
||||
use std::u32;
|
||||
@ -12,17 +12,21 @@ use std::u32;
|
||||
///
|
||||
/// It is normally used for alignment purposes.
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Container<'a, Message, Renderer> {
|
||||
pub struct Container<'a, Message, Renderer: self::Renderer> {
|
||||
width: Length,
|
||||
height: Length,
|
||||
max_width: u32,
|
||||
max_height: u32,
|
||||
horizontal_alignment: Align,
|
||||
vertical_alignment: Align,
|
||||
style: Renderer::Style,
|
||||
content: Element<'a, Message, Renderer>,
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> Container<'a, Message, Renderer> {
|
||||
impl<'a, Message, Renderer> Container<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: self::Renderer,
|
||||
{
|
||||
/// Creates an empty [`Container`].
|
||||
///
|
||||
/// [`Container`]: struct.Container.html
|
||||
@ -37,6 +41,7 @@ impl<'a, Message, Renderer> Container<'a, Message, Renderer> {
|
||||
max_height: u32::MAX,
|
||||
horizontal_alignment: Align::Start,
|
||||
vertical_alignment: Align::Start,
|
||||
style: Renderer::Style::default(),
|
||||
content: content.into(),
|
||||
}
|
||||
}
|
||||
@ -78,7 +83,6 @@ impl<'a, Message, Renderer> Container<'a, Message, Renderer> {
|
||||
/// [`Container`]: struct.Container.html
|
||||
pub fn center_x(mut self) -> Self {
|
||||
self.horizontal_alignment = Align::Center;
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
@ -87,7 +91,14 @@ impl<'a, Message, Renderer> Container<'a, Message, Renderer> {
|
||||
/// [`Container`]: struct.Container.html
|
||||
pub fn center_y(mut self) -> Self {
|
||||
self.vertical_alignment = Align::Center;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the style of the [`Container`].
|
||||
///
|
||||
/// [`Container`]: struct.Container.html
|
||||
pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self {
|
||||
self.style = style.into();
|
||||
self
|
||||
}
|
||||
}
|
||||
@ -95,7 +106,7 @@ impl<'a, Message, Renderer> Container<'a, Message, Renderer> {
|
||||
impl<'a, Message, Renderer> Widget<Message, Renderer>
|
||||
for Container<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: crate::Renderer,
|
||||
Renderer: self::Renderer,
|
||||
{
|
||||
fn width(&self) -> Length {
|
||||
self.width
|
||||
@ -147,13 +158,17 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
self.content.draw(
|
||||
renderer,
|
||||
layout.children().next().unwrap(),
|
||||
renderer.draw(
|
||||
defaults,
|
||||
layout.bounds(),
|
||||
cursor_position,
|
||||
&self.style,
|
||||
&self.content,
|
||||
layout.children().next().unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -168,10 +183,35 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// The renderer of a [`Container`].
|
||||
///
|
||||
/// Your [renderer] will need to implement this trait before being
|
||||
/// able to use a [`Container`] in your user interface.
|
||||
///
|
||||
/// [`Container`]: struct.Container.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer {
|
||||
/// The style supported by this renderer.
|
||||
type Style: Default;
|
||||
|
||||
/// Draws a [`Container`].
|
||||
///
|
||||
/// [`Container`]: struct.Container.html
|
||||
fn draw<Message>(
|
||||
&mut self,
|
||||
defaults: &Self::Defaults,
|
||||
bounds: Rectangle,
|
||||
cursor_position: Point,
|
||||
style: &Self::Style,
|
||||
content: &Element<'_, Message, Self>,
|
||||
content_layout: Layout<'_>,
|
||||
) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> From<Container<'a, Message, Renderer>>
|
||||
for Element<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: 'a + crate::Renderer,
|
||||
Renderer: 'a + self::Renderer,
|
||||
Message: 'static,
|
||||
{
|
||||
fn from(
|
||||
|
@ -95,6 +95,7 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
_defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
_cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
|
@ -1,7 +1,6 @@
|
||||
//! Provide progress feedback to your users.
|
||||
use crate::{
|
||||
layout, Background, Color, Element, Hasher, Layout, Length, Point,
|
||||
Rectangle, Size, Widget,
|
||||
layout, Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget,
|
||||
};
|
||||
|
||||
use std::{hash::Hash, ops::RangeInclusive};
|
||||
@ -10,8 +9,9 @@ use std::{hash::Hash, ops::RangeInclusive};
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use iced_native::ProgressBar;
|
||||
/// # use iced_native::renderer::Null;
|
||||
/// #
|
||||
/// # pub type ProgressBar = iced_native::ProgressBar<Null>;
|
||||
/// let value = 50.0;
|
||||
///
|
||||
/// ProgressBar::new(0.0..=100.0, value);
|
||||
@ -19,16 +19,15 @@ use std::{hash::Hash, ops::RangeInclusive};
|
||||
///
|
||||
/// 
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct ProgressBar {
|
||||
pub struct ProgressBar<Renderer: self::Renderer> {
|
||||
range: RangeInclusive<f32>,
|
||||
value: f32,
|
||||
width: Length,
|
||||
height: Option<Length>,
|
||||
background: Option<Background>,
|
||||
active_color: Option<Color>,
|
||||
style: Renderer::Style,
|
||||
}
|
||||
|
||||
impl ProgressBar {
|
||||
impl<Renderer: self::Renderer> ProgressBar<Renderer> {
|
||||
/// Creates a new [`ProgressBar`].
|
||||
///
|
||||
/// It expects:
|
||||
@ -42,8 +41,7 @@ impl ProgressBar {
|
||||
range,
|
||||
width: Length::Fill,
|
||||
height: None,
|
||||
background: None,
|
||||
active_color: None,
|
||||
style: Renderer::Style::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,24 +61,16 @@ impl ProgressBar {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the background of the [`ProgressBar`].
|
||||
/// Sets the style of the [`ProgressBar`].
|
||||
///
|
||||
/// [`ProgressBar`]: struct.ProgressBar.html
|
||||
pub fn background(mut self, background: Background) -> Self {
|
||||
self.background = Some(background);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the active color of the [`ProgressBar`].
|
||||
///
|
||||
/// [`ProgressBar`]: struct.ProgressBar.html
|
||||
pub fn active_color(mut self, active_color: Color) -> Self {
|
||||
self.active_color = Some(active_color);
|
||||
pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self {
|
||||
self.style = style.into();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<Message, Renderer> Widget<Message, Renderer> for ProgressBar
|
||||
impl<Message, Renderer> Widget<Message, Renderer> for ProgressBar<Renderer>
|
||||
where
|
||||
Renderer: self::Renderer,
|
||||
{
|
||||
@ -111,6 +101,7 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
_defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
_cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
@ -118,8 +109,7 @@ where
|
||||
layout.bounds(),
|
||||
self.range.clone(),
|
||||
self.value,
|
||||
self.background,
|
||||
self.active_color,
|
||||
&self.style,
|
||||
)
|
||||
}
|
||||
|
||||
@ -137,6 +127,9 @@ where
|
||||
/// [`ProgressBar`]: struct.ProgressBar.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer {
|
||||
/// The style supported by this renderer.
|
||||
type Style: Default;
|
||||
|
||||
/// The default height of a [`ProgressBar`].
|
||||
///
|
||||
/// [`ProgressBar`]: struct.ProgressBar.html
|
||||
@ -157,17 +150,19 @@ pub trait Renderer: crate::Renderer {
|
||||
bounds: Rectangle,
|
||||
range: RangeInclusive<f32>,
|
||||
value: f32,
|
||||
background: Option<Background>,
|
||||
active_color: Option<Color>,
|
||||
style: &Self::Style,
|
||||
) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> From<ProgressBar> for Element<'a, Message, Renderer>
|
||||
impl<'a, Message, Renderer> From<ProgressBar<Renderer>>
|
||||
for Element<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: self::Renderer,
|
||||
Renderer: 'static + self::Renderer,
|
||||
Message: 'static,
|
||||
{
|
||||
fn from(progress_bar: ProgressBar) -> Element<'a, Message, Renderer> {
|
||||
fn from(
|
||||
progress_bar: ProgressBar<Renderer>,
|
||||
) -> Element<'a, Message, Renderer> {
|
||||
Element::new(progress_bar)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Create choices using radio buttons.
|
||||
use crate::{
|
||||
input::{mouse, ButtonState},
|
||||
layout, row, text, Align, Clipboard, Color, Element, Event, Font, Hasher,
|
||||
layout, row, text, Align, Clipboard, Element, Event, Font, Hasher,
|
||||
HorizontalAlignment, Layout, Length, Point, Rectangle, Row, Text,
|
||||
VerticalAlignment, Widget,
|
||||
};
|
||||
@ -12,7 +12,8 @@ use std::hash::Hash;
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use iced_native::Radio;
|
||||
/// # type Radio<Message> =
|
||||
/// # iced_native::Radio<Message, iced_native::renderer::Null>;
|
||||
/// #
|
||||
/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
/// pub enum Choice {
|
||||
@ -34,14 +35,14 @@ use std::hash::Hash;
|
||||
///
|
||||
/// 
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Radio<Message> {
|
||||
pub struct Radio<Message, Renderer: self::Renderer> {
|
||||
is_selected: bool,
|
||||
on_click: Message,
|
||||
label: String,
|
||||
label_color: Option<Color>,
|
||||
style: Renderer::Style,
|
||||
}
|
||||
|
||||
impl<Message> Radio<Message> {
|
||||
impl<Message, Renderer: self::Renderer> Radio<Message, Renderer> {
|
||||
/// Creates a new [`Radio`] button.
|
||||
///
|
||||
/// It expects:
|
||||
@ -61,20 +62,20 @@ impl<Message> Radio<Message> {
|
||||
is_selected: Some(value) == selected,
|
||||
on_click: f(value),
|
||||
label: String::from(label),
|
||||
label_color: None,
|
||||
style: Renderer::Style::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the `Color` of the label of the [`Radio`].
|
||||
/// Sets the style of the [`Radio`] button.
|
||||
///
|
||||
/// [`Radio`]: struct.Radio.html
|
||||
pub fn label_color<C: Into<Color>>(mut self, color: C) -> Self {
|
||||
self.label_color = Some(color.into());
|
||||
pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self {
|
||||
self.style = style.into();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<Message, Renderer> Widget<Message, Renderer> for Radio<Message>
|
||||
impl<Message, Renderer> Widget<Message, Renderer> for Radio<Message, Renderer>
|
||||
where
|
||||
Renderer: self::Renderer + text::Renderer + row::Renderer,
|
||||
Message: Clone,
|
||||
@ -132,6 +133,7 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
@ -144,11 +146,12 @@ where
|
||||
|
||||
let label = text::Renderer::draw(
|
||||
renderer,
|
||||
defaults,
|
||||
label_layout.bounds(),
|
||||
&self.label,
|
||||
text::Renderer::default_size(renderer),
|
||||
Font::Default,
|
||||
self.label_color,
|
||||
None,
|
||||
HorizontalAlignment::Left,
|
||||
VerticalAlignment::Center,
|
||||
);
|
||||
@ -161,6 +164,7 @@ where
|
||||
self.is_selected,
|
||||
is_mouse_over,
|
||||
label,
|
||||
&self.style,
|
||||
)
|
||||
}
|
||||
|
||||
@ -177,6 +181,9 @@ where
|
||||
/// [`Radio`]: struct.Radio.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer {
|
||||
/// The style supported by this renderer.
|
||||
type Style: Default;
|
||||
|
||||
/// Returns the default size of a [`Radio`] button.
|
||||
///
|
||||
/// [`Radio`]: struct.Radio.html
|
||||
@ -197,16 +204,17 @@ pub trait Renderer: crate::Renderer {
|
||||
is_selected: bool,
|
||||
is_mouse_over: bool,
|
||||
label: Self::Output,
|
||||
style: &Self::Style,
|
||||
) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> From<Radio<Message>>
|
||||
impl<'a, Message, Renderer> From<Radio<Message, Renderer>>
|
||||
for Element<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: self::Renderer + row::Renderer + text::Renderer,
|
||||
Renderer: 'static + self::Renderer + row::Renderer + text::Renderer,
|
||||
Message: 'static + Clone,
|
||||
{
|
||||
fn from(radio: Radio<Message>) -> Element<'a, Message, Renderer> {
|
||||
fn from(radio: Radio<Message, Renderer>) -> Element<'a, Message, Renderer> {
|
||||
Element::new(radio)
|
||||
}
|
||||
}
|
||||
|
@ -174,10 +174,11 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
renderer.draw(&self.children, layout, cursor_position)
|
||||
renderer.draw(defaults, &self.children, layout, cursor_position)
|
||||
}
|
||||
|
||||
fn hash_layout(&self, state: &mut Hasher) {
|
||||
@ -215,6 +216,7 @@ pub trait Renderer: crate::Renderer + Sized {
|
||||
/// [`Layout`]: ../layout/struct.Layout.html
|
||||
fn draw<Message>(
|
||||
&mut self,
|
||||
defaults: &Self::Defaults,
|
||||
children: &[Element<'_, Message, Self>],
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
|
@ -11,14 +11,15 @@ use std::{f32, hash::Hash, u32};
|
||||
/// A widget that can vertically display an infinite amount of content with a
|
||||
/// scrollbar.
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Scrollable<'a, Message, Renderer> {
|
||||
pub struct Scrollable<'a, Message, Renderer: self::Renderer> {
|
||||
state: &'a mut State,
|
||||
height: Length,
|
||||
max_height: u32,
|
||||
content: Column<'a, Message, Renderer>,
|
||||
style: Renderer::Style,
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> Scrollable<'a, Message, Renderer> {
|
||||
impl<'a, Message, Renderer: self::Renderer> Scrollable<'a, Message, Renderer> {
|
||||
/// Creates a new [`Scrollable`] with the given [`State`].
|
||||
///
|
||||
/// [`Scrollable`]: struct.Scrollable.html
|
||||
@ -29,6 +30,7 @@ impl<'a, Message, Renderer> Scrollable<'a, Message, Renderer> {
|
||||
height: Length::Shrink,
|
||||
max_height: u32::MAX,
|
||||
content: Column::new(),
|
||||
style: Renderer::Style::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,6 +92,14 @@ impl<'a, Message, Renderer> Scrollable<'a, Message, Renderer> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the style of the [`Scrollable`] .
|
||||
///
|
||||
/// [`Scrollable`]: struct.Scrollable.html
|
||||
pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self {
|
||||
self.style = style.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds an element to the [`Scrollable`].
|
||||
///
|
||||
/// [`Scrollable`]: struct.Scrollable.html
|
||||
@ -105,7 +115,7 @@ impl<'a, Message, Renderer> Scrollable<'a, Message, Renderer> {
|
||||
impl<'a, Message, Renderer> Widget<Message, Renderer>
|
||||
for Scrollable<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: self::Renderer + column::Renderer,
|
||||
Renderer: 'static + self::Renderer + column::Renderer,
|
||||
{
|
||||
fn width(&self) -> Length {
|
||||
Length::Fill
|
||||
@ -255,6 +265,7 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
@ -277,7 +288,12 @@ where
|
||||
Point::new(cursor_position.x, -1.0)
|
||||
};
|
||||
|
||||
self.content.draw(renderer, content_layout, cursor_position)
|
||||
self.content.draw(
|
||||
renderer,
|
||||
defaults,
|
||||
content_layout,
|
||||
cursor_position,
|
||||
)
|
||||
};
|
||||
|
||||
self::Renderer::draw(
|
||||
@ -289,12 +305,13 @@ where
|
||||
is_mouse_over_scrollbar,
|
||||
scrollbar,
|
||||
offset,
|
||||
&self.style,
|
||||
content,
|
||||
)
|
||||
}
|
||||
|
||||
fn hash_layout(&self, state: &mut Hasher) {
|
||||
std::any::TypeId::of::<Scrollable<'static, (), ()>>().hash(state);
|
||||
std::any::TypeId::of::<Scrollable<'static, (), Renderer>>().hash(state);
|
||||
|
||||
self.height.hash(state);
|
||||
self.max_height.hash(state);
|
||||
@ -441,6 +458,9 @@ pub struct Scroller {
|
||||
/// [`Scrollable`]: struct.Scrollable.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer + Sized {
|
||||
/// The style supported by this renderer.
|
||||
type Style: Default;
|
||||
|
||||
/// Returns the [`Scrollbar`] given the bounds and content bounds of a
|
||||
/// [`Scrollable`].
|
||||
///
|
||||
@ -477,6 +497,7 @@ pub trait Renderer: crate::Renderer + Sized {
|
||||
is_mouse_over_scrollbar: bool,
|
||||
scrollbar: Option<Scrollbar>,
|
||||
offset: u32,
|
||||
style: &Self::Style,
|
||||
content: Self::Output,
|
||||
) -> Self::Output;
|
||||
}
|
||||
@ -484,7 +505,7 @@ pub trait Renderer: crate::Renderer + Sized {
|
||||
impl<'a, Message, Renderer> From<Scrollable<'a, Message, Renderer>>
|
||||
for Element<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: 'a + self::Renderer + column::Renderer,
|
||||
Renderer: 'static + self::Renderer + column::Renderer,
|
||||
Message: 'static,
|
||||
{
|
||||
fn from(
|
||||
|
@ -21,8 +21,9 @@ use std::{hash::Hash, ops::RangeInclusive};
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use iced_native::{slider, Slider};
|
||||
/// # use iced_native::{slider, renderer::Null};
|
||||
/// #
|
||||
/// # pub type Slider<'a, Message> = iced_native::Slider<'a, Message, Null>;
|
||||
/// pub enum Message {
|
||||
/// SliderChanged(f32),
|
||||
/// }
|
||||
@ -35,15 +36,16 @@ use std::{hash::Hash, ops::RangeInclusive};
|
||||
///
|
||||
/// 
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Slider<'a, Message> {
|
||||
pub struct Slider<'a, Message, Renderer: self::Renderer> {
|
||||
state: &'a mut State,
|
||||
range: RangeInclusive<f32>,
|
||||
value: f32,
|
||||
on_change: Box<dyn Fn(f32) -> Message>,
|
||||
width: Length,
|
||||
style: Renderer::Style,
|
||||
}
|
||||
|
||||
impl<'a, Message> Slider<'a, Message> {
|
||||
impl<'a, Message, Renderer: self::Renderer> Slider<'a, Message, Renderer> {
|
||||
/// Creates a new [`Slider`].
|
||||
///
|
||||
/// It expects:
|
||||
@ -71,6 +73,7 @@ impl<'a, Message> Slider<'a, Message> {
|
||||
range,
|
||||
on_change: Box::new(on_change),
|
||||
width: Length::Fill,
|
||||
style: Renderer::Style::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,6 +84,14 @@ impl<'a, Message> Slider<'a, Message> {
|
||||
self.width = width;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the style of the [`Slider`].
|
||||
///
|
||||
/// [`Slider`]: struct.Slider.html
|
||||
pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self {
|
||||
self.style = style.into();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// The local state of a [`Slider`].
|
||||
@ -100,7 +111,8 @@ impl State {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> Widget<Message, Renderer> for Slider<'a, Message>
|
||||
impl<'a, Message, Renderer> Widget<Message, Renderer>
|
||||
for Slider<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: self::Renderer,
|
||||
{
|
||||
@ -178,6 +190,7 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
_defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
@ -187,6 +200,7 @@ where
|
||||
self.range.clone(),
|
||||
self.value,
|
||||
self.state.is_dragging,
|
||||
&self.style,
|
||||
)
|
||||
}
|
||||
|
||||
@ -203,6 +217,9 @@ where
|
||||
/// [`Slider`]: struct.Slider.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer {
|
||||
/// The style supported by this renderer.
|
||||
type Style: Default;
|
||||
|
||||
/// Returns the height of the [`Slider`].
|
||||
///
|
||||
/// [`Slider`]: struct.Slider.html
|
||||
@ -227,16 +244,19 @@ pub trait Renderer: crate::Renderer {
|
||||
range: RangeInclusive<f32>,
|
||||
value: f32,
|
||||
is_dragging: bool,
|
||||
style: &Self::Style,
|
||||
) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> From<Slider<'a, Message>>
|
||||
impl<'a, Message, Renderer> From<Slider<'a, Message, Renderer>>
|
||||
for Element<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: self::Renderer,
|
||||
Renderer: 'static + self::Renderer,
|
||||
Message: 'static,
|
||||
{
|
||||
fn from(slider: Slider<'a, Message>) -> Element<'a, Message, Renderer> {
|
||||
fn from(
|
||||
slider: Slider<'a, Message, Renderer>,
|
||||
) -> Element<'a, Message, Renderer> {
|
||||
Element::new(slider)
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
_defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
_cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
|
@ -91,6 +91,7 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
_defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
_cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
|
@ -146,10 +146,12 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
_cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
renderer.draw(
|
||||
defaults,
|
||||
layout.bounds(),
|
||||
&self.content,
|
||||
self.size.unwrap_or(renderer.default_size()),
|
||||
@ -209,6 +211,7 @@ pub trait Renderer: crate::Renderer {
|
||||
/// [`VerticalAlignment`]: enum.VerticalAlignment.html
|
||||
fn draw(
|
||||
&mut self,
|
||||
defaults: &Self::Defaults,
|
||||
bounds: Rectangle,
|
||||
content: &str,
|
||||
size: u16,
|
||||
|
@ -15,8 +15,9 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use iced_native::{text_input, TextInput};
|
||||
/// # use iced_native::{text_input, renderer::Null};
|
||||
/// #
|
||||
/// # pub type TextInput<'a, Message> = iced_native::TextInput<'a, Message, Null>;
|
||||
/// #[derive(Debug, Clone)]
|
||||
/// enum Message {
|
||||
/// TextInputChanged(String),
|
||||
@ -35,7 +36,7 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||
/// ```
|
||||
/// 
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct TextInput<'a, Message> {
|
||||
pub struct TextInput<'a, Message, Renderer: self::Renderer> {
|
||||
state: &'a mut State,
|
||||
placeholder: String,
|
||||
value: Value,
|
||||
@ -46,9 +47,10 @@ pub struct TextInput<'a, Message> {
|
||||
size: Option<u16>,
|
||||
on_change: Box<dyn Fn(String) -> Message>,
|
||||
on_submit: Option<Message>,
|
||||
style: Renderer::Style,
|
||||
}
|
||||
|
||||
impl<'a, Message> TextInput<'a, Message> {
|
||||
impl<'a, Message, Renderer: self::Renderer> TextInput<'a, Message, Renderer> {
|
||||
/// Creates a new [`TextInput`].
|
||||
///
|
||||
/// It expects:
|
||||
@ -64,7 +66,7 @@ impl<'a, Message> TextInput<'a, Message> {
|
||||
placeholder: &str,
|
||||
value: &str,
|
||||
on_change: F,
|
||||
) -> TextInput<'a, Message>
|
||||
) -> Self
|
||||
where
|
||||
F: 'static + Fn(String) -> Message,
|
||||
{
|
||||
@ -79,6 +81,7 @@ impl<'a, Message> TextInput<'a, Message> {
|
||||
size: None,
|
||||
on_change: Box::new(on_change),
|
||||
on_submit: None,
|
||||
style: Renderer::Style::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,11 +133,20 @@ impl<'a, Message> TextInput<'a, Message> {
|
||||
self.on_submit = Some(message);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the style of the [`TextInput`].
|
||||
///
|
||||
/// [`TextInput`]: struct.TextInput.html
|
||||
pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self {
|
||||
self.style = style.into();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> Widget<Message, Renderer> for TextInput<'a, Message>
|
||||
impl<'a, Message, Renderer> Widget<Message, Renderer>
|
||||
for TextInput<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: self::Renderer,
|
||||
Renderer: 'static + self::Renderer,
|
||||
Message: Clone + std::fmt::Debug,
|
||||
{
|
||||
fn width(&self) -> Length {
|
||||
@ -343,6 +355,7 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
_defaults: &Renderer::Defaults,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
@ -358,6 +371,7 @@ where
|
||||
&self.placeholder,
|
||||
&self.value.secure(),
|
||||
&self.state,
|
||||
&self.style,
|
||||
)
|
||||
} else {
|
||||
renderer.draw(
|
||||
@ -368,6 +382,7 @@ where
|
||||
&self.placeholder,
|
||||
&self.value,
|
||||
&self.state,
|
||||
&self.style,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -375,7 +390,7 @@ where
|
||||
fn hash_layout(&self, state: &mut Hasher) {
|
||||
use std::{any::TypeId, hash::Hash};
|
||||
|
||||
TypeId::of::<TextInput<'static, ()>>().hash(state);
|
||||
TypeId::of::<TextInput<'static, (), Renderer>>().hash(state);
|
||||
|
||||
self.width.hash(state);
|
||||
self.max_width.hash(state);
|
||||
@ -392,6 +407,9 @@ where
|
||||
/// [`TextInput`]: struct.TextInput.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer + Sized {
|
||||
/// The style supported by this renderer.
|
||||
type Style: Default;
|
||||
|
||||
/// Returns the default size of the text of the [`TextInput`].
|
||||
///
|
||||
/// [`TextInput`]: struct.TextInput.html
|
||||
@ -440,17 +458,18 @@ pub trait Renderer: crate::Renderer + Sized {
|
||||
placeholder: &str,
|
||||
value: &Value,
|
||||
state: &State,
|
||||
style: &Self::Style,
|
||||
) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> From<TextInput<'a, Message>>
|
||||
impl<'a, Message, Renderer> From<TextInput<'a, Message, Renderer>>
|
||||
for Element<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: 'static + self::Renderer,
|
||||
Message: 'static + Clone + std::fmt::Debug,
|
||||
{
|
||||
fn from(
|
||||
text_input: TextInput<'a, Message>,
|
||||
text_input: TextInput<'a, Message, Renderer>,
|
||||
) -> Element<'a, Message, Renderer> {
|
||||
Element::new(text_input)
|
||||
}
|
||||
|
@ -151,7 +151,12 @@ pub trait Application: Sized {
|
||||
Self: 'static,
|
||||
{
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
<Instance<Self> as iced_winit::Application>::run(_settings.into());
|
||||
<Instance<Self> as iced_winit::Application>::run(
|
||||
_settings.into(),
|
||||
iced_wgpu::Settings {
|
||||
default_font: _settings.default_font,
|
||||
},
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
<Instance<Self> as iced_web::Application>::run();
|
||||
|
@ -1,6 +1,6 @@
|
||||
pub use iced_winit::{
|
||||
Align, Background, Color, Command, Font, HorizontalAlignment, Length,
|
||||
Space, Subscription, VerticalAlignment,
|
||||
Space, Subscription, Vector, VerticalAlignment,
|
||||
};
|
||||
|
||||
pub mod widget {
|
||||
@ -22,58 +22,7 @@ pub mod widget {
|
||||
//!
|
||||
//! [`TextInput`]: text_input/struct.TextInput.html
|
||||
//! [`text_input::State`]: text_input/struct.State.html
|
||||
pub mod button {
|
||||
//! Allow your users to perform actions by pressing a button.
|
||||
//!
|
||||
//! A [`Button`] has some local [`State`].
|
||||
//!
|
||||
//! [`Button`]: type.Button.html
|
||||
//! [`State`]: struct.State.html
|
||||
|
||||
/// A widget that produces a message when clicked.
|
||||
///
|
||||
/// This is an alias of an `iced_native` button with a default
|
||||
/// `Renderer`.
|
||||
pub type Button<'a, Message> =
|
||||
iced_winit::Button<'a, Message, iced_wgpu::Renderer>;
|
||||
|
||||
pub use iced_winit::button::State;
|
||||
}
|
||||
|
||||
pub mod scrollable {
|
||||
//! Navigate an endless amount of content with a scrollbar.
|
||||
|
||||
/// A widget that can vertically display an infinite amount of content
|
||||
/// with a scrollbar.
|
||||
///
|
||||
/// This is an alias of an `iced_native` scrollable with a default
|
||||
/// `Renderer`.
|
||||
pub type Scrollable<'a, Message> =
|
||||
iced_winit::Scrollable<'a, Message, iced_wgpu::Renderer>;
|
||||
|
||||
pub use iced_winit::scrollable::State;
|
||||
}
|
||||
|
||||
pub mod text_input {
|
||||
//! Ask for information using text fields.
|
||||
//!
|
||||
//! A [`TextInput`] has some local [`State`].
|
||||
//!
|
||||
//! [`TextInput`]: struct.TextInput.html
|
||||
//! [`State`]: struct.State.html
|
||||
pub use iced_winit::text_input::{State, TextInput};
|
||||
}
|
||||
|
||||
pub mod slider {
|
||||
//! Display an interactive selector of a single value from a range of
|
||||
//! values.
|
||||
//!
|
||||
//! A [`Slider`] has some local [`State`].
|
||||
//!
|
||||
//! [`Slider`]: struct.Slider.html
|
||||
//! [`State`]: struct.State.html
|
||||
pub use iced_winit::slider::{Slider, State};
|
||||
}
|
||||
pub use iced_wgpu::widget::*;
|
||||
|
||||
pub mod image {
|
||||
//! Display images in your user interface.
|
||||
@ -85,12 +34,13 @@ pub mod widget {
|
||||
pub use iced_winit::svg::{Handle, Svg};
|
||||
}
|
||||
|
||||
pub use iced_winit::{Checkbox, ProgressBar, Radio, Text};
|
||||
pub use iced_winit::Text;
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use {
|
||||
button::Button, image::Image, scrollable::Scrollable, slider::Slider,
|
||||
svg::Svg, text_input::TextInput,
|
||||
button::Button, checkbox::Checkbox, container::Container, image::Image,
|
||||
progress_bar::ProgressBar, radio::Radio, scrollable::Scrollable,
|
||||
slider::Slider, svg::Svg, text_input::TextInput,
|
||||
};
|
||||
|
||||
/// A container that distributes its contents vertically.
|
||||
@ -104,13 +54,6 @@ pub mod widget {
|
||||
/// This is an alias of an `iced_native` row with a default `Renderer`.
|
||||
pub type Row<'a, Message> =
|
||||
iced_winit::Row<'a, Message, iced_wgpu::Renderer>;
|
||||
|
||||
/// An element decorating some content.
|
||||
///
|
||||
/// This is an alias of an `iced_native` container with a default
|
||||
/// `Renderer`.
|
||||
pub type Container<'a, Message> =
|
||||
iced_winit::Container<'a, Message, iced_wgpu::Renderer>;
|
||||
}
|
||||
|
||||
#[doc(no_inline)]
|
||||
|
@ -9,6 +9,12 @@ pub struct Settings {
|
||||
///
|
||||
/// [`Window`]: struct.Window.html
|
||||
pub window: Window,
|
||||
|
||||
/// The bytes of the font that will be used by default.
|
||||
///
|
||||
/// If `None` is provided, a default system font will be chosen.
|
||||
// TODO: Add `name` for web compatibility
|
||||
pub default_font: Option<&'static [u8]>,
|
||||
}
|
||||
|
||||
/// The window settings of an application.
|
||||
|
14
style/Cargo.toml
Normal file
14
style/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "iced_style"
|
||||
version = "0.1.0-alpha"
|
||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||
edition = "2018"
|
||||
description = "The default set of styles of Iced"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/hecrj/iced"
|
||||
documentation = "https://docs.rs/iced_style"
|
||||
keywords = ["gui", "ui", "graphics", "interface", "widgets"]
|
||||
categories = ["gui"]
|
||||
|
||||
[dependencies]
|
||||
iced_core = { version = "0.1.0", path = "../core" }
|
96
style/src/button.rs
Normal file
96
style/src/button.rs
Normal file
@ -0,0 +1,96 @@
|
||||
//! Allow your users to perform actions by pressing a button.
|
||||
use iced_core::{Background, Color, Vector};
|
||||
|
||||
/// The appearance of a button.
|
||||
#[derive(Debug)]
|
||||
pub struct Style {
|
||||
pub shadow_offset: Vector,
|
||||
pub background: Option<Background>,
|
||||
pub border_radius: u16,
|
||||
pub border_width: u16,
|
||||
pub border_color: Color,
|
||||
pub text_color: Color,
|
||||
}
|
||||
|
||||
impl std::default::Default for Style {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
shadow_offset: Vector::default(),
|
||||
background: None,
|
||||
border_radius: 0,
|
||||
border_width: 0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
text_color: Color::BLACK,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of rules that dictate the style of a button.
|
||||
pub trait StyleSheet {
|
||||
fn active(&self) -> Style;
|
||||
|
||||
fn hovered(&self) -> Style {
|
||||
let active = self.active();
|
||||
|
||||
Style {
|
||||
shadow_offset: active.shadow_offset + Vector::new(0.0, 1.0),
|
||||
..active
|
||||
}
|
||||
}
|
||||
|
||||
fn pressed(&self) -> Style {
|
||||
Style {
|
||||
shadow_offset: Vector::default(),
|
||||
..self.active()
|
||||
}
|
||||
}
|
||||
|
||||
fn disabled(&self) -> Style {
|
||||
let active = self.active();
|
||||
|
||||
Style {
|
||||
shadow_offset: Vector::default(),
|
||||
background: active.background.map(|background| match background {
|
||||
Background::Color(color) => Background::Color(Color {
|
||||
a: color.a * 0.5,
|
||||
..color
|
||||
}),
|
||||
}),
|
||||
text_color: Color {
|
||||
a: active.text_color.a * 0.5,
|
||||
..active.text_color
|
||||
},
|
||||
..active
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Default;
|
||||
|
||||
impl StyleSheet for Default {
|
||||
fn active(&self) -> Style {
|
||||
Style {
|
||||
shadow_offset: Vector::new(0.0, 1.0),
|
||||
background: Some(Background::Color([0.5, 0.5, 0.5].into())),
|
||||
border_radius: 5,
|
||||
border_width: 0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
text_color: Color::WHITE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
55
style/src/checkbox.rs
Normal file
55
style/src/checkbox.rs
Normal file
@ -0,0 +1,55 @@
|
||||
//! Show toggle controls using checkboxes.
|
||||
use iced_core::{Background, Color};
|
||||
|
||||
/// The appearance of a checkbox.
|
||||
#[derive(Debug)]
|
||||
pub struct Style {
|
||||
pub background: Background,
|
||||
pub checkmark_color: Color,
|
||||
pub border_radius: u16,
|
||||
pub border_width: u16,
|
||||
pub border_color: Color,
|
||||
}
|
||||
|
||||
/// A set of rules that dictate the style of a checkbox.
|
||||
pub trait StyleSheet {
|
||||
fn active(&self, is_checked: bool) -> Style;
|
||||
|
||||
fn hovered(&self, is_checked: bool) -> Style;
|
||||
}
|
||||
|
||||
struct Default;
|
||||
|
||||
impl StyleSheet for Default {
|
||||
fn active(&self, _is_checked: bool) -> Style {
|
||||
Style {
|
||||
background: Background::Color(Color::from_rgb(0.95, 0.95, 0.95)),
|
||||
checkmark_color: Color::from_rgb(0.3, 0.3, 0.3),
|
||||
border_radius: 5,
|
||||
border_width: 1,
|
||||
border_color: Color::from_rgb(0.6, 0.6, 0.6),
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self, is_checked: bool) -> Style {
|
||||
Style {
|
||||
background: Background::Color(Color::from_rgb(0.90, 0.90, 0.90)),
|
||||
..self.active(is_checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
59
style/src/container.rs
Normal file
59
style/src/container.rs
Normal file
@ -0,0 +1,59 @@
|
||||
//! Decorate content and apply alignment.
|
||||
use iced_core::{Background, Color};
|
||||
|
||||
/// The appearance of a container.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Style {
|
||||
pub text_color: Option<Color>,
|
||||
pub background: Option<Background>,
|
||||
pub border_radius: u16,
|
||||
pub border_width: u16,
|
||||
pub border_color: Color,
|
||||
}
|
||||
|
||||
impl std::default::Default for Style {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
text_color: None,
|
||||
background: None,
|
||||
border_radius: 0,
|
||||
border_width: 0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of rules that dictate the style of a container.
|
||||
pub trait StyleSheet {
|
||||
/// Produces the style of a container.
|
||||
fn style(&self) -> Style;
|
||||
}
|
||||
|
||||
struct Default;
|
||||
|
||||
impl StyleSheet for Default {
|
||||
fn style(&self) -> Style {
|
||||
Style {
|
||||
text_color: None,
|
||||
background: None,
|
||||
border_radius: 0,
|
||||
border_width: 0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
8
style/src/lib.rs
Normal file
8
style/src/lib.rs
Normal file
@ -0,0 +1,8 @@
|
||||
pub mod button;
|
||||
pub mod checkbox;
|
||||
pub mod container;
|
||||
pub mod progress_bar;
|
||||
pub mod radio;
|
||||
pub mod scrollable;
|
||||
pub mod slider;
|
||||
pub mod text_input;
|
42
style/src/progress_bar.rs
Normal file
42
style/src/progress_bar.rs
Normal file
@ -0,0 +1,42 @@
|
||||
//! Provide progress feedback to your users.
|
||||
use iced_core::{Background, Color};
|
||||
|
||||
/// The appearance of a progress bar.
|
||||
#[derive(Debug)]
|
||||
pub struct Style {
|
||||
pub background: Background,
|
||||
pub bar: Background,
|
||||
pub border_radius: u16,
|
||||
}
|
||||
|
||||
/// A set of rules that dictate the style of a progress bar.
|
||||
pub trait StyleSheet {
|
||||
fn style(&self) -> Style;
|
||||
}
|
||||
|
||||
struct Default;
|
||||
|
||||
impl StyleSheet for Default {
|
||||
fn style(&self) -> Style {
|
||||
Style {
|
||||
background: Background::Color(Color::from_rgb(0.6, 0.6, 0.6)),
|
||||
bar: Background::Color(Color::from_rgb(0.3, 0.9, 0.3)),
|
||||
border_radius: 5,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
53
style/src/radio.rs
Normal file
53
style/src/radio.rs
Normal file
@ -0,0 +1,53 @@
|
||||
//! Create choices using radio buttons.
|
||||
use iced_core::{Background, Color};
|
||||
|
||||
/// The appearance of a radio button.
|
||||
#[derive(Debug)]
|
||||
pub struct Style {
|
||||
pub background: Background,
|
||||
pub dot_color: Color,
|
||||
pub border_width: u16,
|
||||
pub border_color: Color,
|
||||
}
|
||||
|
||||
/// A set of rules that dictate the style of a radio button.
|
||||
pub trait StyleSheet {
|
||||
fn active(&self) -> Style;
|
||||
|
||||
fn hovered(&self) -> Style;
|
||||
}
|
||||
|
||||
struct Default;
|
||||
|
||||
impl StyleSheet for Default {
|
||||
fn active(&self) -> Style {
|
||||
Style {
|
||||
background: Background::Color(Color::from_rgb(0.95, 0.95, 0.95)),
|
||||
dot_color: Color::from_rgb(0.3, 0.3, 0.3),
|
||||
border_width: 1,
|
||||
border_color: Color::from_rgb(0.6, 0.6, 0.6),
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self) -> Style {
|
||||
Style {
|
||||
background: Background::Color(Color::from_rgb(0.90, 0.90, 0.90)),
|
||||
..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)
|
||||
}
|
||||
}
|
76
style/src/scrollable.rs
Normal file
76
style/src/scrollable.rs
Normal file
@ -0,0 +1,76 @@
|
||||
//! Navigate an endless amount of content with a scrollbar.
|
||||
use iced_core::{Background, Color};
|
||||
|
||||
/// The appearance of a scrollable.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Scrollbar {
|
||||
pub background: Option<Background>,
|
||||
pub border_radius: u16,
|
||||
pub border_width: u16,
|
||||
pub border_color: Color,
|
||||
pub scroller: Scroller,
|
||||
}
|
||||
|
||||
/// The appearance of the scroller of a scrollable.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Scroller {
|
||||
pub color: Color,
|
||||
pub border_radius: u16,
|
||||
pub border_width: u16,
|
||||
pub border_color: Color,
|
||||
}
|
||||
|
||||
/// A set of rules that dictate the style of a scrollable.
|
||||
pub trait StyleSheet {
|
||||
/// Produces the style of an active scrollbar.
|
||||
fn active(&self) -> Scrollbar;
|
||||
|
||||
/// Produces the style of an hovered scrollbar.
|
||||
fn hovered(&self) -> Scrollbar;
|
||||
|
||||
/// Produces the style of a scrollbar that is being dragged.
|
||||
fn dragging(&self) -> Scrollbar {
|
||||
self.hovered()
|
||||
}
|
||||
}
|
||||
|
||||
struct Default;
|
||||
|
||||
impl StyleSheet for Default {
|
||||
fn active(&self) -> Scrollbar {
|
||||
Scrollbar {
|
||||
background: None,
|
||||
border_radius: 5,
|
||||
border_width: 0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
scroller: Scroller {
|
||||
color: [0.0, 0.0, 0.0, 0.7].into(),
|
||||
border_radius: 5,
|
||||
border_width: 0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self) -> Scrollbar {
|
||||
Scrollbar {
|
||||
background: Some(Background::Color([0.0, 0.0, 0.0, 0.3].into())),
|
||||
..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)
|
||||
}
|
||||
}
|
95
style/src/slider.rs
Normal file
95
style/src/slider.rs
Normal file
@ -0,0 +1,95 @@
|
||||
//! Display an interactive selector of a single value from a range of values.
|
||||
use iced_core::Color;
|
||||
|
||||
/// The appearance of a slider.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Style {
|
||||
pub rail_colors: (Color, Color),
|
||||
pub handle: Handle,
|
||||
}
|
||||
|
||||
/// The appearance of the handle of a slider.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Handle {
|
||||
pub shape: HandleShape,
|
||||
pub color: Color,
|
||||
pub border_width: u16,
|
||||
pub border_color: Color,
|
||||
}
|
||||
|
||||
/// The shape of the handle of a slider.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum HandleShape {
|
||||
Circle { radius: u16 },
|
||||
Rectangle { width: u16, border_radius: u16 },
|
||||
}
|
||||
|
||||
/// A set of rules that dictate the style of a slider.
|
||||
pub trait StyleSheet {
|
||||
/// Produces the style of an active slider.
|
||||
fn active(&self) -> Style;
|
||||
|
||||
/// Produces the style of an hovered slider.
|
||||
fn hovered(&self) -> Style;
|
||||
|
||||
/// Produces the style of a slider that is being dragged.
|
||||
fn dragging(&self) -> Style;
|
||||
}
|
||||
|
||||
struct Default;
|
||||
|
||||
impl StyleSheet for Default {
|
||||
fn active(&self) -> Style {
|
||||
Style {
|
||||
rail_colors: ([0.6, 0.6, 0.6, 0.5].into(), Color::WHITE),
|
||||
handle: Handle {
|
||||
shape: HandleShape::Rectangle {
|
||||
width: 8,
|
||||
border_radius: 4,
|
||||
},
|
||||
color: Color::from_rgb(0.95, 0.95, 0.95),
|
||||
border_color: Color::from_rgb(0.6, 0.6, 0.6),
|
||||
border_width: 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self) -> Style {
|
||||
let active = self.active();
|
||||
|
||||
Style {
|
||||
handle: Handle {
|
||||
color: Color::from_rgb(0.90, 0.90, 0.90),
|
||||
..active.handle
|
||||
},
|
||||
..active
|
||||
}
|
||||
}
|
||||
|
||||
fn dragging(&self) -> Style {
|
||||
let active = self.active();
|
||||
|
||||
Style {
|
||||
handle: Handle {
|
||||
color: Color::from_rgb(0.85, 0.85, 0.85),
|
||||
..active.handle
|
||||
},
|
||||
..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)
|
||||
}
|
||||
}
|
83
style/src/text_input.rs
Normal file
83
style/src/text_input.rs
Normal file
@ -0,0 +1,83 @@
|
||||
//! Display fields that can be filled with text.
|
||||
use iced_core::{Background, Color};
|
||||
|
||||
/// The appearance of a text input.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Style {
|
||||
pub background: Background,
|
||||
pub border_radius: u16,
|
||||
pub border_width: u16,
|
||||
pub border_color: Color,
|
||||
}
|
||||
|
||||
impl std::default::Default for Style {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
background: Background::Color(Color::WHITE),
|
||||
border_radius: 0,
|
||||
border_width: 0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of rules that dictate the style of a text input.
|
||||
pub trait StyleSheet {
|
||||
/// Produces the style of an active text input.
|
||||
fn active(&self) -> Style;
|
||||
|
||||
/// Produces the style of a focused text input.
|
||||
fn focused(&self) -> Style;
|
||||
|
||||
fn placeholder_color(&self) -> Color;
|
||||
|
||||
fn value_color(&self) -> Color;
|
||||
|
||||
/// Produces the style of an hovered text input.
|
||||
fn hovered(&self) -> Style {
|
||||
self.focused()
|
||||
}
|
||||
}
|
||||
|
||||
struct Default;
|
||||
|
||||
impl StyleSheet for Default {
|
||||
fn active(&self) -> Style {
|
||||
Style {
|
||||
background: Background::Color(Color::WHITE),
|
||||
border_radius: 5,
|
||||
border_width: 1,
|
||||
border_color: Color::from_rgb(0.7, 0.7, 0.7),
|
||||
}
|
||||
}
|
||||
|
||||
fn focused(&self) -> Style {
|
||||
Style {
|
||||
border_color: Color::from_rgb(0.5, 0.5, 0.5),
|
||||
..self.active()
|
||||
}
|
||||
}
|
||||
|
||||
fn placeholder_color(&self) -> Color {
|
||||
Color::from_rgb(0.7, 0.7, 0.7)
|
||||
}
|
||||
|
||||
fn value_color(&self) -> Color {
|
||||
Color::from_rgb(0.3, 0.3, 0.3)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
@ -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" }
|
||||
|
32
wgpu/src/defaults.rs
Normal file
32
wgpu/src/defaults.rs
Normal file
@ -0,0 +1,32 @@
|
||||
//! Use default styling attributes to inherit styles.
|
||||
use iced_native::Color;
|
||||
|
||||
/// Some default styling attributes.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Defaults {
|
||||
/// Text styling
|
||||
pub text: Text,
|
||||
}
|
||||
|
||||
impl Default for Defaults {
|
||||
fn default() -> Defaults {
|
||||
Defaults {
|
||||
text: Text::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Some default text styling attributes.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Text {
|
||||
/// The default color of text
|
||||
pub color: Color,
|
||||
}
|
||||
|
||||
impl Default for Text {
|
||||
fn default() -> Text {
|
||||
Text {
|
||||
color: Color::BLACK,
|
||||
}
|
||||
}
|
||||
}
|
@ -24,18 +24,25 @@
|
||||
#![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;
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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() {
|
||||
|
@ -1,6 +1,7 @@
|
||||
mod button;
|
||||
mod checkbox;
|
||||
mod column;
|
||||
mod container;
|
||||
mod image;
|
||||
mod progress_bar;
|
||||
mod radio;
|
||||
|
@ -1,54 +1,86 @@
|
||||
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()
|
||||
};
|
||||
|
||||
(
|
||||
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,
|
||||
},
|
||||
content,
|
||||
],
|
||||
let (content, _) = content.draw(
|
||||
self,
|
||||
&Defaults {
|
||||
text: defaults::Text {
|
||||
color: styling.text_color,
|
||||
},
|
||||
..*defaults
|
||||
},
|
||||
content_layout,
|
||||
cursor_position,
|
||||
);
|
||||
|
||||
(
|
||||
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
|
||||
},
|
||||
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
|
||||
|
@ -1,12 +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 {
|
||||
type Style = Box<dyn StyleSheet>;
|
||||
|
||||
fn default_size(&self) -> u32 {
|
||||
SIZE as u32
|
||||
}
|
||||
@ -17,31 +18,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 +42,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 {
|
||||
|
@ -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;
|
||||
|
49
wgpu/src/renderer/widget/container.rs
Normal file
49
wgpu/src/renderer/widget/container.rs
Normal file
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
use crate::{Primitive, Renderer};
|
||||
use iced_native::{progress_bar, Background, Color, MouseCursor, Rectangle};
|
||||
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(
|
||||
@ -9,9 +11,10 @@ impl progress_bar::Renderer for Renderer {
|
||||
bounds: Rectangle,
|
||||
range: std::ops::RangeInclusive<f32>,
|
||||
value: f32,
|
||||
background: Option<Background>,
|
||||
active_color: Option<Color>,
|
||||
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));
|
||||
@ -19,27 +22,31 @@ impl progress_bar::Renderer for Renderer {
|
||||
let background = Primitive::Group {
|
||||
primitives: vec![Primitive::Quad {
|
||||
bounds: Rectangle { ..bounds },
|
||||
background: background
|
||||
.unwrap_or(Background::Color([0.6, 0.6, 0.6].into()))
|
||||
.into(),
|
||||
border_radius: 5,
|
||||
background: style.background,
|
||||
border_radius: style.border_radius,
|
||||
border_width: 0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}],
|
||||
};
|
||||
|
||||
let active_progress = Primitive::Quad {
|
||||
bounds: Rectangle {
|
||||
width: active_progress_width,
|
||||
..bounds
|
||||
},
|
||||
background: Background::Color(
|
||||
active_color.unwrap_or([0.0, 0.95, 0.0].into()),
|
||||
),
|
||||
border_radius: 5,
|
||||
};
|
||||
|
||||
(
|
||||
Primitive::Group {
|
||||
primitives: vec![background, active_progress],
|
||||
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,
|
||||
)
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -1,10 +1,14 @@
|
||||
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;
|
||||
|
||||
impl scrollable::Renderer for Renderer {
|
||||
type Style = Box<dyn iced_style::scrollable::StyleSheet>;
|
||||
|
||||
fn scrollbar(
|
||||
&self,
|
||||
bounds: Rectangle,
|
||||
@ -51,6 +55,7 @@ impl scrollable::Renderer for Renderer {
|
||||
is_mouse_over_scrollbar: bool,
|
||||
scrollbar: Option<scrollable::Scrollbar>,
|
||||
offset: u32,
|
||||
style_sheet: &Self::Style,
|
||||
(content, mouse_cursor): Self::Output,
|
||||
) -> Self::Output {
|
||||
let clip = Primitive::Clip {
|
||||
@ -61,40 +66,53 @@ impl scrollable::Renderer for Renderer {
|
||||
|
||||
(
|
||||
if let Some(scrollbar) = scrollbar {
|
||||
if is_mouse_over || state.is_scroller_grabbed() {
|
||||
let scroller = Primitive::Quad {
|
||||
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 scroller = if is_mouse_over
|
||||
|| state.is_scroller_grabbed()
|
||||
|| is_scrollbar_visible
|
||||
{
|
||||
Primitive::Quad {
|
||||
bounds: scrollbar.scroller.bounds,
|
||||
background: Background::Color(
|
||||
[0.0, 0.0, 0.0, 0.7].into(),
|
||||
),
|
||||
border_radius: 5,
|
||||
};
|
||||
|
||||
if is_mouse_over_scrollbar || state.is_scroller_grabbed() {
|
||||
let scrollbar = Primitive::Quad {
|
||||
bounds: Rectangle {
|
||||
x: scrollbar.bounds.x
|
||||
+ f32::from(SCROLLBAR_MARGIN),
|
||||
width: scrollbar.bounds.width
|
||||
- f32::from(2 * SCROLLBAR_MARGIN),
|
||||
..scrollbar.bounds
|
||||
},
|
||||
background: Background::Color(
|
||||
[0.0, 0.0, 0.0, 0.3].into(),
|
||||
),
|
||||
border_radius: 5,
|
||||
};
|
||||
|
||||
Primitive::Group {
|
||||
primitives: vec![clip, scrollbar, scroller],
|
||||
}
|
||||
} else {
|
||||
Primitive::Group {
|
||||
primitives: vec![clip, scroller],
|
||||
}
|
||||
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 {
|
||||
clip
|
||||
Primitive::None
|
||||
};
|
||||
|
||||
let scrollbar = if is_scrollbar_visible {
|
||||
Primitive::Quad {
|
||||
bounds: Rectangle {
|
||||
x: scrollbar.bounds.x + f32::from(SCROLLBAR_MARGIN),
|
||||
width: scrollbar.bounds.width
|
||||
- f32::from(2 * SCROLLBAR_MARGIN),
|
||||
..scrollbar.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,
|
||||
}
|
||||
} else {
|
||||
Primitive::None
|
||||
};
|
||||
|
||||
Primitive::Group {
|
||||
primitives: vec![clip, scrollbar, scroller],
|
||||
}
|
||||
} else {
|
||||
clip
|
||||
|
@ -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: Color::from_rgb(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: Color::from_rgb(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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
10
wgpu/src/settings.rs
Normal file
10
wgpu/src/settings.rs
Normal file
@ -0,0 +1,10 @@
|
||||
/// The settings of a [`Renderer`].
|
||||
///
|
||||
/// [`Renderer`]: struct.Renderer.html
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub struct Settings {
|
||||
/// The bytes of the font that will be used by default.
|
||||
///
|
||||
/// If `None` is provided, a default system font will be chosen.
|
||||
pub default_font: Option<&'static [u8]>,
|
||||
}
|
@ -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;
|
||||
|
||||
o_Color = vec4(v_Color.xyz, v_Color.w * radius_alpha);
|
||||
// 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(mixed_color.xyz, mixed_color.w * radius_alpha);
|
||||
}
|
||||
|
Binary file not shown.
@ -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);
|
||||
}
|
||||
|
Binary file not shown.
@ -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 =
|
||||
|
34
wgpu/src/widget.rs
Normal file
34
wgpu/src/widget.rs
Normal file
@ -0,0 +1,34 @@
|
||||
//! Use the widgets supported out-of-the-box.
|
||||
//!
|
||||
//! # Re-exports
|
||||
//! For convenience, the contents of this module are available at the root
|
||||
//! module. Therefore, you can directly type:
|
||||
//!
|
||||
//! ```
|
||||
//! use iced_wgpu::{button, Button};
|
||||
//! ```
|
||||
pub mod button;
|
||||
pub mod checkbox;
|
||||
pub mod container;
|
||||
pub mod progress_bar;
|
||||
pub mod radio;
|
||||
pub mod scrollable;
|
||||
pub mod slider;
|
||||
pub mod text_input;
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use button::Button;
|
||||
#[doc(no_inline)]
|
||||
pub use checkbox::Checkbox;
|
||||
#[doc(no_inline)]
|
||||
pub use container::Container;
|
||||
#[doc(no_inline)]
|
||||
pub use progress_bar::ProgressBar;
|
||||
#[doc(no_inline)]
|
||||
pub use radio::Radio;
|
||||
#[doc(no_inline)]
|
||||
pub use scrollable::Scrollable;
|
||||
#[doc(no_inline)]
|
||||
pub use slider::Slider;
|
||||
#[doc(no_inline)]
|
||||
pub use text_input::TextInput;
|
15
wgpu/src/widget/button.rs
Normal file
15
wgpu/src/widget/button.rs
Normal file
@ -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>;
|
9
wgpu/src/widget/checkbox.rs
Normal file
9
wgpu/src/widget/checkbox.rs
Normal file
@ -0,0 +1,9 @@
|
||||
//! Show toggle controls using checkboxes.
|
||||
use crate::Renderer;
|
||||
|
||||
pub use iced_style::checkbox::{Style, StyleSheet};
|
||||
|
||||
/// A box that can be checked.
|
||||
///
|
||||
/// This is an alias of an `iced_native` checkbox with an `iced_wgpu::Renderer`.
|
||||
pub type Checkbox<Message> = iced_native::Checkbox<Message, Renderer>;
|
10
wgpu/src/widget/container.rs
Normal file
10
wgpu/src/widget/container.rs
Normal file
@ -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>;
|
15
wgpu/src/widget/progress_bar.rs
Normal file
15
wgpu/src/widget/progress_bar.rs
Normal file
@ -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_style::progress_bar::{Style, StyleSheet};
|
||||
|
||||
/// A bar that displays progress.
|
||||
///
|
||||
/// This is an alias of an `iced_native` progress bar with an
|
||||
/// `iced_wgpu::Renderer`.
|
||||
pub type ProgressBar = iced_native::ProgressBar<Renderer>;
|
10
wgpu/src/widget/radio.rs
Normal file
10
wgpu/src/widget/radio.rs
Normal file
@ -0,0 +1,10 @@
|
||||
//! Create choices using radio buttons.
|
||||
use crate::Renderer;
|
||||
|
||||
pub use iced_style::radio::{Style, StyleSheet};
|
||||
|
||||
/// A circular button representing a choice.
|
||||
///
|
||||
/// This is an alias of an `iced_native` radio button with an
|
||||
/// `iced_wgpu::Renderer`.
|
||||
pub type Radio<Message> = iced_native::Radio<Message, Renderer>;
|
13
wgpu/src/widget/scrollable.rs
Normal file
13
wgpu/src/widget/scrollable.rs
Normal file
@ -0,0 +1,13 @@
|
||||
//! Navigate an endless amount of content with a scrollbar.
|
||||
use crate::Renderer;
|
||||
|
||||
pub use iced_native::scrollable::State;
|
||||
pub use iced_style::scrollable::{Scrollbar, Scroller, StyleSheet};
|
||||
|
||||
/// A widget that can vertically display an infinite amount of content
|
||||
/// with a scrollbar.
|
||||
///
|
||||
/// This is an alias of an `iced_native` scrollable with a default
|
||||
/// `Renderer`.
|
||||
pub type Scrollable<'a, Message> =
|
||||
iced_native::Scrollable<'a, Message, Renderer>;
|
16
wgpu/src/widget/slider.rs
Normal file
16
wgpu/src/widget/slider.rs
Normal file
@ -0,0 +1,16 @@
|
||||
//! Display an interactive selector of a single value from a range of values.
|
||||
//!
|
||||
//! A [`Slider`] has some local [`State`].
|
||||
//!
|
||||
//! [`Slider`]: struct.Slider.html
|
||||
//! [`State`]: struct.State.html
|
||||
use crate::Renderer;
|
||||
|
||||
pub use iced_native::slider::State;
|
||||
pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet};
|
||||
|
||||
/// An horizontal bar and a handle that selects a single value from a range of
|
||||
/// values.
|
||||
///
|
||||
/// This is an alias of an `iced_native` slider with an `iced_wgpu::Renderer`.
|
||||
pub type Slider<'a, Message> = iced_native::Slider<'a, Message, Renderer>;
|
15
wgpu/src/widget/text_input.rs
Normal file
15
wgpu/src/widget/text_input.rs
Normal file
@ -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>;
|
@ -6,6 +6,9 @@ edition = "2018"
|
||||
description = "A winit runtime for Iced"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/hecrj/iced"
|
||||
documentation = "https://docs.rs/iced_winit"
|
||||
keywords = ["gui", "ui", "graphics", "interface", "widgets"]
|
||||
categories = ["gui"]
|
||||
|
||||
[features]
|
||||
debug = []
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
conversion,
|
||||
container, conversion,
|
||||
input::{keyboard, mouse},
|
||||
renderer::{Target, Windowed},
|
||||
subscription, Cache, Clipboard, Command, Container, Debug, Element, Event,
|
||||
@ -18,7 +18,7 @@ pub trait Application: Sized {
|
||||
/// The renderer to use to draw the [`Application`].
|
||||
///
|
||||
/// [`Application`]: trait.Application.html
|
||||
type Renderer: Windowed;
|
||||
type Renderer: Windowed + container::Renderer;
|
||||
|
||||
/// The type of __messages__ your [`Application`] will produce.
|
||||
///
|
||||
@ -81,8 +81,10 @@ pub trait Application: Sized {
|
||||
/// It should probably be that last thing you call in your `main` function.
|
||||
///
|
||||
/// [`Application`]: trait.Application.html
|
||||
fn run(settings: Settings)
|
||||
where
|
||||
fn run(
|
||||
settings: Settings,
|
||||
renderer_settings: <Self::Renderer as Windowed>::Settings,
|
||||
) where
|
||||
Self: 'static,
|
||||
{
|
||||
use winit::{
|
||||
@ -140,7 +142,7 @@ pub trait Application: Sized {
|
||||
let mut resized = false;
|
||||
|
||||
let clipboard = Clipboard::new(&window);
|
||||
let mut renderer = Self::Renderer::new();
|
||||
let mut renderer = Self::Renderer::new(renderer_settings);
|
||||
|
||||
let mut target = {
|
||||
let (width, height) = to_physical(size, dpi);
|
||||
|
@ -1,5 +1,4 @@
|
||||
//! Configure your application.
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[path = "windows.rs"]
|
||||
mod platform;
|
||||
@ -10,7 +9,7 @@ mod platform;
|
||||
pub use platform::PlatformSpecific;
|
||||
|
||||
/// The settings of an application.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Settings {
|
||||
/// The [`Window`] settings
|
||||
///
|
||||
@ -18,6 +17,14 @@ pub struct Settings {
|
||||
pub window: Window,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
fn default() -> Settings {
|
||||
Settings {
|
||||
window: Window::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The window settings of an application.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Window {
|
||||
|
Loading…
x
Reference in New Issue
Block a user