Merge pull request #146 from hecrj/feature/custom-styling
Custom styling
This commit is contained in:
commit
0a83024505
81 changed files with 2293 additions and 600 deletions
|
|
@ -24,6 +24,7 @@ maintenance = { status = "actively-developed" }
|
||||||
members = [
|
members = [
|
||||||
"core",
|
"core",
|
||||||
"native",
|
"native",
|
||||||
|
"style",
|
||||||
"web",
|
"web",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
"winit",
|
"winit",
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,21 @@ impl Color {
|
||||||
a: 1.0,
|
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.
|
/// Creates a [`Color`] from its RGB8 components.
|
||||||
///
|
///
|
||||||
/// [`Color`]: struct.Color.html
|
/// [`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.
|
/// Converts the [`Color`] into its linear values.
|
||||||
///
|
///
|
||||||
/// [`Color`]: struct.Color.html
|
/// [`Color`]: struct.Color.html
|
||||||
|
|
|
||||||
|
|
@ -31,3 +31,15 @@ where
|
||||||
Self::new(self.x + b.x, self.y + b.y)
|
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,
|
layout, Background, Color, Element, Hasher, Layout, Length,
|
||||||
MouseCursor, Point, Size, Widget,
|
MouseCursor, Point, Size, Widget,
|
||||||
};
|
};
|
||||||
use iced_wgpu::{Primitive, Renderer};
|
use iced_wgpu::{Defaults, Primitive, Renderer};
|
||||||
|
|
||||||
pub struct Circle {
|
pub struct Circle {
|
||||||
radius: u16,
|
radius: u16,
|
||||||
|
|
@ -54,6 +54,7 @@ mod circle {
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
_renderer: &mut Renderer,
|
_renderer: &mut Renderer,
|
||||||
|
_defaults: &Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
_cursor_position: Point,
|
_cursor_position: Point,
|
||||||
) -> (Primitive, MouseCursor) {
|
) -> (Primitive, MouseCursor) {
|
||||||
|
|
@ -62,6 +63,8 @@ mod circle {
|
||||||
bounds: layout.bounds(),
|
bounds: layout.bounds(),
|
||||||
background: Background::Color(Color::BLACK),
|
background: Background::Color(Color::BLACK),
|
||||||
border_radius: self.radius,
|
border_radius: self.radius,
|
||||||
|
border_width: 0,
|
||||||
|
border_color: Color::TRANSPARENT,
|
||||||
},
|
},
|
||||||
MouseCursor::OutOfBounds,
|
MouseCursor::OutOfBounds,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ mod rainbow {
|
||||||
};
|
};
|
||||||
use iced_wgpu::{
|
use iced_wgpu::{
|
||||||
triangle::{Mesh2D, Vertex2D},
|
triangle::{Mesh2D, Vertex2D},
|
||||||
Primitive, Renderer,
|
Defaults, Primitive, Renderer,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Rainbow;
|
pub struct Rainbow;
|
||||||
|
|
@ -51,6 +51,7 @@ mod rainbow {
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
_renderer: &mut Renderer,
|
_renderer: &mut Renderer,
|
||||||
|
_defaults: &Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
) -> (Primitive, MouseCursor) {
|
) -> (Primitive, MouseCursor) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use iced::{
|
use iced::{
|
||||||
button, image, Align, Application, Button, Color, Column, Command,
|
button, image, Align, Application, Button, Column, Command, Container,
|
||||||
Container, Element, Image, Length, Row, Settings, Text,
|
Element, Image, Length, Row, Settings, Text,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main() {
|
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> {
|
fn button<'a>(state: &'a mut button::State, text: &str) -> Button<'a, Message> {
|
||||||
Button::new(state, Text::new(text).color(Color::WHITE))
|
Button::new(state, Text::new(text))
|
||||||
.background(Color::from_rgb(0.11, 0.42, 0.87))
|
|
||||||
.border_radius(10)
|
|
||||||
.padding(10)
|
.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::{
|
use iced::{slider, Column, Element, ProgressBar, Sandbox, Settings, Slider};
|
||||||
settings::Window, slider, Background, Color, Column, Element, Length,
|
|
||||||
ProgressBar, Sandbox, Settings, Slider,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
Progress::run(Settings {
|
Progress::run(Settings::default())
|
||||||
window: Window {
|
|
||||||
size: (700, 300),
|
|
||||||
resizable: true,
|
|
||||||
decorations: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -44,14 +35,7 @@ impl Sandbox for Progress {
|
||||||
fn view(&mut self) -> Element<Message> {
|
fn view(&mut self) -> Element<Message> {
|
||||||
Column::new()
|
Column::new()
|
||||||
.padding(20)
|
.padding(20)
|
||||||
.push(
|
.push(ProgressBar::new(0.0..=100.0, self.value))
|
||||||
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(Slider::new(
|
.push(Slider::new(
|
||||||
&mut self.progress_bar_slider,
|
&mut self.progress_bar_slider,
|
||||||
0.0..=100.0,
|
0.0..=100.0,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use iced::{
|
use iced::{
|
||||||
button, Align, Application, Background, Button, Color, Column, Command,
|
button, Align, Application, Button, Column, Command, Container, Element,
|
||||||
Container, Element, HorizontalAlignment, Length, Row, Settings,
|
HorizontalAlignment, Length, Row, Settings, Subscription, Text,
|
||||||
Subscription, Text,
|
|
||||||
};
|
};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
|
@ -98,30 +97,29 @@ impl Application for Stopwatch {
|
||||||
))
|
))
|
||||||
.size(40);
|
.size(40);
|
||||||
|
|
||||||
let button = |state, label, color: [f32; 3]| {
|
let button = |state, label, style| {
|
||||||
Button::new(
|
Button::new(
|
||||||
state,
|
state,
|
||||||
Text::new(label)
|
Text::new(label)
|
||||||
.color(Color::WHITE)
|
|
||||||
.horizontal_alignment(HorizontalAlignment::Center),
|
.horizontal_alignment(HorizontalAlignment::Center),
|
||||||
)
|
)
|
||||||
.min_width(80)
|
.min_width(80)
|
||||||
.background(Background::Color(color.into()))
|
|
||||||
.border_radius(10)
|
|
||||||
.padding(10)
|
.padding(10)
|
||||||
|
.style(style)
|
||||||
};
|
};
|
||||||
|
|
||||||
let toggle_button = {
|
let toggle_button = {
|
||||||
let (label, color) = match self.state {
|
let (label, color) = match self.state {
|
||||||
State::Idle => ("Start", [0.11, 0.42, 0.87]),
|
State::Idle => ("Start", style::Button::Primary),
|
||||||
State::Ticking { .. } => ("Stop", [0.9, 0.4, 0.4]),
|
State::Ticking { .. } => ("Stop", style::Button::Destructive),
|
||||||
};
|
};
|
||||||
|
|
||||||
button(&mut self.toggle, label, color).on_press(Message::Toggle)
|
button(&mut self.toggle, label, color).on_press(Message::Toggle)
|
||||||
};
|
};
|
||||||
|
|
||||||
let reset_button = button(&mut self.reset, "Reset", [0.7, 0.7, 0.7])
|
let reset_button =
|
||||||
.on_press(Message::Reset);
|
button(&mut self.reset, "Reset", style::Button::Secondary)
|
||||||
|
.on_press(Message::Reset);
|
||||||
|
|
||||||
let controls = Row::new()
|
let controls = Row::new()
|
||||||
.spacing(20)
|
.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::{
|
use iced::{
|
||||||
button, scrollable, text_input, Align, Application, Button, Checkbox,
|
button, scrollable, text_input, Align, Application, Button, Checkbox,
|
||||||
Color, Column, Command, Container, Element, Font, HorizontalAlignment,
|
Column, Command, Container, Element, Font, HorizontalAlignment, Length,
|
||||||
Length, Row, Scrollable, Settings, Text, TextInput,
|
Row, Scrollable, Settings, Text, TextInput,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
|
@ -293,12 +293,10 @@ impl Task {
|
||||||
.align_items(Align::Center)
|
.align_items(Align::Center)
|
||||||
.push(checkbox)
|
.push(checkbox)
|
||||||
.push(
|
.push(
|
||||||
Button::new(
|
Button::new(edit_button, edit_icon())
|
||||||
edit_button,
|
.on_press(TaskMessage::Edit)
|
||||||
edit_icon().color([0.5, 0.5, 0.5]),
|
.padding(10)
|
||||||
)
|
.style(style::Button::Icon),
|
||||||
.on_press(TaskMessage::Edit)
|
|
||||||
.padding(10),
|
|
||||||
)
|
)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
@ -324,13 +322,12 @@ impl Task {
|
||||||
delete_button,
|
delete_button,
|
||||||
Row::new()
|
Row::new()
|
||||||
.spacing(10)
|
.spacing(10)
|
||||||
.push(delete_icon().color(Color::WHITE))
|
.push(delete_icon())
|
||||||
.push(Text::new("Delete").color(Color::WHITE)),
|
.push(Text::new("Delete")),
|
||||||
)
|
)
|
||||||
.on_press(TaskMessage::Delete)
|
.on_press(TaskMessage::Delete)
|
||||||
.padding(10)
|
.padding(10)
|
||||||
.border_radius(5)
|
.style(style::Button::Destructive),
|
||||||
.background(Color::from_rgb(0.8, 0.2, 0.2)),
|
|
||||||
)
|
)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
@ -357,17 +354,12 @@ impl Controls {
|
||||||
|
|
||||||
let filter_button = |state, label, filter, current_filter| {
|
let filter_button = |state, label, filter, current_filter| {
|
||||||
let label = Text::new(label).size(16);
|
let label = Text::new(label).size(16);
|
||||||
let button = if filter == current_filter {
|
let button =
|
||||||
Button::new(state, label.color(Color::WHITE))
|
Button::new(state, label).style(style::Button::Filter {
|
||||||
.background(Color::from_rgb(0.2, 0.2, 0.7))
|
selected: filter == current_filter,
|
||||||
} else {
|
});
|
||||||
Button::new(state, label)
|
|
||||||
};
|
|
||||||
|
|
||||||
button
|
button.on_press(Message::FilterChanged(filter)).padding(8)
|
||||||
.on_press(Message::FilterChanged(filter))
|
|
||||||
.padding(8)
|
|
||||||
.border_radius(10)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Row::new()
|
Row::new()
|
||||||
|
|
@ -560,3 +552,63 @@ impl SavedState {
|
||||||
Ok(())
|
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() {
|
if steps.has_previous() {
|
||||||
controls = controls.push(
|
controls = controls.push(
|
||||||
secondary_button(back_button, "Back")
|
button(back_button, "Back")
|
||||||
.on_press(Message::BackPressed),
|
.on_press(Message::BackPressed)
|
||||||
|
.style(style::Button::Secondary),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,8 +72,9 @@ impl Sandbox for Tour {
|
||||||
|
|
||||||
if steps.can_continue() {
|
if steps.can_continue() {
|
||||||
controls = controls.push(
|
controls = controls.push(
|
||||||
primary_button(next_button, "Next")
|
button(next_button, "Next")
|
||||||
.on_press(Message::NextPressed),
|
.on_press(Message::NextPressed)
|
||||||
|
.style(style::Button::Primary),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -698,29 +700,12 @@ fn button<'a, Message>(
|
||||||
) -> Button<'a, Message> {
|
) -> Button<'a, Message> {
|
||||||
Button::new(
|
Button::new(
|
||||||
state,
|
state,
|
||||||
Text::new(label)
|
Text::new(label).horizontal_alignment(HorizontalAlignment::Center),
|
||||||
.color(Color::WHITE)
|
|
||||||
.horizontal_alignment(HorizontalAlignment::Center),
|
|
||||||
)
|
)
|
||||||
.padding(12)
|
.padding(12)
|
||||||
.border_radius(12)
|
|
||||||
.min_width(100)
|
.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)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Language {
|
pub enum Language {
|
||||||
Rust,
|
Rust,
|
||||||
|
|
@ -763,6 +748,38 @@ pub enum Layout {
|
||||||
Column,
|
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
|
// 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
|
// own proc macro, or maybe the whole process is streamlined by `wasm-pack` at
|
||||||
// some point.
|
// some point.
|
||||||
|
|
|
||||||
|
|
@ -235,10 +235,12 @@ where
|
||||||
pub fn draw(
|
pub fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> 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) {
|
pub(crate) fn hash_layout(&self, state: &mut Hasher) {
|
||||||
|
|
@ -316,10 +318,12 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
self.widget.draw(renderer, layout, cursor_position)
|
self.widget
|
||||||
|
.draw(renderer, defaults, layout, cursor_position)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_layout(&self, state: &mut Hasher) {
|
fn hash_layout(&self, state: &mut Hasher) {
|
||||||
|
|
@ -384,10 +388,12 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
renderer.explain(
|
renderer.explain(
|
||||||
|
defaults,
|
||||||
self.element.widget.as_ref(),
|
self.element.widget.as_ref(),
|
||||||
layout,
|
layout,
|
||||||
cursor_position,
|
cursor_position,
|
||||||
|
|
|
||||||
|
|
@ -21,14 +21,15 @@
|
||||||
//! [`checkbox::Renderer`]: ../widget/checkbox/trait.Renderer.html
|
//! [`checkbox::Renderer`]: ../widget/checkbox/trait.Renderer.html
|
||||||
|
|
||||||
mod debugger;
|
mod debugger;
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
mod null;
|
|
||||||
mod windowed;
|
mod windowed;
|
||||||
|
|
||||||
pub use debugger::Debugger;
|
pub use debugger::Debugger;
|
||||||
|
pub use windowed::{Target, Windowed};
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
mod null;
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
pub use null::Null;
|
pub use null::Null;
|
||||||
pub use windowed::{Target, Windowed};
|
|
||||||
|
|
||||||
use crate::{layout, Element};
|
use crate::{layout, Element};
|
||||||
|
|
||||||
|
|
@ -43,6 +44,13 @@ pub trait Renderer: Sized {
|
||||||
/// [`Renderer`]: trait.Renderer.html
|
/// [`Renderer`]: trait.Renderer.html
|
||||||
type Output;
|
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.
|
/// Lays out the elements of a user interface.
|
||||||
///
|
///
|
||||||
/// You should override this if you need to perform any operations before or
|
/// 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
|
/// [`Element::explain`]: struct.Element.html#method.explain
|
||||||
fn explain<Message>(
|
fn explain<Message>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
defaults: &Self::Defaults,
|
||||||
widget: &dyn Widget<Message, Self>,
|
widget: &dyn Widget<Message, Self>,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,33 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
button, checkbox, column, radio, row, scrollable, text, text_input,
|
button, checkbox, column, progress_bar, radio, row, scrollable, slider,
|
||||||
Background, Color, Element, Font, HorizontalAlignment, Layout, Point,
|
text, text_input, Color, Element, Font, HorizontalAlignment, Layout, Point,
|
||||||
Rectangle, Renderer, Size, VerticalAlignment,
|
Rectangle, Renderer, Size, VerticalAlignment,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A renderer that does nothing.
|
/// A renderer that does nothing.
|
||||||
|
///
|
||||||
|
/// It can be useful if you are writing tests!
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Null;
|
pub struct Null;
|
||||||
|
|
||||||
|
impl Null {
|
||||||
|
/// Creates a new [`Null`] renderer.
|
||||||
|
///
|
||||||
|
/// [`Null`]: struct.Null.html
|
||||||
|
pub fn new() -> Null {
|
||||||
|
Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Renderer for Null {
|
impl Renderer for Null {
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
type Defaults = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl column::Renderer for Null {
|
impl column::Renderer for Null {
|
||||||
fn draw<Message>(
|
fn draw<Message>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_defaults: &Self::Defaults,
|
||||||
_content: &[Element<'_, Message, Self>],
|
_content: &[Element<'_, Message, Self>],
|
||||||
_layout: Layout<'_>,
|
_layout: Layout<'_>,
|
||||||
_cursor_position: Point,
|
_cursor_position: Point,
|
||||||
|
|
@ -25,6 +38,7 @@ impl column::Renderer for Null {
|
||||||
impl row::Renderer for Null {
|
impl row::Renderer for Null {
|
||||||
fn draw<Message>(
|
fn draw<Message>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_defaults: &Self::Defaults,
|
||||||
_content: &[Element<'_, Message, Self>],
|
_content: &[Element<'_, Message, Self>],
|
||||||
_layout: Layout<'_>,
|
_layout: Layout<'_>,
|
||||||
_cursor_position: Point,
|
_cursor_position: Point,
|
||||||
|
|
@ -49,6 +63,7 @@ impl text::Renderer for Null {
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_defaults: &Self::Defaults,
|
||||||
_bounds: Rectangle,
|
_bounds: Rectangle,
|
||||||
_content: &str,
|
_content: &str,
|
||||||
_size: u16,
|
_size: u16,
|
||||||
|
|
@ -61,6 +76,8 @@ impl text::Renderer for Null {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl scrollable::Renderer for Null {
|
impl scrollable::Renderer for Null {
|
||||||
|
type Style = ();
|
||||||
|
|
||||||
fn scrollbar(
|
fn scrollbar(
|
||||||
&self,
|
&self,
|
||||||
_bounds: Rectangle,
|
_bounds: Rectangle,
|
||||||
|
|
@ -79,12 +96,15 @@ impl scrollable::Renderer for Null {
|
||||||
_is_mouse_over_scrollbar: bool,
|
_is_mouse_over_scrollbar: bool,
|
||||||
_scrollbar: Option<scrollable::Scrollbar>,
|
_scrollbar: Option<scrollable::Scrollbar>,
|
||||||
_offset: u32,
|
_offset: u32,
|
||||||
|
_style: &Self::Style,
|
||||||
_content: Self::Output,
|
_content: Self::Output,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl text_input::Renderer for Null {
|
impl text_input::Renderer for Null {
|
||||||
|
type Style = ();
|
||||||
|
|
||||||
fn default_size(&self) -> u16 {
|
fn default_size(&self) -> u16 {
|
||||||
20
|
20
|
||||||
}
|
}
|
||||||
|
|
@ -112,24 +132,31 @@ impl text_input::Renderer for Null {
|
||||||
_placeholder: &str,
|
_placeholder: &str,
|
||||||
_value: &text_input::Value,
|
_value: &text_input::Value,
|
||||||
_state: &text_input::State,
|
_state: &text_input::State,
|
||||||
|
_style: &Self::Style,
|
||||||
) -> Self::Output {
|
) -> Self::Output {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl button::Renderer for Null {
|
impl button::Renderer for Null {
|
||||||
fn draw(
|
type Style = ();
|
||||||
|
|
||||||
|
fn draw<Message>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_defaults: &Self::Defaults,
|
||||||
_bounds: Rectangle,
|
_bounds: Rectangle,
|
||||||
_cursor_position: Point,
|
_cursor_position: Point,
|
||||||
|
_is_disabled: bool,
|
||||||
_is_pressed: bool,
|
_is_pressed: bool,
|
||||||
_background: Option<Background>,
|
_style: &Self::Style,
|
||||||
_border_radius: u16,
|
_content: &Element<'_, Message, Self>,
|
||||||
_content: Self::Output,
|
_content_layout: Layout<'_>,
|
||||||
) -> Self::Output {
|
) -> Self::Output {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl radio::Renderer for Null {
|
impl radio::Renderer for Null {
|
||||||
|
type Style = ();
|
||||||
|
|
||||||
fn default_size(&self) -> u32 {
|
fn default_size(&self) -> u32 {
|
||||||
20
|
20
|
||||||
}
|
}
|
||||||
|
|
@ -140,11 +167,14 @@ impl radio::Renderer for Null {
|
||||||
_is_selected: bool,
|
_is_selected: bool,
|
||||||
_is_mouse_over: bool,
|
_is_mouse_over: bool,
|
||||||
_label: Self::Output,
|
_label: Self::Output,
|
||||||
|
_style: &Self::Style,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl checkbox::Renderer for Null {
|
impl checkbox::Renderer for Null {
|
||||||
|
type Style = ();
|
||||||
|
|
||||||
fn default_size(&self) -> u32 {
|
fn default_size(&self) -> u32 {
|
||||||
20
|
20
|
||||||
}
|
}
|
||||||
|
|
@ -155,6 +185,41 @@ impl checkbox::Renderer for Null {
|
||||||
_is_checked: bool,
|
_is_checked: bool,
|
||||||
_is_mouse_over: bool,
|
_is_mouse_over: bool,
|
||||||
_label: Self::Output,
|
_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.
|
/// A renderer that can target windows.
|
||||||
pub trait Windowed: super::Renderer + Sized {
|
pub trait Windowed: super::Renderer + Sized {
|
||||||
|
/// The settings of the renderer.
|
||||||
|
type Settings: Default;
|
||||||
|
|
||||||
/// The type of target.
|
/// The type of target.
|
||||||
type Target: Target<Renderer = Self>;
|
type Target: Target<Renderer = Self>;
|
||||||
|
|
||||||
/// Creates a new [`Windowed`] renderer.
|
/// Creates a new [`Windowed`] renderer.
|
||||||
///
|
///
|
||||||
/// [`Windowed`]: trait.Windowed.html
|
/// [`Windowed`]: trait.Windowed.html
|
||||||
fn new() -> Self;
|
fn new(settings: Self::Settings) -> Self;
|
||||||
|
|
||||||
/// Performs the drawing operations described in the output on the given
|
/// Performs the drawing operations described in the output on the given
|
||||||
/// target.
|
/// target.
|
||||||
|
|
|
||||||
|
|
@ -43,24 +43,7 @@ where
|
||||||
/// use iced_wgpu::Renderer;
|
/// use iced_wgpu::Renderer;
|
||||||
///
|
///
|
||||||
/// # mod iced_wgpu {
|
/// # mod iced_wgpu {
|
||||||
/// # pub struct Renderer;
|
/// # pub use iced_native::renderer::Null as 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 {
|
|
||||||
/// # ()
|
|
||||||
/// # }
|
|
||||||
/// # }
|
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # use iced_native::Column;
|
/// # use iced_native::Column;
|
||||||
|
|
@ -139,24 +122,7 @@ where
|
||||||
/// use iced_wgpu::Renderer;
|
/// use iced_wgpu::Renderer;
|
||||||
///
|
///
|
||||||
/// # mod iced_wgpu {
|
/// # mod iced_wgpu {
|
||||||
/// # pub struct Renderer;
|
/// # pub use iced_native::renderer::Null as 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 {
|
|
||||||
/// # ()
|
|
||||||
/// # }
|
|
||||||
/// # }
|
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # use iced_native::Column;
|
/// # use iced_native::Column;
|
||||||
|
|
@ -241,24 +207,7 @@ where
|
||||||
/// use iced_wgpu::Renderer;
|
/// use iced_wgpu::Renderer;
|
||||||
///
|
///
|
||||||
/// # mod iced_wgpu {
|
/// # mod iced_wgpu {
|
||||||
/// # pub struct Renderer;
|
/// # pub use iced_native::renderer::Null as 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 {
|
|
||||||
/// # ()
|
|
||||||
/// # }
|
|
||||||
/// # }
|
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # use iced_native::Column;
|
/// # use iced_native::Column;
|
||||||
|
|
@ -304,6 +253,7 @@ where
|
||||||
pub fn draw(&self, renderer: &mut Renderer) -> Renderer::Output {
|
pub fn draw(&self, renderer: &mut Renderer) -> Renderer::Output {
|
||||||
self.root.widget.draw(
|
self.root.widget.draw(
|
||||||
renderer,
|
renderer,
|
||||||
|
&Renderer::Defaults::default(),
|
||||||
Layout::new(&self.layout),
|
Layout::new(&self.layout),
|
||||||
self.cursor_position,
|
self.cursor_position,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,7 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
) -> Renderer::Output;
|
) -> Renderer::Output;
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@
|
||||||
//! [`State`]: struct.State.html
|
//! [`State`]: struct.State.html
|
||||||
use crate::{
|
use crate::{
|
||||||
input::{mouse, ButtonState},
|
input::{mouse, ButtonState},
|
||||||
layout, Background, Clipboard, Element, Event, Hasher, Layout, Length,
|
layout, Clipboard, Element, Event, Hasher, Layout, Length, Point,
|
||||||
Point, Rectangle, Widget,
|
Rectangle, Widget,
|
||||||
};
|
};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
|
@ -28,7 +28,7 @@ use std::hash::Hash;
|
||||||
/// .on_press(Message::ButtonPressed);
|
/// .on_press(Message::ButtonPressed);
|
||||||
/// ```
|
/// ```
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Button<'a, Message, Renderer> {
|
pub struct Button<'a, Message, Renderer: self::Renderer> {
|
||||||
state: &'a mut State,
|
state: &'a mut State,
|
||||||
content: Element<'a, Message, Renderer>,
|
content: Element<'a, Message, Renderer>,
|
||||||
on_press: Option<Message>,
|
on_press: Option<Message>,
|
||||||
|
|
@ -37,11 +37,13 @@ pub struct Button<'a, Message, Renderer> {
|
||||||
min_width: u32,
|
min_width: u32,
|
||||||
min_height: u32,
|
min_height: u32,
|
||||||
padding: u16,
|
padding: u16,
|
||||||
background: Option<Background>,
|
style: Renderer::Style,
|
||||||
border_radius: u16,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
/// Creates a new [`Button`] with some local [`State`] and the given
|
||||||
/// content.
|
/// content.
|
||||||
///
|
///
|
||||||
|
|
@ -60,8 +62,7 @@ impl<'a, Message, Renderer> Button<'a, Message, Renderer> {
|
||||||
min_width: 0,
|
min_width: 0,
|
||||||
min_height: 0,
|
min_height: 0,
|
||||||
padding: 0,
|
padding: 0,
|
||||||
background: None,
|
style: Renderer::Style::default(),
|
||||||
border_radius: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,23 +106,6 @@ impl<'a, Message, Renderer> Button<'a, Message, Renderer> {
|
||||||
self
|
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.
|
/// Sets the message that will be produced when the [`Button`] is pressed.
|
||||||
///
|
///
|
||||||
/// [`Button`]: struct.Button.html
|
/// [`Button`]: struct.Button.html
|
||||||
|
|
@ -129,6 +113,14 @@ impl<'a, Message, Renderer> Button<'a, Message, Renderer> {
|
||||||
self.on_press = Some(msg);
|
self.on_press = Some(msg);
|
||||||
self
|
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`].
|
/// The local state of a [`Button`].
|
||||||
|
|
@ -227,22 +219,19 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
let content = self.content.draw(
|
|
||||||
renderer,
|
|
||||||
layout.children().next().unwrap(),
|
|
||||||
cursor_position,
|
|
||||||
);
|
|
||||||
|
|
||||||
renderer.draw(
|
renderer.draw(
|
||||||
|
defaults,
|
||||||
layout.bounds(),
|
layout.bounds(),
|
||||||
cursor_position,
|
cursor_position,
|
||||||
|
self.on_press.is_none(),
|
||||||
self.state.is_pressed,
|
self.state.is_pressed,
|
||||||
self.background,
|
&self.style,
|
||||||
self.border_radius,
|
&self.content,
|
||||||
content,
|
layout.children().next().unwrap(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,17 +249,22 @@ where
|
||||||
/// [`Button`]: struct.Button.html
|
/// [`Button`]: struct.Button.html
|
||||||
/// [renderer]: ../../renderer/index.html
|
/// [renderer]: ../../renderer/index.html
|
||||||
pub trait Renderer: crate::Renderer + Sized {
|
pub trait Renderer: crate::Renderer + Sized {
|
||||||
|
/// The style supported by this renderer.
|
||||||
|
type Style: Default;
|
||||||
|
|
||||||
/// Draws a [`Button`].
|
/// Draws a [`Button`].
|
||||||
///
|
///
|
||||||
/// [`Button`]: struct.Button.html
|
/// [`Button`]: struct.Button.html
|
||||||
fn draw(
|
fn draw<Message>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
defaults: &Self::Defaults,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
|
is_disabled: bool,
|
||||||
is_pressed: bool,
|
is_pressed: bool,
|
||||||
background: Option<Background>,
|
style: &Self::Style,
|
||||||
border_radius: u16,
|
content: &Element<'_, Message, Self>,
|
||||||
content: Self::Output,
|
content_layout: Layout<'_>,
|
||||||
) -> Self::Output;
|
) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::hash::Hash;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
input::{mouse, ButtonState},
|
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,
|
HorizontalAlignment, Layout, Length, Point, Rectangle, Row, Text,
|
||||||
VerticalAlignment, Widget,
|
VerticalAlignment, Widget,
|
||||||
};
|
};
|
||||||
|
|
@ -13,7 +13,7 @@ use crate::{
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use iced_native::Checkbox;
|
/// # type Checkbox<Message> = iced_native::Checkbox<Message, iced_native::renderer::Null>;
|
||||||
/// #
|
/// #
|
||||||
/// pub enum Message {
|
/// pub enum Message {
|
||||||
/// CheckboxToggled(bool),
|
/// CheckboxToggled(bool),
|
||||||
|
|
@ -26,15 +26,15 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// 
|
/// 
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Checkbox<Message> {
|
pub struct Checkbox<Message, Renderer: self::Renderer> {
|
||||||
is_checked: bool,
|
is_checked: bool,
|
||||||
on_toggle: Box<dyn Fn(bool) -> Message>,
|
on_toggle: Box<dyn Fn(bool) -> Message>,
|
||||||
label: String,
|
label: String,
|
||||||
label_color: Option<Color>,
|
|
||||||
width: Length,
|
width: Length,
|
||||||
|
style: Renderer::Style,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Message> Checkbox<Message> {
|
impl<Message, Renderer: self::Renderer> Checkbox<Message, Renderer> {
|
||||||
/// Creates a new [`Checkbox`].
|
/// Creates a new [`Checkbox`].
|
||||||
///
|
///
|
||||||
/// It expects:
|
/// It expects:
|
||||||
|
|
@ -53,19 +53,11 @@ impl<Message> Checkbox<Message> {
|
||||||
is_checked,
|
is_checked,
|
||||||
on_toggle: Box::new(f),
|
on_toggle: Box::new(f),
|
||||||
label: String::from(label),
|
label: String::from(label),
|
||||||
label_color: None,
|
|
||||||
width: Length::Shrink,
|
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`].
|
/// Sets the width of the [`Checkbox`].
|
||||||
///
|
///
|
||||||
/// [`Checkbox`]: struct.Checkbox.html
|
/// [`Checkbox`]: struct.Checkbox.html
|
||||||
|
|
@ -73,9 +65,18 @@ impl<Message> Checkbox<Message> {
|
||||||
self.width = width;
|
self.width = width;
|
||||||
self
|
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
|
where
|
||||||
Renderer: self::Renderer + text::Renderer + row::Renderer,
|
Renderer: self::Renderer + text::Renderer + row::Renderer,
|
||||||
{
|
{
|
||||||
|
|
@ -134,6 +135,7 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
|
|
@ -146,11 +148,12 @@ where
|
||||||
|
|
||||||
let label = text::Renderer::draw(
|
let label = text::Renderer::draw(
|
||||||
renderer,
|
renderer,
|
||||||
|
defaults,
|
||||||
label_layout.bounds(),
|
label_layout.bounds(),
|
||||||
&self.label,
|
&self.label,
|
||||||
text::Renderer::default_size(renderer),
|
text::Renderer::default_size(renderer),
|
||||||
Font::Default,
|
Font::Default,
|
||||||
self.label_color,
|
None,
|
||||||
HorizontalAlignment::Left,
|
HorizontalAlignment::Left,
|
||||||
VerticalAlignment::Center,
|
VerticalAlignment::Center,
|
||||||
);
|
);
|
||||||
|
|
@ -163,6 +166,7 @@ where
|
||||||
self.is_checked,
|
self.is_checked,
|
||||||
is_mouse_over,
|
is_mouse_over,
|
||||||
label,
|
label,
|
||||||
|
&self.style,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,6 +183,9 @@ where
|
||||||
/// [`Checkbox`]: struct.Checkbox.html
|
/// [`Checkbox`]: struct.Checkbox.html
|
||||||
/// [renderer]: ../../renderer/index.html
|
/// [renderer]: ../../renderer/index.html
|
||||||
pub trait Renderer: crate::Renderer {
|
pub trait Renderer: crate::Renderer {
|
||||||
|
/// The style supported by this renderer.
|
||||||
|
type Style: Default;
|
||||||
|
|
||||||
/// Returns the default size of a [`Checkbox`].
|
/// Returns the default size of a [`Checkbox`].
|
||||||
///
|
///
|
||||||
/// [`Checkbox`]: struct.Checkbox.html
|
/// [`Checkbox`]: struct.Checkbox.html
|
||||||
|
|
@ -199,16 +206,19 @@ pub trait Renderer: crate::Renderer {
|
||||||
is_checked: bool,
|
is_checked: bool,
|
||||||
is_mouse_over: bool,
|
is_mouse_over: bool,
|
||||||
label: Self::Output,
|
label: Self::Output,
|
||||||
|
style: &Self::Style,
|
||||||
) -> Self::Output;
|
) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, Renderer> From<Checkbox<Message>>
|
impl<'a, Message, Renderer> From<Checkbox<Message, Renderer>>
|
||||||
for Element<'a, Message, Renderer>
|
for Element<'a, Message, Renderer>
|
||||||
where
|
where
|
||||||
Renderer: self::Renderer + text::Renderer + row::Renderer,
|
Renderer: 'static + self::Renderer + text::Renderer + row::Renderer,
|
||||||
Message: 'static,
|
Message: 'static,
|
||||||
{
|
{
|
||||||
fn from(checkbox: Checkbox<Message>) -> Element<'a, Message, Renderer> {
|
fn from(
|
||||||
|
checkbox: Checkbox<Message, Renderer>,
|
||||||
|
) -> Element<'a, Message, Renderer> {
|
||||||
Element::new(checkbox)
|
Element::new(checkbox)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -173,10 +173,11 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
renderer.draw(&self.children, layout, cursor_position)
|
renderer.draw(defaults, &self.children, layout, cursor_position)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_layout(&self, state: &mut Hasher) {
|
fn hash_layout(&self, state: &mut Hasher) {
|
||||||
|
|
@ -213,6 +214,7 @@ pub trait Renderer: crate::Renderer + Sized {
|
||||||
/// [`Layout`]: ../layout/struct.Layout.html
|
/// [`Layout`]: ../layout/struct.Layout.html
|
||||||
fn draw<Message>(
|
fn draw<Message>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
defaults: &Self::Defaults,
|
||||||
content: &[Element<'_, Message, Self>],
|
content: &[Element<'_, Message, Self>],
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::hash::Hash;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
layout, Align, Clipboard, Element, Event, Hasher, Layout, Length, Point,
|
layout, Align, Clipboard, Element, Event, Hasher, Layout, Length, Point,
|
||||||
Widget,
|
Rectangle, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::u32;
|
use std::u32;
|
||||||
|
|
@ -12,17 +12,21 @@ use std::u32;
|
||||||
///
|
///
|
||||||
/// It is normally used for alignment purposes.
|
/// It is normally used for alignment purposes.
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Container<'a, Message, Renderer> {
|
pub struct Container<'a, Message, Renderer: self::Renderer> {
|
||||||
width: Length,
|
width: Length,
|
||||||
height: Length,
|
height: Length,
|
||||||
max_width: u32,
|
max_width: u32,
|
||||||
max_height: u32,
|
max_height: u32,
|
||||||
horizontal_alignment: Align,
|
horizontal_alignment: Align,
|
||||||
vertical_alignment: Align,
|
vertical_alignment: Align,
|
||||||
|
style: Renderer::Style,
|
||||||
content: Element<'a, Message, Renderer>,
|
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`].
|
/// Creates an empty [`Container`].
|
||||||
///
|
///
|
||||||
/// [`Container`]: struct.Container.html
|
/// [`Container`]: struct.Container.html
|
||||||
|
|
@ -37,6 +41,7 @@ impl<'a, Message, Renderer> Container<'a, Message, Renderer> {
|
||||||
max_height: u32::MAX,
|
max_height: u32::MAX,
|
||||||
horizontal_alignment: Align::Start,
|
horizontal_alignment: Align::Start,
|
||||||
vertical_alignment: Align::Start,
|
vertical_alignment: Align::Start,
|
||||||
|
style: Renderer::Style::default(),
|
||||||
content: content.into(),
|
content: content.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -78,7 +83,6 @@ impl<'a, Message, Renderer> Container<'a, Message, Renderer> {
|
||||||
/// [`Container`]: struct.Container.html
|
/// [`Container`]: struct.Container.html
|
||||||
pub fn center_x(mut self) -> Self {
|
pub fn center_x(mut self) -> Self {
|
||||||
self.horizontal_alignment = Align::Center;
|
self.horizontal_alignment = Align::Center;
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,7 +91,14 @@ impl<'a, Message, Renderer> Container<'a, Message, Renderer> {
|
||||||
/// [`Container`]: struct.Container.html
|
/// [`Container`]: struct.Container.html
|
||||||
pub fn center_y(mut self) -> Self {
|
pub fn center_y(mut self) -> Self {
|
||||||
self.vertical_alignment = Align::Center;
|
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
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -95,7 +106,7 @@ impl<'a, Message, Renderer> Container<'a, Message, Renderer> {
|
||||||
impl<'a, Message, Renderer> Widget<Message, Renderer>
|
impl<'a, Message, Renderer> Widget<Message, Renderer>
|
||||||
for Container<'a, Message, Renderer>
|
for Container<'a, Message, Renderer>
|
||||||
where
|
where
|
||||||
Renderer: crate::Renderer,
|
Renderer: self::Renderer,
|
||||||
{
|
{
|
||||||
fn width(&self) -> Length {
|
fn width(&self) -> Length {
|
||||||
self.width
|
self.width
|
||||||
|
|
@ -147,13 +158,17 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
self.content.draw(
|
renderer.draw(
|
||||||
renderer,
|
defaults,
|
||||||
layout.children().next().unwrap(),
|
layout.bounds(),
|
||||||
cursor_position,
|
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>>
|
impl<'a, Message, Renderer> From<Container<'a, Message, Renderer>>
|
||||||
for Element<'a, Message, Renderer>
|
for Element<'a, Message, Renderer>
|
||||||
where
|
where
|
||||||
Renderer: 'a + crate::Renderer,
|
Renderer: 'a + self::Renderer,
|
||||||
Message: 'static,
|
Message: 'static,
|
||||||
{
|
{
|
||||||
fn from(
|
fn from(
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,7 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
_defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
_cursor_position: Point,
|
_cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
//! Provide progress feedback to your users.
|
//! Provide progress feedback to your users.
|
||||||
use crate::{
|
use crate::{
|
||||||
layout, Background, Color, Element, Hasher, Layout, Length, Point,
|
layout, Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget,
|
||||||
Rectangle, Size, Widget,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{hash::Hash, ops::RangeInclusive};
|
use std::{hash::Hash, ops::RangeInclusive};
|
||||||
|
|
@ -10,8 +9,9 @@ use std::{hash::Hash, ops::RangeInclusive};
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # use iced_native::ProgressBar;
|
/// # use iced_native::renderer::Null;
|
||||||
/// #
|
/// #
|
||||||
|
/// # pub type ProgressBar = iced_native::ProgressBar<Null>;
|
||||||
/// let value = 50.0;
|
/// let value = 50.0;
|
||||||
///
|
///
|
||||||
/// ProgressBar::new(0.0..=100.0, value);
|
/// ProgressBar::new(0.0..=100.0, value);
|
||||||
|
|
@ -19,16 +19,15 @@ use std::{hash::Hash, ops::RangeInclusive};
|
||||||
///
|
///
|
||||||
/// 
|
/// 
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct ProgressBar {
|
pub struct ProgressBar<Renderer: self::Renderer> {
|
||||||
range: RangeInclusive<f32>,
|
range: RangeInclusive<f32>,
|
||||||
value: f32,
|
value: f32,
|
||||||
width: Length,
|
width: Length,
|
||||||
height: Option<Length>,
|
height: Option<Length>,
|
||||||
background: Option<Background>,
|
style: Renderer::Style,
|
||||||
active_color: Option<Color>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProgressBar {
|
impl<Renderer: self::Renderer> ProgressBar<Renderer> {
|
||||||
/// Creates a new [`ProgressBar`].
|
/// Creates a new [`ProgressBar`].
|
||||||
///
|
///
|
||||||
/// It expects:
|
/// It expects:
|
||||||
|
|
@ -42,8 +41,7 @@ impl ProgressBar {
|
||||||
range,
|
range,
|
||||||
width: Length::Fill,
|
width: Length::Fill,
|
||||||
height: None,
|
height: None,
|
||||||
background: None,
|
style: Renderer::Style::default(),
|
||||||
active_color: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,24 +61,16 @@ impl ProgressBar {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the background of the [`ProgressBar`].
|
/// Sets the style of the [`ProgressBar`].
|
||||||
///
|
///
|
||||||
/// [`ProgressBar`]: struct.ProgressBar.html
|
/// [`ProgressBar`]: struct.ProgressBar.html
|
||||||
pub fn background(mut self, background: Background) -> Self {
|
pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self {
|
||||||
self.background = Some(background);
|
self.style = style.into();
|
||||||
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);
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Message, Renderer> Widget<Message, Renderer> for ProgressBar
|
impl<Message, Renderer> Widget<Message, Renderer> for ProgressBar<Renderer>
|
||||||
where
|
where
|
||||||
Renderer: self::Renderer,
|
Renderer: self::Renderer,
|
||||||
{
|
{
|
||||||
|
|
@ -111,6 +101,7 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
_defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
_cursor_position: Point,
|
_cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
|
|
@ -118,8 +109,7 @@ where
|
||||||
layout.bounds(),
|
layout.bounds(),
|
||||||
self.range.clone(),
|
self.range.clone(),
|
||||||
self.value,
|
self.value,
|
||||||
self.background,
|
&self.style,
|
||||||
self.active_color,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,6 +127,9 @@ where
|
||||||
/// [`ProgressBar`]: struct.ProgressBar.html
|
/// [`ProgressBar`]: struct.ProgressBar.html
|
||||||
/// [renderer]: ../../renderer/index.html
|
/// [renderer]: ../../renderer/index.html
|
||||||
pub trait Renderer: crate::Renderer {
|
pub trait Renderer: crate::Renderer {
|
||||||
|
/// The style supported by this renderer.
|
||||||
|
type Style: Default;
|
||||||
|
|
||||||
/// The default height of a [`ProgressBar`].
|
/// The default height of a [`ProgressBar`].
|
||||||
///
|
///
|
||||||
/// [`ProgressBar`]: struct.ProgressBar.html
|
/// [`ProgressBar`]: struct.ProgressBar.html
|
||||||
|
|
@ -157,17 +150,19 @@ pub trait Renderer: crate::Renderer {
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
range: RangeInclusive<f32>,
|
range: RangeInclusive<f32>,
|
||||||
value: f32,
|
value: f32,
|
||||||
background: Option<Background>,
|
style: &Self::Style,
|
||||||
active_color: Option<Color>,
|
|
||||||
) -> Self::Output;
|
) -> 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
|
where
|
||||||
Renderer: self::Renderer,
|
Renderer: 'static + self::Renderer,
|
||||||
Message: 'static,
|
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)
|
Element::new(progress_bar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! Create choices using radio buttons.
|
//! Create choices using radio buttons.
|
||||||
use crate::{
|
use crate::{
|
||||||
input::{mouse, ButtonState},
|
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,
|
HorizontalAlignment, Layout, Length, Point, Rectangle, Row, Text,
|
||||||
VerticalAlignment, Widget,
|
VerticalAlignment, Widget,
|
||||||
};
|
};
|
||||||
|
|
@ -12,7 +12,8 @@ use std::hash::Hash;
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # use iced_native::Radio;
|
/// # type Radio<Message> =
|
||||||
|
/// # iced_native::Radio<Message, iced_native::renderer::Null>;
|
||||||
/// #
|
/// #
|
||||||
/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
/// pub enum Choice {
|
/// pub enum Choice {
|
||||||
|
|
@ -34,14 +35,14 @@ use std::hash::Hash;
|
||||||
///
|
///
|
||||||
/// 
|
/// 
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Radio<Message> {
|
pub struct Radio<Message, Renderer: self::Renderer> {
|
||||||
is_selected: bool,
|
is_selected: bool,
|
||||||
on_click: Message,
|
on_click: Message,
|
||||||
label: String,
|
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.
|
/// Creates a new [`Radio`] button.
|
||||||
///
|
///
|
||||||
/// It expects:
|
/// It expects:
|
||||||
|
|
@ -61,20 +62,20 @@ impl<Message> Radio<Message> {
|
||||||
is_selected: Some(value) == selected,
|
is_selected: Some(value) == selected,
|
||||||
on_click: f(value),
|
on_click: f(value),
|
||||||
label: String::from(label),
|
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
|
/// [`Radio`]: struct.Radio.html
|
||||||
pub fn label_color<C: Into<Color>>(mut self, color: C) -> Self {
|
pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self {
|
||||||
self.label_color = Some(color.into());
|
self.style = style.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Message, Renderer> Widget<Message, Renderer> for Radio<Message>
|
impl<Message, Renderer> Widget<Message, Renderer> for Radio<Message, Renderer>
|
||||||
where
|
where
|
||||||
Renderer: self::Renderer + text::Renderer + row::Renderer,
|
Renderer: self::Renderer + text::Renderer + row::Renderer,
|
||||||
Message: Clone,
|
Message: Clone,
|
||||||
|
|
@ -132,6 +133,7 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
|
|
@ -144,11 +146,12 @@ where
|
||||||
|
|
||||||
let label = text::Renderer::draw(
|
let label = text::Renderer::draw(
|
||||||
renderer,
|
renderer,
|
||||||
|
defaults,
|
||||||
label_layout.bounds(),
|
label_layout.bounds(),
|
||||||
&self.label,
|
&self.label,
|
||||||
text::Renderer::default_size(renderer),
|
text::Renderer::default_size(renderer),
|
||||||
Font::Default,
|
Font::Default,
|
||||||
self.label_color,
|
None,
|
||||||
HorizontalAlignment::Left,
|
HorizontalAlignment::Left,
|
||||||
VerticalAlignment::Center,
|
VerticalAlignment::Center,
|
||||||
);
|
);
|
||||||
|
|
@ -161,6 +164,7 @@ where
|
||||||
self.is_selected,
|
self.is_selected,
|
||||||
is_mouse_over,
|
is_mouse_over,
|
||||||
label,
|
label,
|
||||||
|
&self.style,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,6 +181,9 @@ where
|
||||||
/// [`Radio`]: struct.Radio.html
|
/// [`Radio`]: struct.Radio.html
|
||||||
/// [renderer]: ../../renderer/index.html
|
/// [renderer]: ../../renderer/index.html
|
||||||
pub trait Renderer: crate::Renderer {
|
pub trait Renderer: crate::Renderer {
|
||||||
|
/// The style supported by this renderer.
|
||||||
|
type Style: Default;
|
||||||
|
|
||||||
/// Returns the default size of a [`Radio`] button.
|
/// Returns the default size of a [`Radio`] button.
|
||||||
///
|
///
|
||||||
/// [`Radio`]: struct.Radio.html
|
/// [`Radio`]: struct.Radio.html
|
||||||
|
|
@ -197,16 +204,17 @@ pub trait Renderer: crate::Renderer {
|
||||||
is_selected: bool,
|
is_selected: bool,
|
||||||
is_mouse_over: bool,
|
is_mouse_over: bool,
|
||||||
label: Self::Output,
|
label: Self::Output,
|
||||||
|
style: &Self::Style,
|
||||||
) -> Self::Output;
|
) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, Renderer> From<Radio<Message>>
|
impl<'a, Message, Renderer> From<Radio<Message, Renderer>>
|
||||||
for Element<'a, Message, Renderer>
|
for Element<'a, Message, Renderer>
|
||||||
where
|
where
|
||||||
Renderer: self::Renderer + row::Renderer + text::Renderer,
|
Renderer: 'static + self::Renderer + row::Renderer + text::Renderer,
|
||||||
Message: 'static + Clone,
|
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)
|
Element::new(radio)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -174,10 +174,11 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
renderer.draw(&self.children, layout, cursor_position)
|
renderer.draw(defaults, &self.children, layout, cursor_position)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_layout(&self, state: &mut Hasher) {
|
fn hash_layout(&self, state: &mut Hasher) {
|
||||||
|
|
@ -215,6 +216,7 @@ pub trait Renderer: crate::Renderer + Sized {
|
||||||
/// [`Layout`]: ../layout/struct.Layout.html
|
/// [`Layout`]: ../layout/struct.Layout.html
|
||||||
fn draw<Message>(
|
fn draw<Message>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
defaults: &Self::Defaults,
|
||||||
children: &[Element<'_, Message, Self>],
|
children: &[Element<'_, Message, Self>],
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
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
|
/// A widget that can vertically display an infinite amount of content with a
|
||||||
/// scrollbar.
|
/// scrollbar.
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Scrollable<'a, Message, Renderer> {
|
pub struct Scrollable<'a, Message, Renderer: self::Renderer> {
|
||||||
state: &'a mut State,
|
state: &'a mut State,
|
||||||
height: Length,
|
height: Length,
|
||||||
max_height: u32,
|
max_height: u32,
|
||||||
content: Column<'a, Message, Renderer>,
|
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`].
|
/// Creates a new [`Scrollable`] with the given [`State`].
|
||||||
///
|
///
|
||||||
/// [`Scrollable`]: struct.Scrollable.html
|
/// [`Scrollable`]: struct.Scrollable.html
|
||||||
|
|
@ -29,6 +30,7 @@ impl<'a, Message, Renderer> Scrollable<'a, Message, Renderer> {
|
||||||
height: Length::Shrink,
|
height: Length::Shrink,
|
||||||
max_height: u32::MAX,
|
max_height: u32::MAX,
|
||||||
content: Column::new(),
|
content: Column::new(),
|
||||||
|
style: Renderer::Style::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,6 +92,14 @@ impl<'a, Message, Renderer> Scrollable<'a, Message, Renderer> {
|
||||||
self
|
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`].
|
/// Adds an element to the [`Scrollable`].
|
||||||
///
|
///
|
||||||
/// [`Scrollable`]: struct.Scrollable.html
|
/// [`Scrollable`]: struct.Scrollable.html
|
||||||
|
|
@ -105,7 +115,7 @@ impl<'a, Message, Renderer> Scrollable<'a, Message, Renderer> {
|
||||||
impl<'a, Message, Renderer> Widget<Message, Renderer>
|
impl<'a, Message, Renderer> Widget<Message, Renderer>
|
||||||
for Scrollable<'a, Message, Renderer>
|
for Scrollable<'a, Message, Renderer>
|
||||||
where
|
where
|
||||||
Renderer: self::Renderer + column::Renderer,
|
Renderer: 'static + self::Renderer + column::Renderer,
|
||||||
{
|
{
|
||||||
fn width(&self) -> Length {
|
fn width(&self) -> Length {
|
||||||
Length::Fill
|
Length::Fill
|
||||||
|
|
@ -255,6 +265,7 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
|
|
@ -277,7 +288,12 @@ where
|
||||||
Point::new(cursor_position.x, -1.0)
|
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(
|
self::Renderer::draw(
|
||||||
|
|
@ -289,12 +305,13 @@ where
|
||||||
is_mouse_over_scrollbar,
|
is_mouse_over_scrollbar,
|
||||||
scrollbar,
|
scrollbar,
|
||||||
offset,
|
offset,
|
||||||
|
&self.style,
|
||||||
content,
|
content,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_layout(&self, state: &mut Hasher) {
|
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.height.hash(state);
|
||||||
self.max_height.hash(state);
|
self.max_height.hash(state);
|
||||||
|
|
@ -441,6 +458,9 @@ pub struct Scroller {
|
||||||
/// [`Scrollable`]: struct.Scrollable.html
|
/// [`Scrollable`]: struct.Scrollable.html
|
||||||
/// [renderer]: ../../renderer/index.html
|
/// [renderer]: ../../renderer/index.html
|
||||||
pub trait Renderer: crate::Renderer + Sized {
|
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
|
/// Returns the [`Scrollbar`] given the bounds and content bounds of a
|
||||||
/// [`Scrollable`].
|
/// [`Scrollable`].
|
||||||
///
|
///
|
||||||
|
|
@ -477,6 +497,7 @@ pub trait Renderer: crate::Renderer + Sized {
|
||||||
is_mouse_over_scrollbar: bool,
|
is_mouse_over_scrollbar: bool,
|
||||||
scrollbar: Option<Scrollbar>,
|
scrollbar: Option<Scrollbar>,
|
||||||
offset: u32,
|
offset: u32,
|
||||||
|
style: &Self::Style,
|
||||||
content: Self::Output,
|
content: Self::Output,
|
||||||
) -> Self::Output;
|
) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
@ -484,7 +505,7 @@ pub trait Renderer: crate::Renderer + Sized {
|
||||||
impl<'a, Message, Renderer> From<Scrollable<'a, Message, Renderer>>
|
impl<'a, Message, Renderer> From<Scrollable<'a, Message, Renderer>>
|
||||||
for Element<'a, Message, Renderer>
|
for Element<'a, Message, Renderer>
|
||||||
where
|
where
|
||||||
Renderer: 'a + self::Renderer + column::Renderer,
|
Renderer: 'static + self::Renderer + column::Renderer,
|
||||||
Message: 'static,
|
Message: 'static,
|
||||||
{
|
{
|
||||||
fn from(
|
fn from(
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,9 @@ use std::{hash::Hash, ops::RangeInclusive};
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # 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 {
|
/// pub enum Message {
|
||||||
/// SliderChanged(f32),
|
/// SliderChanged(f32),
|
||||||
/// }
|
/// }
|
||||||
|
|
@ -35,15 +36,16 @@ use std::{hash::Hash, ops::RangeInclusive};
|
||||||
///
|
///
|
||||||
/// 
|
/// 
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Slider<'a, Message> {
|
pub struct Slider<'a, Message, Renderer: self::Renderer> {
|
||||||
state: &'a mut State,
|
state: &'a mut State,
|
||||||
range: RangeInclusive<f32>,
|
range: RangeInclusive<f32>,
|
||||||
value: f32,
|
value: f32,
|
||||||
on_change: Box<dyn Fn(f32) -> Message>,
|
on_change: Box<dyn Fn(f32) -> Message>,
|
||||||
width: Length,
|
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`].
|
/// Creates a new [`Slider`].
|
||||||
///
|
///
|
||||||
/// It expects:
|
/// It expects:
|
||||||
|
|
@ -71,6 +73,7 @@ impl<'a, Message> Slider<'a, Message> {
|
||||||
range,
|
range,
|
||||||
on_change: Box::new(on_change),
|
on_change: Box::new(on_change),
|
||||||
width: Length::Fill,
|
width: Length::Fill,
|
||||||
|
style: Renderer::Style::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,6 +84,14 @@ impl<'a, Message> Slider<'a, Message> {
|
||||||
self.width = width;
|
self.width = width;
|
||||||
self
|
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`].
|
/// 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
|
where
|
||||||
Renderer: self::Renderer,
|
Renderer: self::Renderer,
|
||||||
{
|
{
|
||||||
|
|
@ -178,6 +190,7 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
_defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
|
|
@ -187,6 +200,7 @@ where
|
||||||
self.range.clone(),
|
self.range.clone(),
|
||||||
self.value,
|
self.value,
|
||||||
self.state.is_dragging,
|
self.state.is_dragging,
|
||||||
|
&self.style,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -203,6 +217,9 @@ where
|
||||||
/// [`Slider`]: struct.Slider.html
|
/// [`Slider`]: struct.Slider.html
|
||||||
/// [renderer]: ../../renderer/index.html
|
/// [renderer]: ../../renderer/index.html
|
||||||
pub trait Renderer: crate::Renderer {
|
pub trait Renderer: crate::Renderer {
|
||||||
|
/// The style supported by this renderer.
|
||||||
|
type Style: Default;
|
||||||
|
|
||||||
/// Returns the height of the [`Slider`].
|
/// Returns the height of the [`Slider`].
|
||||||
///
|
///
|
||||||
/// [`Slider`]: struct.Slider.html
|
/// [`Slider`]: struct.Slider.html
|
||||||
|
|
@ -227,16 +244,19 @@ pub trait Renderer: crate::Renderer {
|
||||||
range: RangeInclusive<f32>,
|
range: RangeInclusive<f32>,
|
||||||
value: f32,
|
value: f32,
|
||||||
is_dragging: bool,
|
is_dragging: bool,
|
||||||
|
style: &Self::Style,
|
||||||
) -> Self::Output;
|
) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, Renderer> From<Slider<'a, Message>>
|
impl<'a, Message, Renderer> From<Slider<'a, Message, Renderer>>
|
||||||
for Element<'a, Message, Renderer>
|
for Element<'a, Message, Renderer>
|
||||||
where
|
where
|
||||||
Renderer: self::Renderer,
|
Renderer: 'static + self::Renderer,
|
||||||
Message: 'static,
|
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)
|
Element::new(slider)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
_defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
_cursor_position: Point,
|
_cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,7 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
_defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
_cursor_position: Point,
|
_cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
|
|
|
||||||
|
|
@ -146,10 +146,12 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
_cursor_position: Point,
|
_cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
renderer.draw(
|
renderer.draw(
|
||||||
|
defaults,
|
||||||
layout.bounds(),
|
layout.bounds(),
|
||||||
&self.content,
|
&self.content,
|
||||||
self.size.unwrap_or(renderer.default_size()),
|
self.size.unwrap_or(renderer.default_size()),
|
||||||
|
|
@ -209,6 +211,7 @@ pub trait Renderer: crate::Renderer {
|
||||||
/// [`VerticalAlignment`]: enum.VerticalAlignment.html
|
/// [`VerticalAlignment`]: enum.VerticalAlignment.html
|
||||||
fn draw(
|
fn draw(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
defaults: &Self::Defaults,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
content: &str,
|
content: &str,
|
||||||
size: u16,
|
size: u16,
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,9 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # 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)]
|
/// #[derive(Debug, Clone)]
|
||||||
/// enum Message {
|
/// enum Message {
|
||||||
/// TextInputChanged(String),
|
/// TextInputChanged(String),
|
||||||
|
|
@ -35,7 +36,7 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||||
/// ```
|
/// ```
|
||||||
/// 
|
/// 
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct TextInput<'a, Message> {
|
pub struct TextInput<'a, Message, Renderer: self::Renderer> {
|
||||||
state: &'a mut State,
|
state: &'a mut State,
|
||||||
placeholder: String,
|
placeholder: String,
|
||||||
value: Value,
|
value: Value,
|
||||||
|
|
@ -46,9 +47,10 @@ pub struct TextInput<'a, Message> {
|
||||||
size: Option<u16>,
|
size: Option<u16>,
|
||||||
on_change: Box<dyn Fn(String) -> Message>,
|
on_change: Box<dyn Fn(String) -> Message>,
|
||||||
on_submit: Option<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`].
|
/// Creates a new [`TextInput`].
|
||||||
///
|
///
|
||||||
/// It expects:
|
/// It expects:
|
||||||
|
|
@ -64,7 +66,7 @@ impl<'a, Message> TextInput<'a, Message> {
|
||||||
placeholder: &str,
|
placeholder: &str,
|
||||||
value: &str,
|
value: &str,
|
||||||
on_change: F,
|
on_change: F,
|
||||||
) -> TextInput<'a, Message>
|
) -> Self
|
||||||
where
|
where
|
||||||
F: 'static + Fn(String) -> Message,
|
F: 'static + Fn(String) -> Message,
|
||||||
{
|
{
|
||||||
|
|
@ -79,6 +81,7 @@ impl<'a, Message> TextInput<'a, Message> {
|
||||||
size: None,
|
size: None,
|
||||||
on_change: Box::new(on_change),
|
on_change: Box::new(on_change),
|
||||||
on_submit: None,
|
on_submit: None,
|
||||||
|
style: Renderer::Style::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,11 +133,20 @@ impl<'a, Message> TextInput<'a, Message> {
|
||||||
self.on_submit = Some(message);
|
self.on_submit = Some(message);
|
||||||
self
|
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
|
where
|
||||||
Renderer: self::Renderer,
|
Renderer: 'static + self::Renderer,
|
||||||
Message: Clone + std::fmt::Debug,
|
Message: Clone + std::fmt::Debug,
|
||||||
{
|
{
|
||||||
fn width(&self) -> Length {
|
fn width(&self) -> Length {
|
||||||
|
|
@ -343,6 +355,7 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
|
_defaults: &Renderer::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
|
|
@ -358,6 +371,7 @@ where
|
||||||
&self.placeholder,
|
&self.placeholder,
|
||||||
&self.value.secure(),
|
&self.value.secure(),
|
||||||
&self.state,
|
&self.state,
|
||||||
|
&self.style,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
renderer.draw(
|
renderer.draw(
|
||||||
|
|
@ -368,6 +382,7 @@ where
|
||||||
&self.placeholder,
|
&self.placeholder,
|
||||||
&self.value,
|
&self.value,
|
||||||
&self.state,
|
&self.state,
|
||||||
|
&self.style,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -375,7 +390,7 @@ where
|
||||||
fn hash_layout(&self, state: &mut Hasher) {
|
fn hash_layout(&self, state: &mut Hasher) {
|
||||||
use std::{any::TypeId, hash::Hash};
|
use std::{any::TypeId, hash::Hash};
|
||||||
|
|
||||||
TypeId::of::<TextInput<'static, ()>>().hash(state);
|
TypeId::of::<TextInput<'static, (), Renderer>>().hash(state);
|
||||||
|
|
||||||
self.width.hash(state);
|
self.width.hash(state);
|
||||||
self.max_width.hash(state);
|
self.max_width.hash(state);
|
||||||
|
|
@ -392,6 +407,9 @@ where
|
||||||
/// [`TextInput`]: struct.TextInput.html
|
/// [`TextInput`]: struct.TextInput.html
|
||||||
/// [renderer]: ../../renderer/index.html
|
/// [renderer]: ../../renderer/index.html
|
||||||
pub trait Renderer: crate::Renderer + Sized {
|
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`].
|
/// Returns the default size of the text of the [`TextInput`].
|
||||||
///
|
///
|
||||||
/// [`TextInput`]: struct.TextInput.html
|
/// [`TextInput`]: struct.TextInput.html
|
||||||
|
|
@ -440,17 +458,18 @@ pub trait Renderer: crate::Renderer + Sized {
|
||||||
placeholder: &str,
|
placeholder: &str,
|
||||||
value: &Value,
|
value: &Value,
|
||||||
state: &State,
|
state: &State,
|
||||||
|
style: &Self::Style,
|
||||||
) -> Self::Output;
|
) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, Renderer> From<TextInput<'a, Message>>
|
impl<'a, Message, Renderer> From<TextInput<'a, Message, Renderer>>
|
||||||
for Element<'a, Message, Renderer>
|
for Element<'a, Message, Renderer>
|
||||||
where
|
where
|
||||||
Renderer: 'static + self::Renderer,
|
Renderer: 'static + self::Renderer,
|
||||||
Message: 'static + Clone + std::fmt::Debug,
|
Message: 'static + Clone + std::fmt::Debug,
|
||||||
{
|
{
|
||||||
fn from(
|
fn from(
|
||||||
text_input: TextInput<'a, Message>,
|
text_input: TextInput<'a, Message, Renderer>,
|
||||||
) -> Element<'a, Message, Renderer> {
|
) -> Element<'a, Message, Renderer> {
|
||||||
Element::new(text_input)
|
Element::new(text_input)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,12 @@ pub trait Application: Sized {
|
||||||
Self: 'static,
|
Self: 'static,
|
||||||
{
|
{
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[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")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
<Instance<Self> as iced_web::Application>::run();
|
<Instance<Self> as iced_web::Application>::run();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
pub use iced_winit::{
|
pub use iced_winit::{
|
||||||
Align, Background, Color, Command, Font, HorizontalAlignment, Length,
|
Align, Background, Color, Command, Font, HorizontalAlignment, Length,
|
||||||
Space, Subscription, VerticalAlignment,
|
Space, Subscription, Vector, VerticalAlignment,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod widget {
|
pub mod widget {
|
||||||
|
|
@ -22,58 +22,7 @@ pub mod widget {
|
||||||
//!
|
//!
|
||||||
//! [`TextInput`]: text_input/struct.TextInput.html
|
//! [`TextInput`]: text_input/struct.TextInput.html
|
||||||
//! [`text_input::State`]: text_input/struct.State.html
|
//! [`text_input::State`]: text_input/struct.State.html
|
||||||
pub mod button {
|
pub use iced_wgpu::widget::*;
|
||||||
//! 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 mod image {
|
pub mod image {
|
||||||
//! Display images in your user interface.
|
//! Display images in your user interface.
|
||||||
|
|
@ -85,12 +34,13 @@ pub mod widget {
|
||||||
pub use iced_winit::svg::{Handle, Svg};
|
pub use iced_winit::svg::{Handle, Svg};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use iced_winit::{Checkbox, ProgressBar, Radio, Text};
|
pub use iced_winit::Text;
|
||||||
|
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use {
|
pub use {
|
||||||
button::Button, image::Image, scrollable::Scrollable, slider::Slider,
|
button::Button, checkbox::Checkbox, container::Container, image::Image,
|
||||||
svg::Svg, text_input::TextInput,
|
progress_bar::ProgressBar, radio::Radio, scrollable::Scrollable,
|
||||||
|
slider::Slider, svg::Svg, text_input::TextInput,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A container that distributes its contents vertically.
|
/// 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`.
|
/// This is an alias of an `iced_native` row with a default `Renderer`.
|
||||||
pub type Row<'a, Message> =
|
pub type Row<'a, Message> =
|
||||||
iced_winit::Row<'a, Message, iced_wgpu::Renderer>;
|
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)]
|
#[doc(no_inline)]
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,12 @@ pub struct Settings {
|
||||||
///
|
///
|
||||||
/// [`Window`]: struct.Window.html
|
/// [`Window`]: struct.Window.html
|
||||||
pub window: Window,
|
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.
|
/// 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]
|
[dependencies]
|
||||||
iced_native = { version = "0.1.0", path = "../native" }
|
iced_native = { version = "0.1.0", path = "../native" }
|
||||||
|
iced_style = { version = "0.1.0-alpha", path = "../style" }
|
||||||
wgpu = "0.4"
|
wgpu = "0.4"
|
||||||
glyph_brush = "0.6"
|
glyph_brush = "0.6"
|
||||||
wgpu_glyph = { version = "0.7", git = "https://github.com/hecrj/wgpu_glyph", branch = "fix/font-load-panic" }
|
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(unused_results)]
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![deny(rust_2018_idioms)]
|
#![deny(rust_2018_idioms)]
|
||||||
|
pub mod defaults;
|
||||||
pub mod triangle;
|
pub mod triangle;
|
||||||
|
pub mod widget;
|
||||||
|
|
||||||
mod image;
|
mod image;
|
||||||
mod primitive;
|
mod primitive;
|
||||||
mod quad;
|
mod quad;
|
||||||
mod renderer;
|
mod renderer;
|
||||||
|
mod settings;
|
||||||
mod text;
|
mod text;
|
||||||
mod transformation;
|
mod transformation;
|
||||||
|
|
||||||
pub(crate) use crate::image::Image;
|
pub use defaults::Defaults;
|
||||||
pub(crate) use quad::Quad;
|
|
||||||
pub(crate) use transformation::Transformation;
|
|
||||||
|
|
||||||
pub use primitive::Primitive;
|
pub use primitive::Primitive;
|
||||||
pub use renderer::{Renderer, Target};
|
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,
|
background: Background,
|
||||||
/// The border radius of the quad
|
/// The border radius of the quad
|
||||||
border_radius: u16,
|
border_radius: u16,
|
||||||
|
/// The border width of the quad
|
||||||
|
border_width: u16,
|
||||||
|
/// The border color of the quad
|
||||||
|
border_color: Color,
|
||||||
},
|
},
|
||||||
/// An image primitive
|
/// An image primitive
|
||||||
Image {
|
Image {
|
||||||
|
|
|
||||||
|
|
@ -125,9 +125,19 @@ impl Pipeline {
|
||||||
},
|
},
|
||||||
wgpu::VertexAttributeDescriptor {
|
wgpu::VertexAttributeDescriptor {
|
||||||
shader_location: 4,
|
shader_location: 4,
|
||||||
format: wgpu::VertexFormat::Float,
|
format: wgpu::VertexFormat::Float4,
|
||||||
offset: 4 * (2 + 2 + 4),
|
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.x,
|
||||||
bounds.y,
|
bounds.y,
|
||||||
bounds.width,
|
bounds.width,
|
||||||
bounds.height,
|
// TODO: Address anti-aliasing adjustments properly
|
||||||
|
bounds.height + 1,
|
||||||
);
|
);
|
||||||
|
|
||||||
render_pass.draw_indexed(
|
render_pass.draw_indexed(
|
||||||
|
|
@ -277,7 +288,9 @@ pub struct Quad {
|
||||||
pub position: [f32; 2],
|
pub position: [f32; 2],
|
||||||
pub scale: [f32; 2],
|
pub scale: [f32; 2],
|
||||||
pub color: [f32; 4],
|
pub color: [f32; 4],
|
||||||
|
pub border_color: [f32; 4],
|
||||||
pub border_radius: f32,
|
pub border_radius: f32,
|
||||||
|
pub border_width: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Quad {
|
impl Quad {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
image, quad, text, triangle, Image, Primitive, Quad, Transformation,
|
image, quad, text, triangle, Defaults, Image, Primitive, Quad, Settings,
|
||||||
|
Transformation,
|
||||||
};
|
};
|
||||||
use iced_native::{
|
use iced_native::{
|
||||||
renderer::{Debugger, Windowed},
|
renderer::{Debugger, Windowed},
|
||||||
|
|
@ -24,7 +25,7 @@ pub struct Renderer {
|
||||||
device: Device,
|
device: Device,
|
||||||
queue: Queue,
|
queue: Queue,
|
||||||
quad_pipeline: quad::Pipeline,
|
quad_pipeline: quad::Pipeline,
|
||||||
image_pipeline: crate::image::Pipeline,
|
image_pipeline: image::Pipeline,
|
||||||
text_pipeline: text::Pipeline,
|
text_pipeline: text::Pipeline,
|
||||||
triangle_pipeline: crate::triangle::Pipeline,
|
triangle_pipeline: crate::triangle::Pipeline,
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +53,7 @@ impl<'a> Layer<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer {
|
impl Renderer {
|
||||||
fn new() -> Self {
|
fn new(settings: Settings) -> Self {
|
||||||
let adapter = Adapter::request(&RequestAdapterOptions {
|
let adapter = Adapter::request(&RequestAdapterOptions {
|
||||||
power_preference: PowerPreference::Default,
|
power_preference: PowerPreference::Default,
|
||||||
backends: BackendBit::all(),
|
backends: BackendBit::all(),
|
||||||
|
|
@ -66,7 +67,8 @@ impl Renderer {
|
||||||
limits: Limits { max_bind_groups: 2 },
|
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 quad_pipeline = quad::Pipeline::new(&mut device);
|
||||||
let image_pipeline = crate::image::Pipeline::new(&mut device);
|
let image_pipeline = crate::image::Pipeline::new(&mut device);
|
||||||
let triangle_pipeline = triangle::Pipeline::new(&mut device);
|
let triangle_pipeline = triangle::Pipeline::new(&mut device);
|
||||||
|
|
@ -223,6 +225,8 @@ impl Renderer {
|
||||||
bounds,
|
bounds,
|
||||||
background,
|
background,
|
||||||
border_radius,
|
border_radius,
|
||||||
|
border_width,
|
||||||
|
border_color,
|
||||||
} => {
|
} => {
|
||||||
// TODO: Move some of this computations to the GPU (?)
|
// TODO: Move some of this computations to the GPU (?)
|
||||||
layer.quads.push(Quad {
|
layer.quads.push(Quad {
|
||||||
|
|
@ -235,6 +239,8 @@ impl Renderer {
|
||||||
Background::Color(color) => color.into_linear(),
|
Background::Color(color) => color.into_linear(),
|
||||||
},
|
},
|
||||||
border_radius: *border_radius as f32,
|
border_radius: *border_radius as f32,
|
||||||
|
border_width: *border_width as f32,
|
||||||
|
border_color: border_color.into_linear(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Primitive::Image { handle, bounds } => {
|
Primitive::Image { handle, bounds } => {
|
||||||
|
|
@ -434,6 +440,7 @@ impl Renderer {
|
||||||
|
|
||||||
impl iced_native::Renderer for Renderer {
|
impl iced_native::Renderer for Renderer {
|
||||||
type Output = (Primitive, MouseCursor);
|
type Output = (Primitive, MouseCursor);
|
||||||
|
type Defaults = Defaults;
|
||||||
|
|
||||||
fn layout<'a, Message>(
|
fn layout<'a, Message>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -448,10 +455,11 @@ impl iced_native::Renderer for Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Windowed for Renderer {
|
impl Windowed for Renderer {
|
||||||
|
type Settings = Settings;
|
||||||
type Target = Target;
|
type Target = Target;
|
||||||
|
|
||||||
fn new() -> Self {
|
fn new(settings: Settings) -> Self {
|
||||||
Self::new()
|
Self::new(settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw<T: AsRef<str>>(
|
fn draw<T: AsRef<str>>(
|
||||||
|
|
@ -467,13 +475,15 @@ impl Windowed for Renderer {
|
||||||
impl Debugger for Renderer {
|
impl Debugger for Renderer {
|
||||||
fn explain<Message>(
|
fn explain<Message>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
defaults: &Defaults,
|
||||||
widget: &dyn Widget<Message, Self>,
|
widget: &dyn Widget<Message, Self>,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
color: Color,
|
color: Color,
|
||||||
) -> Self::Output {
|
) -> Self::Output {
|
||||||
let mut primitives = Vec::new();
|
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);
|
explain_layout(layout, color, &mut primitives);
|
||||||
primitives.push(primitive);
|
primitives.push(primitive);
|
||||||
|
|
@ -487,11 +497,12 @@ fn explain_layout(
|
||||||
color: Color,
|
color: Color,
|
||||||
primitives: &mut Vec<Primitive>,
|
primitives: &mut Vec<Primitive>,
|
||||||
) {
|
) {
|
||||||
// TODO: Draw borders instead
|
|
||||||
primitives.push(Primitive::Quad {
|
primitives.push(Primitive::Quad {
|
||||||
bounds: layout.bounds(),
|
bounds: layout.bounds(),
|
||||||
background: Background::Color([0.0, 0.0, 0.0, 0.05].into()),
|
background: Background::Color(Color::TRANSPARENT),
|
||||||
border_radius: 0,
|
border_radius: 0,
|
||||||
|
border_width: 1,
|
||||||
|
border_color: [0.6, 0.6, 0.6, 0.5].into(),
|
||||||
});
|
});
|
||||||
|
|
||||||
for child in layout.children() {
|
for child in layout.children() {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
mod button;
|
mod button;
|
||||||
mod checkbox;
|
mod checkbox;
|
||||||
mod column;
|
mod column;
|
||||||
|
mod container;
|
||||||
mod image;
|
mod image;
|
||||||
mod progress_bar;
|
mod progress_bar;
|
||||||
mod radio;
|
mod radio;
|
||||||
|
|
|
||||||
|
|
@ -1,54 +1,86 @@
|
||||||
use crate::{Primitive, Renderer};
|
use crate::{button::StyleSheet, defaults, Defaults, Primitive, Renderer};
|
||||||
use iced_native::{button, Background, MouseCursor, Point, Rectangle};
|
use iced_native::{
|
||||||
|
Background, Color, Element, Layout, MouseCursor, Point, Rectangle, Vector,
|
||||||
|
};
|
||||||
|
|
||||||
impl button::Renderer for Renderer {
|
impl iced_native::button::Renderer for Renderer {
|
||||||
fn draw(
|
type Style = Box<dyn StyleSheet>;
|
||||||
|
|
||||||
|
fn draw<Message>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
defaults: &Defaults,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
|
is_disabled: bool,
|
||||||
is_pressed: bool,
|
is_pressed: bool,
|
||||||
background: Option<Background>,
|
style: &Box<dyn StyleSheet>,
|
||||||
border_radius: u16,
|
content: &Element<'_, Message, Self>,
|
||||||
(content, _): Self::Output,
|
content_layout: Layout<'_>,
|
||||||
) -> Self::Output {
|
) -> Self::Output {
|
||||||
let is_mouse_over = bounds.contains(cursor_position);
|
let is_mouse_over = bounds.contains(cursor_position);
|
||||||
|
|
||||||
// TODO: Render proper shadows
|
let styling = if is_disabled {
|
||||||
// TODO: Make hovering and pressed styles configurable
|
style.disabled()
|
||||||
let shadow_offset = if is_mouse_over {
|
} else if is_mouse_over {
|
||||||
if is_pressed {
|
if is_pressed {
|
||||||
0.0
|
style.pressed()
|
||||||
} else {
|
} else {
|
||||||
2.0
|
style.hovered()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
1.0
|
style.active()
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
let (content, _) = content.draw(
|
||||||
match background {
|
self,
|
||||||
None => content,
|
&Defaults {
|
||||||
Some(background) => Primitive::Group {
|
text: defaults::Text {
|
||||||
primitives: vec![
|
color: styling.text_color,
|
||||||
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,
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
|
..*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 {
|
if is_mouse_over {
|
||||||
MouseCursor::Pointer
|
MouseCursor::Pointer
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
use crate::{Primitive, Renderer};
|
use crate::{checkbox::StyleSheet, Primitive, Renderer};
|
||||||
use iced_native::{
|
use iced_native::{
|
||||||
checkbox, Background, HorizontalAlignment, MouseCursor, Rectangle,
|
checkbox, HorizontalAlignment, MouseCursor, Rectangle, VerticalAlignment,
|
||||||
VerticalAlignment,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const SIZE: f32 = 28.0;
|
const SIZE: f32 = 28.0;
|
||||||
|
|
||||||
impl checkbox::Renderer for Renderer {
|
impl checkbox::Renderer for Renderer {
|
||||||
|
type Style = Box<dyn StyleSheet>;
|
||||||
|
|
||||||
fn default_size(&self) -> u32 {
|
fn default_size(&self) -> u32 {
|
||||||
SIZE as u32
|
SIZE as u32
|
||||||
}
|
}
|
||||||
|
|
@ -17,31 +18,21 @@ impl checkbox::Renderer for Renderer {
|
||||||
is_checked: bool,
|
is_checked: bool,
|
||||||
is_mouse_over: bool,
|
is_mouse_over: bool,
|
||||||
(label, _): Self::Output,
|
(label, _): Self::Output,
|
||||||
|
style_sheet: &Self::Style,
|
||||||
) -> Self::Output {
|
) -> Self::Output {
|
||||||
let (checkbox_border, checkbox_box) = (
|
let style = if is_mouse_over {
|
||||||
Primitive::Quad {
|
style_sheet.hovered(is_checked)
|
||||||
bounds,
|
} else {
|
||||||
background: Background::Color([0.6, 0.6, 0.6].into()),
|
style_sheet.active(is_checked)
|
||||||
border_radius: 6,
|
};
|
||||||
},
|
|
||||||
Primitive::Quad {
|
let checkbox = Primitive::Quad {
|
||||||
bounds: Rectangle {
|
bounds,
|
||||||
x: bounds.x + 1.0,
|
background: style.background,
|
||||||
y: bounds.y + 1.0,
|
border_radius: style.border_radius,
|
||||||
width: bounds.width - 2.0,
|
border_width: style.border_width,
|
||||||
height: bounds.height - 2.0,
|
border_color: style.border_color,
|
||||||
},
|
};
|
||||||
background: Background::Color(
|
|
||||||
if is_mouse_over {
|
|
||||||
[0.90, 0.90, 0.90]
|
|
||||||
} else {
|
|
||||||
[0.95, 0.95, 0.95]
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
),
|
|
||||||
border_radius: 5,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
(
|
(
|
||||||
Primitive::Group {
|
Primitive::Group {
|
||||||
|
|
@ -51,14 +42,14 @@ impl checkbox::Renderer for Renderer {
|
||||||
font: crate::text::BUILTIN_ICONS,
|
font: crate::text::BUILTIN_ICONS,
|
||||||
size: bounds.height * 0.7,
|
size: bounds.height * 0.7,
|
||||||
bounds: bounds,
|
bounds: bounds,
|
||||||
color: [0.3, 0.3, 0.3].into(),
|
color: style.checkmark_color,
|
||||||
horizontal_alignment: HorizontalAlignment::Center,
|
horizontal_alignment: HorizontalAlignment::Center,
|
||||||
vertical_alignment: VerticalAlignment::Center,
|
vertical_alignment: VerticalAlignment::Center,
|
||||||
};
|
};
|
||||||
|
|
||||||
vec![checkbox_border, checkbox_box, check, label]
|
vec![checkbox, check, label]
|
||||||
} else {
|
} else {
|
||||||
vec![checkbox_border, checkbox_box, label]
|
vec![checkbox, label]
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
if is_mouse_over {
|
if is_mouse_over {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use iced_native::{column, Element, Layout, MouseCursor, Point};
|
||||||
impl column::Renderer for Renderer {
|
impl column::Renderer for Renderer {
|
||||||
fn draw<Message>(
|
fn draw<Message>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
defaults: &Self::Defaults,
|
||||||
content: &[Element<'_, Message, Self>],
|
content: &[Element<'_, Message, Self>],
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
|
|
@ -17,7 +18,7 @@ impl column::Renderer for Renderer {
|
||||||
.zip(layout.children())
|
.zip(layout.children())
|
||||||
.map(|(child, layout)| {
|
.map(|(child, layout)| {
|
||||||
let (primitive, new_mouse_cursor) =
|
let (primitive, new_mouse_cursor) =
|
||||||
child.draw(self, layout, cursor_position);
|
child.draw(self, defaults, layout, cursor_position);
|
||||||
|
|
||||||
if new_mouse_cursor > mouse_cursor {
|
if new_mouse_cursor > mouse_cursor {
|
||||||
mouse_cursor = new_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 crate::{progress_bar::StyleSheet, Primitive, Renderer};
|
||||||
use iced_native::{progress_bar, Background, Color, MouseCursor, Rectangle};
|
use iced_native::{progress_bar, Color, MouseCursor, Rectangle};
|
||||||
|
|
||||||
impl progress_bar::Renderer for Renderer {
|
impl progress_bar::Renderer for Renderer {
|
||||||
|
type Style = Box<dyn StyleSheet>;
|
||||||
|
|
||||||
const DEFAULT_HEIGHT: u16 = 30;
|
const DEFAULT_HEIGHT: u16 = 30;
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
|
@ -9,9 +11,10 @@ impl progress_bar::Renderer for Renderer {
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
range: std::ops::RangeInclusive<f32>,
|
range: std::ops::RangeInclusive<f32>,
|
||||||
value: f32,
|
value: f32,
|
||||||
background: Option<Background>,
|
style_sheet: &Self::Style,
|
||||||
active_color: Option<Color>,
|
|
||||||
) -> Self::Output {
|
) -> Self::Output {
|
||||||
|
let style = style_sheet.style();
|
||||||
|
|
||||||
let (range_start, range_end) = range.into_inner();
|
let (range_start, range_end) = range.into_inner();
|
||||||
let active_progress_width = bounds.width
|
let active_progress_width = bounds.width
|
||||||
* ((value - range_start) / (range_end - range_start).max(1.0));
|
* ((value - range_start) / (range_end - range_start).max(1.0));
|
||||||
|
|
@ -19,27 +22,31 @@ impl progress_bar::Renderer for Renderer {
|
||||||
let background = Primitive::Group {
|
let background = Primitive::Group {
|
||||||
primitives: vec![Primitive::Quad {
|
primitives: vec![Primitive::Quad {
|
||||||
bounds: Rectangle { ..bounds },
|
bounds: Rectangle { ..bounds },
|
||||||
background: background
|
background: style.background,
|
||||||
.unwrap_or(Background::Color([0.6, 0.6, 0.6].into()))
|
border_radius: style.border_radius,
|
||||||
.into(),
|
border_width: 0,
|
||||||
border_radius: 5,
|
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 {
|
if active_progress_width > 0.0 {
|
||||||
primitives: vec![background, active_progress],
|
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,
|
MouseCursor::OutOfBounds,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
use crate::{Primitive, Renderer};
|
use crate::{radio::StyleSheet, Primitive, Renderer};
|
||||||
use iced_native::{radio, Background, MouseCursor, Rectangle};
|
use iced_native::{radio, Background, Color, MouseCursor, Rectangle};
|
||||||
|
|
||||||
const SIZE: f32 = 28.0;
|
const SIZE: f32 = 28.0;
|
||||||
const DOT_SIZE: f32 = SIZE / 2.0;
|
const DOT_SIZE: f32 = SIZE / 2.0;
|
||||||
|
|
||||||
impl radio::Renderer for Renderer {
|
impl radio::Renderer for Renderer {
|
||||||
|
type Style = Box<dyn StyleSheet>;
|
||||||
|
|
||||||
fn default_size(&self) -> u32 {
|
fn default_size(&self) -> u32 {
|
||||||
SIZE as u32
|
SIZE as u32
|
||||||
}
|
}
|
||||||
|
|
@ -15,31 +17,21 @@ impl radio::Renderer for Renderer {
|
||||||
is_selected: bool,
|
is_selected: bool,
|
||||||
is_mouse_over: bool,
|
is_mouse_over: bool,
|
||||||
(label, _): Self::Output,
|
(label, _): Self::Output,
|
||||||
|
style_sheet: &Self::Style,
|
||||||
) -> Self::Output {
|
) -> Self::Output {
|
||||||
let (radio_border, radio_box) = (
|
let style = if is_mouse_over {
|
||||||
Primitive::Quad {
|
style_sheet.hovered()
|
||||||
bounds,
|
} else {
|
||||||
background: Background::Color([0.6, 0.6, 0.6].into()),
|
style_sheet.active()
|
||||||
border_radius: (SIZE / 2.0) as u16,
|
};
|
||||||
},
|
|
||||||
Primitive::Quad {
|
let radio = Primitive::Quad {
|
||||||
bounds: Rectangle {
|
bounds,
|
||||||
x: bounds.x + 1.0,
|
background: style.background,
|
||||||
y: bounds.y + 1.0,
|
border_radius: (SIZE / 2.0) as u16,
|
||||||
width: bounds.width - 2.0,
|
border_width: style.border_width,
|
||||||
height: bounds.height - 2.0,
|
border_color: style.border_color,
|
||||||
},
|
};
|
||||||
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,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
(
|
(
|
||||||
Primitive::Group {
|
Primitive::Group {
|
||||||
|
|
@ -51,13 +43,15 @@ impl radio::Renderer for Renderer {
|
||||||
width: bounds.width - DOT_SIZE,
|
width: bounds.width - DOT_SIZE,
|
||||||
height: bounds.height - 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_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 {
|
} else {
|
||||||
vec![radio_border, radio_box, label]
|
vec![radio, label]
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
if is_mouse_over {
|
if is_mouse_over {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use iced_native::{row, Element, Layout, MouseCursor, Point};
|
||||||
impl row::Renderer for Renderer {
|
impl row::Renderer for Renderer {
|
||||||
fn draw<Message>(
|
fn draw<Message>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
defaults: &Self::Defaults,
|
||||||
children: &[Element<'_, Message, Self>],
|
children: &[Element<'_, Message, Self>],
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
|
|
@ -17,7 +18,7 @@ impl row::Renderer for Renderer {
|
||||||
.zip(layout.children())
|
.zip(layout.children())
|
||||||
.map(|(child, layout)| {
|
.map(|(child, layout)| {
|
||||||
let (primitive, new_mouse_cursor) =
|
let (primitive, new_mouse_cursor) =
|
||||||
child.draw(self, layout, cursor_position);
|
child.draw(self, defaults, layout, cursor_position);
|
||||||
|
|
||||||
if new_mouse_cursor > mouse_cursor {
|
if new_mouse_cursor > mouse_cursor {
|
||||||
mouse_cursor = new_mouse_cursor;
|
mouse_cursor = new_mouse_cursor;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
use crate::{Primitive, Renderer};
|
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_WIDTH: u16 = 10;
|
||||||
const SCROLLBAR_MARGIN: u16 = 2;
|
const SCROLLBAR_MARGIN: u16 = 2;
|
||||||
|
|
||||||
impl scrollable::Renderer for Renderer {
|
impl scrollable::Renderer for Renderer {
|
||||||
|
type Style = Box<dyn iced_style::scrollable::StyleSheet>;
|
||||||
|
|
||||||
fn scrollbar(
|
fn scrollbar(
|
||||||
&self,
|
&self,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
|
|
@ -51,6 +55,7 @@ impl scrollable::Renderer for Renderer {
|
||||||
is_mouse_over_scrollbar: bool,
|
is_mouse_over_scrollbar: bool,
|
||||||
scrollbar: Option<scrollable::Scrollbar>,
|
scrollbar: Option<scrollable::Scrollbar>,
|
||||||
offset: u32,
|
offset: u32,
|
||||||
|
style_sheet: &Self::Style,
|
||||||
(content, mouse_cursor): Self::Output,
|
(content, mouse_cursor): Self::Output,
|
||||||
) -> Self::Output {
|
) -> Self::Output {
|
||||||
let clip = Primitive::Clip {
|
let clip = Primitive::Clip {
|
||||||
|
|
@ -61,40 +66,53 @@ impl scrollable::Renderer for Renderer {
|
||||||
|
|
||||||
(
|
(
|
||||||
if let Some(scrollbar) = scrollbar {
|
if let Some(scrollbar) = scrollbar {
|
||||||
if is_mouse_over || state.is_scroller_grabbed() {
|
let style = if state.is_scroller_grabbed() {
|
||||||
let scroller = Primitive::Quad {
|
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,
|
bounds: scrollbar.scroller.bounds,
|
||||||
background: Background::Color(
|
background: Background::Color(style.scroller.color),
|
||||||
[0.0, 0.0, 0.0, 0.7].into(),
|
border_radius: style.scroller.border_radius,
|
||||||
),
|
border_width: style.scroller.border_width,
|
||||||
border_radius: 5,
|
border_color: style.scroller.border_color,
|
||||||
};
|
|
||||||
|
|
||||||
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],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
clip
|
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};
|
use iced_native::{slider, Background, Color, MouseCursor, Point, Rectangle};
|
||||||
|
|
||||||
const HANDLE_WIDTH: f32 = 8.0;
|
|
||||||
const HANDLE_HEIGHT: f32 = 22.0;
|
const HANDLE_HEIGHT: f32 = 22.0;
|
||||||
|
|
||||||
impl slider::Renderer for Renderer {
|
impl slider::Renderer for Renderer {
|
||||||
|
type Style = Box<dyn StyleSheet>;
|
||||||
|
|
||||||
fn height(&self) -> u32 {
|
fn height(&self) -> u32 {
|
||||||
30
|
30
|
||||||
}
|
}
|
||||||
|
|
@ -16,9 +20,18 @@ impl slider::Renderer for Renderer {
|
||||||
range: std::ops::RangeInclusive<f32>,
|
range: std::ops::RangeInclusive<f32>,
|
||||||
value: f32,
|
value: f32,
|
||||||
is_dragging: bool,
|
is_dragging: bool,
|
||||||
|
style_sheet: &Self::Style,
|
||||||
) -> Self::Output {
|
) -> Self::Output {
|
||||||
let is_mouse_over = bounds.contains(cursor_position);
|
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_y = bounds.y + (bounds.height / 2.0).round();
|
||||||
|
|
||||||
let (rail_top, rail_bottom) = (
|
let (rail_top, rail_bottom) = (
|
||||||
|
|
@ -29,8 +42,10 @@ impl slider::Renderer for Renderer {
|
||||||
width: bounds.width,
|
width: bounds.width,
|
||||||
height: 2.0,
|
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_radius: 0,
|
||||||
|
border_width: 0,
|
||||||
|
border_color: Color::TRANSPARENT,
|
||||||
},
|
},
|
||||||
Primitive::Quad {
|
Primitive::Quad {
|
||||||
bounds: Rectangle {
|
bounds: Rectangle {
|
||||||
|
|
@ -39,51 +54,45 @@ impl slider::Renderer for Renderer {
|
||||||
width: bounds.width,
|
width: bounds.width,
|
||||||
height: 2.0,
|
height: 2.0,
|
||||||
},
|
},
|
||||||
background: Background::Color(Color::WHITE),
|
background: Background::Color(style.rail_colors.1),
|
||||||
border_radius: 0,
|
border_radius: 0,
|
||||||
|
border_width: 0,
|
||||||
|
border_color: Color::TRANSPARENT,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let (range_start, range_end) = range.into_inner();
|
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));
|
* ((value - range_start) / (range_end - range_start).max(1.0));
|
||||||
|
|
||||||
let (handle_border, handle) = (
|
let handle = Primitive::Quad {
|
||||||
Primitive::Quad {
|
bounds: Rectangle {
|
||||||
bounds: Rectangle {
|
x: bounds.x + handle_offset.round(),
|
||||||
x: bounds.x + handle_offset.round() - 1.0,
|
y: rail_y - handle_height / 2.0,
|
||||||
y: rail_y - HANDLE_HEIGHT / 2.0 - 1.0,
|
width: handle_width,
|
||||||
width: HANDLE_WIDTH + 2.0,
|
height: handle_height,
|
||||||
height: HANDLE_HEIGHT + 2.0,
|
|
||||||
},
|
|
||||||
background: Color::from_rgb(0.6, 0.6, 0.6).into(),
|
|
||||||
border_radius: 5,
|
|
||||||
},
|
},
|
||||||
Primitive::Quad {
|
background: Background::Color(style.handle.color),
|
||||||
bounds: Rectangle {
|
border_radius: handle_border_radius,
|
||||||
x: bounds.x + handle_offset.round(),
|
border_width: style.handle.border_width,
|
||||||
y: rail_y - HANDLE_HEIGHT / 2.0,
|
border_color: style.handle.border_color,
|
||||||
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,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
(
|
(
|
||||||
Primitive::Group {
|
Primitive::Group {
|
||||||
primitives: vec![rail_top, rail_bottom, handle_border, handle],
|
primitives: vec![rail_top, rail_bottom, handle],
|
||||||
},
|
},
|
||||||
if is_dragging {
|
if is_dragging {
|
||||||
MouseCursor::Grabbing
|
MouseCursor::Grabbing
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ impl text::Renderer for Renderer {
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
defaults: &Self::Defaults,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
content: &str,
|
content: &str,
|
||||||
size: u16,
|
size: u16,
|
||||||
|
|
@ -40,7 +41,7 @@ impl text::Renderer for Renderer {
|
||||||
content: content.to_string(),
|
content: content.to_string(),
|
||||||
size: f32::from(size),
|
size: f32::from(size),
|
||||||
bounds,
|
bounds,
|
||||||
color: color.unwrap_or(Color::BLACK),
|
color: color.unwrap_or(defaults.text.color),
|
||||||
font,
|
font,
|
||||||
horizontal_alignment,
|
horizontal_alignment,
|
||||||
vertical_alignment,
|
vertical_alignment,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{Primitive, Renderer};
|
use crate::{text_input::StyleSheet, Primitive, Renderer};
|
||||||
|
|
||||||
use iced_native::{
|
use iced_native::{
|
||||||
text_input, Background, Color, Font, HorizontalAlignment, MouseCursor,
|
text_input, Background, Color, Font, HorizontalAlignment, MouseCursor,
|
||||||
|
|
@ -7,6 +7,8 @@ use iced_native::{
|
||||||
use std::f32;
|
use std::f32;
|
||||||
|
|
||||||
impl text_input::Renderer for Renderer {
|
impl text_input::Renderer for Renderer {
|
||||||
|
type Style = Box<dyn StyleSheet>;
|
||||||
|
|
||||||
fn default_size(&self) -> u16 {
|
fn default_size(&self) -> u16 {
|
||||||
// TODO: Make this configurable
|
// TODO: Make this configurable
|
||||||
20
|
20
|
||||||
|
|
@ -61,31 +63,24 @@ impl text_input::Renderer for Renderer {
|
||||||
placeholder: &str,
|
placeholder: &str,
|
||||||
value: &text_input::Value,
|
value: &text_input::Value,
|
||||||
state: &text_input::State,
|
state: &text_input::State,
|
||||||
|
style_sheet: &Self::Style,
|
||||||
) -> Self::Output {
|
) -> Self::Output {
|
||||||
let is_mouse_over = bounds.contains(cursor_position);
|
let is_mouse_over = bounds.contains(cursor_position);
|
||||||
|
|
||||||
let border = Primitive::Quad {
|
let style = if state.is_focused() {
|
||||||
bounds,
|
style_sheet.focused()
|
||||||
background: Background::Color(
|
} else if is_mouse_over {
|
||||||
if is_mouse_over || state.is_focused() {
|
style_sheet.hovered()
|
||||||
[0.5, 0.5, 0.5]
|
} else {
|
||||||
} else {
|
style_sheet.active()
|
||||||
[0.7, 0.7, 0.7]
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
),
|
|
||||||
border_radius: 5,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let input = Primitive::Quad {
|
let input = Primitive::Quad {
|
||||||
bounds: Rectangle {
|
bounds,
|
||||||
x: bounds.x + 1.0,
|
background: style.background,
|
||||||
y: bounds.y + 1.0,
|
border_radius: style.border_radius,
|
||||||
width: bounds.width - 2.0,
|
border_width: style.border_width,
|
||||||
height: bounds.height - 2.0,
|
border_color: style.border_color,
|
||||||
},
|
|
||||||
background: Background::Color(Color::WHITE),
|
|
||||||
border_radius: 4,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let text = value.to_string();
|
let text = value.to_string();
|
||||||
|
|
@ -97,9 +92,9 @@ impl text_input::Renderer for Renderer {
|
||||||
text.clone()
|
text.clone()
|
||||||
},
|
},
|
||||||
color: if text.is_empty() {
|
color: if text.is_empty() {
|
||||||
[0.7, 0.7, 0.7]
|
style_sheet.placeholder_color()
|
||||||
} else {
|
} else {
|
||||||
[0.3, 0.3, 0.3]
|
style_sheet.value_color()
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
font: Font::Default,
|
font: Font::Default,
|
||||||
|
|
@ -128,8 +123,10 @@ impl text_input::Renderer for Renderer {
|
||||||
width: 1.0,
|
width: 1.0,
|
||||||
height: text_bounds.height,
|
height: text_bounds.height,
|
||||||
},
|
},
|
||||||
background: Background::Color(Color::BLACK),
|
background: Background::Color(style_sheet.value_color()),
|
||||||
border_radius: 0,
|
border_radius: 0,
|
||||||
|
border_width: 0,
|
||||||
|
border_color: Color::TRANSPARENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
|
|
@ -150,7 +147,7 @@ impl text_input::Renderer for Renderer {
|
||||||
|
|
||||||
(
|
(
|
||||||
Primitive::Group {
|
Primitive::Group {
|
||||||
primitives: vec![border, input, contents],
|
primitives: vec![input, contents],
|
||||||
},
|
},
|
||||||
if is_mouse_over {
|
if is_mouse_over {
|
||||||
MouseCursor::Text
|
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
|
#version 450
|
||||||
|
|
||||||
layout(location = 0) in vec4 v_Color;
|
layout(location = 0) in vec4 v_Color;
|
||||||
layout(location = 1) in vec2 v_Pos;
|
layout(location = 1) in vec4 v_BorderColor;
|
||||||
layout(location = 2) in vec2 v_Scale;
|
layout(location = 2) in vec2 v_Pos;
|
||||||
layout(location = 3) in float v_BorderRadius;
|
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;
|
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 inner_size = size - vec2(radius, radius) * 2.0;
|
||||||
vec2 top_left = position + vec2(radius, radius);
|
vec2 top_left = position + vec2(radius, radius);
|
||||||
vec2 bottom_right = top_left + inner_size;
|
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)
|
max(max(top_left_distance.y, bottom_right_distance.y), 0)
|
||||||
);
|
);
|
||||||
|
|
||||||
float d = sqrt(distance.x * distance.x + distance.y * distance.y);
|
return sqrt(distance.x * distance.x + distance.y * distance.y);
|
||||||
|
|
||||||
return 1.0 - smoothstep(radius - s, radius + s, d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
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 = 1) in vec2 i_Pos;
|
||||||
layout(location = 2) in vec2 i_Scale;
|
layout(location = 2) in vec2 i_Scale;
|
||||||
layout(location = 3) in vec4 i_Color;
|
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 {
|
layout (set = 0, binding = 0) uniform Globals {
|
||||||
mat4 u_Transform;
|
mat4 u_Transform;
|
||||||
|
|
@ -12,9 +14,11 @@ layout (set = 0, binding = 0) uniform Globals {
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(location = 0) out vec4 o_Color;
|
layout(location = 0) out vec4 o_Color;
|
||||||
layout(location = 1) out vec2 o_Pos;
|
layout(location = 1) out vec4 o_BorderColor;
|
||||||
layout(location = 2) out vec2 o_Scale;
|
layout(location = 2) out vec2 o_Pos;
|
||||||
layout(location = 3) out float o_BorderRadius;
|
layout(location = 3) out vec2 o_Scale;
|
||||||
|
layout(location = 4) out float o_BorderRadius;
|
||||||
|
layout(location = 5) out float o_BorderWidth;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 p_Pos = i_Pos * u_Scale;
|
vec2 p_Pos = i_Pos * u_Scale;
|
||||||
|
|
@ -28,9 +32,11 @@ void main() {
|
||||||
);
|
);
|
||||||
|
|
||||||
o_Color = i_Color;
|
o_Color = i_Color;
|
||||||
|
o_BorderColor = i_BorderColor;
|
||||||
o_Pos = p_Pos;
|
o_Pos = p_Pos;
|
||||||
o_Scale = p_Scale;
|
o_Scale = p_Scale;
|
||||||
o_BorderRadius = i_BorderRadius * u_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);
|
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 {
|
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
|
// TODO: Font customization
|
||||||
let font_source = font::Source::new();
|
let font_source = font::Source::new();
|
||||||
|
|
||||||
let default_font = font_source
|
let default_font =
|
||||||
.load(&[font::Family::SansSerif, font::Family::Serif])
|
default_font.map(|slice| slice.to_vec()).unwrap_or_else(|| {
|
||||||
.unwrap_or_else(|_| FALLBACK_FONT.to_vec());
|
font_source
|
||||||
|
.load(&[font::Family::SansSerif, font::Family::Serif])
|
||||||
|
.unwrap_or_else(|_| FALLBACK_FONT.to_vec())
|
||||||
|
});
|
||||||
|
|
||||||
let load_glyph_brush = |font: Vec<u8>| {
|
let load_glyph_brush = |font: Vec<u8>| {
|
||||||
let builder =
|
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"
|
description = "A winit runtime for Iced"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/hecrj/iced"
|
repository = "https://github.com/hecrj/iced"
|
||||||
|
documentation = "https://docs.rs/iced_winit"
|
||||||
|
keywords = ["gui", "ui", "graphics", "interface", "widgets"]
|
||||||
|
categories = ["gui"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
debug = []
|
debug = []
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
conversion,
|
container, conversion,
|
||||||
input::{keyboard, mouse},
|
input::{keyboard, mouse},
|
||||||
renderer::{Target, Windowed},
|
renderer::{Target, Windowed},
|
||||||
subscription, Cache, Clipboard, Command, Container, Debug, Element, Event,
|
subscription, Cache, Clipboard, Command, Container, Debug, Element, Event,
|
||||||
|
|
@ -18,7 +18,7 @@ pub trait Application: Sized {
|
||||||
/// The renderer to use to draw the [`Application`].
|
/// The renderer to use to draw the [`Application`].
|
||||||
///
|
///
|
||||||
/// [`Application`]: trait.Application.html
|
/// [`Application`]: trait.Application.html
|
||||||
type Renderer: Windowed;
|
type Renderer: Windowed + container::Renderer;
|
||||||
|
|
||||||
/// The type of __messages__ your [`Application`] will produce.
|
/// 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.
|
/// It should probably be that last thing you call in your `main` function.
|
||||||
///
|
///
|
||||||
/// [`Application`]: trait.Application.html
|
/// [`Application`]: trait.Application.html
|
||||||
fn run(settings: Settings)
|
fn run(
|
||||||
where
|
settings: Settings,
|
||||||
|
renderer_settings: <Self::Renderer as Windowed>::Settings,
|
||||||
|
) where
|
||||||
Self: 'static,
|
Self: 'static,
|
||||||
{
|
{
|
||||||
use winit::{
|
use winit::{
|
||||||
|
|
@ -140,7 +142,7 @@ pub trait Application: Sized {
|
||||||
let mut resized = false;
|
let mut resized = false;
|
||||||
|
|
||||||
let clipboard = Clipboard::new(&window);
|
let clipboard = Clipboard::new(&window);
|
||||||
let mut renderer = Self::Renderer::new();
|
let mut renderer = Self::Renderer::new(renderer_settings);
|
||||||
|
|
||||||
let mut target = {
|
let mut target = {
|
||||||
let (width, height) = to_physical(size, dpi);
|
let (width, height) = to_physical(size, dpi);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
//! Configure your application.
|
//! Configure your application.
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
#[path = "windows.rs"]
|
#[path = "windows.rs"]
|
||||||
mod platform;
|
mod platform;
|
||||||
|
|
@ -10,7 +9,7 @@ mod platform;
|
||||||
pub use platform::PlatformSpecific;
|
pub use platform::PlatformSpecific;
|
||||||
|
|
||||||
/// The settings of an application.
|
/// The settings of an application.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct Settings {
|
pub struct Settings {
|
||||||
/// The [`Window`] settings
|
/// The [`Window`] settings
|
||||||
///
|
///
|
||||||
|
|
@ -18,6 +17,14 @@ pub struct Settings {
|
||||||
pub window: Window,
|
pub window: Window,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Settings {
|
||||||
|
fn default() -> Settings {
|
||||||
|
Settings {
|
||||||
|
window: Window::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The window settings of an application.
|
/// The window settings of an application.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue