Make iced_core::Button customizable
Now it supports: - Any kind of content - Custom border radius - Custom background
This commit is contained in:
parent
a0234d5bce
commit
10e10e5e06
35 changed files with 288 additions and 160 deletions
|
|
@ -19,6 +19,8 @@ members = [
|
|||
"core",
|
||||
"native",
|
||||
"web",
|
||||
"wgpu",
|
||||
"winit",
|
||||
]
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
|
|
|
|||
7
core/src/background.rs
Normal file
7
core/src/background.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
use crate::Color;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Background {
|
||||
Color(Color),
|
||||
// TODO: Add gradient and image variants
|
||||
}
|
||||
|
|
@ -17,6 +17,14 @@ impl Color {
|
|||
a: 1.0,
|
||||
};
|
||||
|
||||
/// The white color.
|
||||
pub const WHITE: Color = Color {
|
||||
r: 1.0,
|
||||
g: 1.0,
|
||||
b: 1.0,
|
||||
a: 1.0,
|
||||
};
|
||||
|
||||
pub fn into_linear(self) -> [f32; 4] {
|
||||
// As described in:
|
||||
// https://en.wikipedia.org/wiki/SRGB#The_reverse_transformation
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
pub mod widget;
|
||||
|
||||
mod align;
|
||||
mod background;
|
||||
mod color;
|
||||
mod justify;
|
||||
mod length;
|
||||
|
|
@ -9,6 +10,7 @@ mod rectangle;
|
|||
mod vector;
|
||||
|
||||
pub use align::Align;
|
||||
pub use background::Background;
|
||||
pub use color::Color;
|
||||
pub use justify::Justify;
|
||||
pub use length::Length;
|
||||
|
|
|
|||
|
|
@ -5,68 +5,58 @@
|
|||
//! [`Button`]: struct.Button.html
|
||||
//! [`State`]: struct.State.html
|
||||
|
||||
use crate::{Align, Length};
|
||||
use crate::{Align, Background, Length};
|
||||
|
||||
/// A generic widget that produces a message when clicked.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use iced_core::{button, Button};
|
||||
///
|
||||
/// pub enum Message {
|
||||
/// ButtonClicked,
|
||||
/// }
|
||||
///
|
||||
/// let state = &mut button::State::new();
|
||||
///
|
||||
/// Button::new(state, "Click me!")
|
||||
/// .on_press(Message::ButtonClicked);
|
||||
/// ```
|
||||
///
|
||||
/// 
|
||||
pub struct Button<'a, Message> {
|
||||
pub struct Button<'a, Message, Element> {
|
||||
/// The current state of the button
|
||||
pub state: &'a mut State,
|
||||
|
||||
/// The label of the button
|
||||
pub label: String,
|
||||
pub content: Element,
|
||||
|
||||
/// The message to produce when the button is pressed
|
||||
pub on_press: Option<Message>,
|
||||
|
||||
pub class: Class,
|
||||
|
||||
pub width: Length,
|
||||
|
||||
pub padding: u16,
|
||||
|
||||
pub background: Option<Background>,
|
||||
|
||||
pub border_radius: u16,
|
||||
|
||||
pub align_self: Option<Align>,
|
||||
}
|
||||
|
||||
impl<'a, Message> std::fmt::Debug for Button<'a, Message>
|
||||
impl<'a, Message, Element> std::fmt::Debug for Button<'a, Message, Element>
|
||||
where
|
||||
Message: std::fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Button")
|
||||
.field("state", &self.state)
|
||||
.field("label", &self.label)
|
||||
.field("on_press", &self.on_press)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Message> Button<'a, Message> {
|
||||
impl<'a, Message, Element> Button<'a, Message, Element> {
|
||||
/// Creates a new [`Button`] with some local [`State`] and the given label.
|
||||
///
|
||||
/// [`Button`]: struct.Button.html
|
||||
/// [`State`]: struct.State.html
|
||||
pub fn new(state: &'a mut State, label: &str) -> Self {
|
||||
pub fn new<E>(state: &'a mut State, content: E) -> Self
|
||||
where
|
||||
E: Into<Element>,
|
||||
{
|
||||
Button {
|
||||
state,
|
||||
label: String::from(label),
|
||||
content: content.into(),
|
||||
on_press: None,
|
||||
class: Class::Primary,
|
||||
width: Length::Shrink,
|
||||
padding: 0,
|
||||
background: None,
|
||||
border_radius: 0,
|
||||
align_self: None,
|
||||
}
|
||||
}
|
||||
|
|
@ -79,6 +69,21 @@ impl<'a, Message> Button<'a, Message> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn padding(mut self, padding: u16) -> Self {
|
||||
self.padding = padding;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn background(mut self, background: Background) -> Self {
|
||||
self.background = Some(background);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn border_radius(mut self, border_radius: u16) -> Self {
|
||||
self.border_radius = border_radius;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the alignment of the [`Button`] itself.
|
||||
///
|
||||
/// This is useful if you want to override the default alignment given by
|
||||
|
|
@ -90,16 +95,6 @@ impl<'a, Message> Button<'a, Message> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Sets the [`Class`] of the [`Button`].
|
||||
///
|
||||
///
|
||||
/// [`Button`]: struct.Button.html
|
||||
/// [`Class`]: enum.Class.html
|
||||
pub fn class(mut self, class: Class) -> Self {
|
||||
self.class = class;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the message that will be produced when the [`Button`] is pressed.
|
||||
///
|
||||
/// [`Button`]: struct.Button.html
|
||||
|
|
@ -133,26 +128,3 @@ impl State {
|
|||
self.is_pressed
|
||||
}
|
||||
}
|
||||
|
||||
/// The type of a [`Button`].
|
||||
///
|
||||
/// 
|
||||
///
|
||||
/// [`Button`]: struct.Button.html
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Class {
|
||||
/// The [`Button`] performs the main action.
|
||||
///
|
||||
/// [`Button`]: struct.Button.html
|
||||
Primary,
|
||||
|
||||
/// The [`Button`] performs an alternative action.
|
||||
///
|
||||
/// [`Button`]: struct.Button.html
|
||||
Secondary,
|
||||
|
||||
/// The [`Button`] performs a productive action.
|
||||
///
|
||||
/// [`Button`]: struct.Button.html
|
||||
Positive,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//! Write some text for your users to read.
|
||||
use crate::{Color, Length};
|
||||
use crate::{Align, Color, Length};
|
||||
|
||||
/// A paragraph of text.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use iced::{
|
||||
button, slider, text::HorizontalAlignment, Align, Button, Checkbox, Color,
|
||||
Column, Element, Image, Justify, Length, Radio, Row, Slider, Text,
|
||||
UserInterface,
|
||||
button, slider, text::HorizontalAlignment, Align, Background, Button,
|
||||
Checkbox, Color, Column, Element, Image, Justify, Length, Radio, Row,
|
||||
Slider, Text, UserInterface,
|
||||
};
|
||||
|
||||
pub fn main() {
|
||||
|
|
@ -59,9 +59,8 @@ impl UserInterface for Tour {
|
|||
|
||||
if steps.has_previous() {
|
||||
controls = controls.push(
|
||||
Button::new(back_button, "Back")
|
||||
.on_press(Message::BackPressed)
|
||||
.class(button::Class::Secondary),
|
||||
secondary_button(back_button, "Back")
|
||||
.on_press(Message::BackPressed),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +68,8 @@ impl UserInterface for Tour {
|
|||
|
||||
if steps.can_continue() {
|
||||
controls = controls.push(
|
||||
Button::new(next_button, "Next").on_press(Message::NextPressed),
|
||||
primary_button(next_button, "Next")
|
||||
.on_press(Message::NextPressed),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -546,6 +546,44 @@ impl<'a> Step {
|
|||
}
|
||||
}
|
||||
|
||||
fn button<'a, Message>(
|
||||
state: &'a mut button::State,
|
||||
label: &str,
|
||||
) -> Button<'a, Message> {
|
||||
Button::new(
|
||||
state,
|
||||
Text::new(label)
|
||||
.color(Color::WHITE)
|
||||
.horizontal_alignment(HorizontalAlignment::Center),
|
||||
)
|
||||
.padding(10)
|
||||
.border_radius(10)
|
||||
}
|
||||
|
||||
fn primary_button<'a, Message>(
|
||||
state: &'a mut button::State,
|
||||
label: &str,
|
||||
) -> Button<'a, Message> {
|
||||
button(state, label).background(Background::Color(Color {
|
||||
r: 0.3,
|
||||
g: 0.3,
|
||||
b: 0.8,
|
||||
a: 1.0,
|
||||
}))
|
||||
}
|
||||
|
||||
fn secondary_button<'a, Message>(
|
||||
state: &'a mut button::State,
|
||||
label: &str,
|
||||
) -> Button<'a, Message> {
|
||||
button(state, label).background(Background::Color(Color {
|
||||
r: 0.8,
|
||||
g: 0.8,
|
||||
b: 0.8,
|
||||
a: 1.0,
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Language {
|
||||
Rust,
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn node(&self, renderer: &Renderer) -> Node {
|
||||
self.widget.node(renderer)
|
||||
}
|
||||
|
||||
pub fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
|
|
@ -97,22 +101,22 @@ where
|
|||
///
|
||||
/// ```
|
||||
/// # mod counter {
|
||||
/// # use iced_native::{button, Button};
|
||||
/// # use iced_native::{text, Text};
|
||||
/// #
|
||||
/// # #[derive(Debug, Clone, Copy)]
|
||||
/// # pub enum Message {}
|
||||
/// # pub struct Counter(button::State);
|
||||
/// # pub struct Counter;
|
||||
/// #
|
||||
/// # impl Counter {
|
||||
/// # pub fn view(&mut self) -> Button<Message> {
|
||||
/// # Button::new(&mut self.0, "_")
|
||||
/// # pub fn view(&mut self) -> Text {
|
||||
/// # Text::new("")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # }
|
||||
/// #
|
||||
/// # mod iced_wgpu {
|
||||
/// # use iced_native::{
|
||||
/// # button, row, Button, Node, Point, Rectangle, Style, Layout, Row
|
||||
/// # text, row, Text, Node, Point, Rectangle, Style, Layout, Row
|
||||
/// # };
|
||||
/// # pub struct Renderer;
|
||||
/// #
|
||||
|
|
@ -127,16 +131,15 @@ where
|
|||
/// # ) {}
|
||||
/// # }
|
||||
/// #
|
||||
/// # impl button::Renderer for Renderer {
|
||||
/// # fn node<Message>(&self, _button: &Button<'_, Message>) -> Node {
|
||||
/// # impl text::Renderer for Renderer {
|
||||
/// # fn node(&self, _text: &Text) -> Node {
|
||||
/// # Node::new(Style::default())
|
||||
/// # }
|
||||
/// #
|
||||
/// # fn draw<Message>(
|
||||
/// # fn draw(
|
||||
/// # &mut self,
|
||||
/// # _button: &Button<'_, Message>,
|
||||
/// # _text: &Text,
|
||||
/// # _layout: Layout<'_>,
|
||||
/// # _cursor_position: Point,
|
||||
/// # ) {}
|
||||
/// # }
|
||||
/// # }
|
||||
|
|
@ -289,7 +292,7 @@ where
|
|||
A: Copy,
|
||||
Renderer: crate::Renderer,
|
||||
{
|
||||
fn node(&self, renderer: &mut Renderer) -> Node {
|
||||
fn node(&self, renderer: &Renderer) -> Node {
|
||||
self.widget.node(renderer)
|
||||
}
|
||||
|
||||
|
|
@ -359,7 +362,7 @@ impl<'a, Message, Renderer> Widget<Message, Renderer>
|
|||
where
|
||||
Renderer: crate::Renderer + renderer::Debugger,
|
||||
{
|
||||
fn node(&self, renderer: &mut Renderer) -> Node {
|
||||
fn node(&self, renderer: &Renderer) -> Node {
|
||||
self.element.widget.node(renderer)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -89,14 +89,14 @@
|
|||
//! # impl button::Renderer for Renderer {
|
||||
//! # fn node<Message>(
|
||||
//! # &self,
|
||||
//! # _button: &Button<'_, Message>
|
||||
//! # _button: &Button<'_, Message, Self>
|
||||
//! # ) -> Node {
|
||||
//! # Node::new(Style::default())
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn draw<Message>(
|
||||
//! # &mut self,
|
||||
//! # _button: &Button<'_, Message>,
|
||||
//! # _button: &Button<'_, Message, Self>,
|
||||
//! # _layout: Layout<'_>,
|
||||
//! # _cursor_position: Point,
|
||||
//! # ) {}
|
||||
|
|
@ -125,7 +125,7 @@
|
|||
//! .push(
|
||||
//! // The increment button. We tell it to produce an
|
||||
//! // `IncrementPressed` message when pressed
|
||||
//! Button::new(&mut self.increment_button, "+")
|
||||
//! Button::new(&mut self.increment_button, Text::new("+"))
|
||||
//! .on_press(Message::IncrementPressed),
|
||||
//! )
|
||||
//! .push(
|
||||
|
|
@ -135,7 +135,7 @@
|
|||
//! .push(
|
||||
//! // The decrement button. We tell it to produce a
|
||||
//! // `DecrementPressed` message when pressed
|
||||
//! Button::new(&mut self.decrement_button, "-")
|
||||
//! Button::new(&mut self.decrement_button, Text::new("-"))
|
||||
//! .on_press(Message::DecrementPressed),
|
||||
//! )
|
||||
//! }
|
||||
|
|
@ -212,7 +212,9 @@ mod user_interface;
|
|||
|
||||
pub(crate) use iced_core::Vector;
|
||||
|
||||
pub use iced_core::{Align, Color, Justify, Length, Point, Rectangle};
|
||||
pub use iced_core::{
|
||||
Align, Background, Color, Justify, Length, Point, Rectangle,
|
||||
};
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use stretch::{geometry::Size, number::Number};
|
||||
|
|
|
|||
|
|
@ -74,12 +74,12 @@ impl Style {
|
|||
self
|
||||
}
|
||||
|
||||
pub(crate) fn align_items(mut self, align: Align) -> Self {
|
||||
pub fn align_items(mut self, align: Align) -> Self {
|
||||
self.0.align_items = into_align_items(align);
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn justify_content(mut self, justify: Justify) -> Self {
|
||||
pub fn justify_content(mut self, justify: Justify) -> Self {
|
||||
self.0.justify_content = into_justify_content(justify);
|
||||
self
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ where
|
|||
/// [`Node`]: ../struct.Node.html
|
||||
/// [`Widget`]: trait.Widget.html
|
||||
/// [`Layout`]: ../struct.Layout.html
|
||||
fn node(&self, renderer: &mut Renderer) -> Node;
|
||||
fn node(&self, renderer: &Renderer) -> Node;
|
||||
|
||||
/// Draws the [`Widget`] using the associated `Renderer`.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -10,14 +10,18 @@ use crate::input::{mouse, ButtonState};
|
|||
use crate::{Element, Event, Hasher, Layout, Node, Point, Widget};
|
||||
use std::hash::Hash;
|
||||
|
||||
pub use iced_core::button::*;
|
||||
pub use iced_core::button::State;
|
||||
|
||||
impl<'a, Message, Renderer> Widget<Message, Renderer> for Button<'a, Message>
|
||||
pub type Button<'a, Message, Renderer> =
|
||||
iced_core::Button<'a, Message, Element<'a, Message, Renderer>>;
|
||||
|
||||
impl<'a, Message, Renderer> Widget<Message, Renderer>
|
||||
for Button<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: self::Renderer,
|
||||
Message: Copy + std::fmt::Debug,
|
||||
{
|
||||
fn node(&self, renderer: &mut Renderer) -> Node {
|
||||
fn node(&self, renderer: &Renderer) -> Node {
|
||||
renderer.node(&self)
|
||||
}
|
||||
|
||||
|
|
@ -68,9 +72,9 @@ where
|
|||
}
|
||||
|
||||
fn hash_layout(&self, state: &mut Hasher) {
|
||||
self.label.hash(state);
|
||||
self.width.hash(state);
|
||||
self.align_self.hash(state);
|
||||
self.content.hash_layout(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -81,31 +85,33 @@ where
|
|||
///
|
||||
/// [`Button`]: struct.Button.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer {
|
||||
pub trait Renderer: crate::Renderer + Sized {
|
||||
/// Creates a [`Node`] for the provided [`Button`].
|
||||
///
|
||||
/// [`Node`]: ../../struct.Node.html
|
||||
/// [`Button`]: struct.Button.html
|
||||
fn node<Message>(&self, button: &Button<'_, Message>) -> Node;
|
||||
fn node<Message>(&self, button: &Button<'_, Message, Self>) -> Node;
|
||||
|
||||
/// Draws a [`Button`].
|
||||
///
|
||||
/// [`Button`]: struct.Button.html
|
||||
fn draw<Message>(
|
||||
&mut self,
|
||||
button: &Button<'_, Message>,
|
||||
button: &Button<'_, Message, Self>,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Self::Primitive;
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> From<Button<'a, Message>>
|
||||
impl<'a, Message, Renderer> From<Button<'a, Message, Renderer>>
|
||||
for Element<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: self::Renderer,
|
||||
Renderer: 'static + self::Renderer,
|
||||
Message: 'static + Copy + std::fmt::Debug,
|
||||
{
|
||||
fn from(button: Button<'a, Message>) -> Element<'a, Message, Renderer> {
|
||||
fn from(
|
||||
button: Button<'a, Message, Renderer>,
|
||||
) -> Element<'a, Message, Renderer> {
|
||||
Element::new(button)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ impl<Message, Renderer> Widget<Message, Renderer> for Checkbox<Message>
|
|||
where
|
||||
Renderer: self::Renderer,
|
||||
{
|
||||
fn node(&self, renderer: &mut Renderer) -> Node {
|
||||
fn node(&self, renderer: &Renderer) -> Node {
|
||||
renderer.node(&self)
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ pub trait Renderer: crate::Renderer {
|
|||
///
|
||||
/// [`Node`]: ../../struct.Node.html
|
||||
/// [`Checkbox`]: struct.Checkbox.html
|
||||
fn node<Message>(&mut self, checkbox: &Checkbox<Message>) -> Node;
|
||||
fn node<Message>(&self, checkbox: &Checkbox<Message>) -> Node;
|
||||
|
||||
/// Draws a [`Checkbox`].
|
||||
///
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ impl<'a, Message, Renderer> Widget<Message, Renderer>
|
|||
where
|
||||
Renderer: self::Renderer,
|
||||
{
|
||||
fn node(&self, renderer: &mut Renderer) -> Node {
|
||||
fn node(&self, renderer: &Renderer) -> Node {
|
||||
let mut children: Vec<Node> = self
|
||||
.children
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ where
|
|||
Renderer: self::Renderer<I>,
|
||||
I: Clone,
|
||||
{
|
||||
fn node(&self, renderer: &mut Renderer) -> Node {
|
||||
fn node(&self, renderer: &Renderer) -> Node {
|
||||
renderer.node(&self)
|
||||
}
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ pub trait Renderer<I>: crate::Renderer {
|
|||
///
|
||||
/// [`Node`]: ../../struct.Node.html
|
||||
/// [`Image`]: struct.Image.html
|
||||
fn node(&mut self, image: &Image<I>) -> Node;
|
||||
fn node(&self, image: &Image<I>) -> Node;
|
||||
|
||||
/// Draws an [`Image`].
|
||||
///
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ where
|
|||
Renderer: self::Renderer,
|
||||
Message: Copy + std::fmt::Debug,
|
||||
{
|
||||
fn node(&self, renderer: &mut Renderer) -> Node {
|
||||
fn node(&self, renderer: &Renderer) -> Node {
|
||||
renderer.node(&self)
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ pub trait Renderer: crate::Renderer {
|
|||
///
|
||||
/// [`Node`]: ../../struct.Node.html
|
||||
/// [`Radio`]: struct.Radio.html
|
||||
fn node<Message>(&mut self, radio: &Radio<Message>) -> Node;
|
||||
fn node<Message>(&self, radio: &Radio<Message>) -> Node;
|
||||
|
||||
/// Draws a [`Radio`] button.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ impl<'a, Message, Renderer> Widget<Message, Renderer>
|
|||
where
|
||||
Renderer: self::Renderer,
|
||||
{
|
||||
fn node(&self, renderer: &mut Renderer) -> Node {
|
||||
fn node(&self, renderer: &Renderer) -> Node {
|
||||
let mut children: Vec<Node> = self
|
||||
.children
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ impl<'a, Message, Renderer> Widget<Message, Renderer> for Slider<'a, Message>
|
|||
where
|
||||
Renderer: self::Renderer,
|
||||
{
|
||||
fn node(&self, renderer: &mut Renderer) -> Node {
|
||||
fn node(&self, renderer: &Renderer) -> Node {
|
||||
renderer.node(&self)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ impl<Message, Renderer> Widget<Message, Renderer> for Text
|
|||
where
|
||||
Renderer: self::Renderer,
|
||||
{
|
||||
fn node(&self, renderer: &mut Renderer) -> Node {
|
||||
fn node(&self, renderer: &Renderer) -> Node {
|
||||
renderer.node(&self)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
pub use iced_wgpu::{Primitive, Renderer};
|
||||
pub use iced_winit::{
|
||||
button, slider, text, winit, Align, Button, Checkbox, Color, Image,
|
||||
button, slider, text, winit, Align, Background, Checkbox, Color, Image,
|
||||
Justify, Length, Radio, Slider, Text,
|
||||
};
|
||||
|
||||
pub type Element<'a, Message> = iced_winit::Element<'a, Message, Renderer>;
|
||||
pub type Row<'a, Message> = iced_winit::Row<'a, Message, Renderer>;
|
||||
pub type Column<'a, Message> = iced_winit::Column<'a, Message, Renderer>;
|
||||
pub type Button<'a, Message> = iced_winit::Button<'a, Message, Renderer>;
|
||||
|
||||
pub trait UserInterface {
|
||||
type Message;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,14 @@ impl<'a, Message> Element<'a, Message> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn node<'b>(
|
||||
&self,
|
||||
bump: &'b bumpalo::Bump,
|
||||
bus: &Bus<Message>,
|
||||
) -> dodrio::Node<'b> {
|
||||
self.widget.node(bump, bus)
|
||||
}
|
||||
|
||||
pub fn explain(self, _color: Color) -> Element<'a, Message> {
|
||||
self
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@ use crate::{Bus, Element, Widget};
|
|||
|
||||
use dodrio::bumpalo;
|
||||
|
||||
pub use iced_core::button::*;
|
||||
pub use iced_core::button::State;
|
||||
|
||||
pub type Button<'a, Message> =
|
||||
iced_core::Button<'a, Message, Element<'a, Message>>;
|
||||
|
||||
impl<'a, Message> Widget<Message> for Button<'a, Message>
|
||||
where
|
||||
|
|
@ -15,9 +18,8 @@ where
|
|||
) -> dodrio::Node<'b> {
|
||||
use dodrio::builder::*;
|
||||
|
||||
let label = bumpalo::format!(in bump, "{}", self.label);
|
||||
|
||||
let mut node = button(bump).children(vec![text(label.into_bump_str())]);
|
||||
let mut node =
|
||||
button(bump).children(vec![self.content.node(bump, bus)]);
|
||||
|
||||
if let Some(on_press) = self.on_press {
|
||||
let event_bus = bus.clone();
|
||||
|
|
|
|||
|
|
@ -8,5 +8,5 @@ pub(crate) use quad::Quad;
|
|||
pub(crate) use transformation::Transformation;
|
||||
|
||||
pub use mouse_cursor::MouseCursor;
|
||||
pub use primitive::{Background, Primitive};
|
||||
pub use primitive::Primitive;
|
||||
pub use renderer::{Renderer, Target};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use iced_native::{Color, Rectangle};
|
||||
use iced_native::{text, Background, Color, Rectangle};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Primitive {
|
||||
|
|
@ -9,16 +9,14 @@ pub enum Primitive {
|
|||
Text {
|
||||
content: String,
|
||||
bounds: Rectangle,
|
||||
color: Color,
|
||||
size: f32,
|
||||
horizontal_alignment: text::HorizontalAlignment,
|
||||
vertical_alignment: text::VerticalAlignment,
|
||||
},
|
||||
Quad {
|
||||
bounds: Rectangle,
|
||||
background: Background,
|
||||
border_radius: u16,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Background {
|
||||
Color(Color),
|
||||
// TODO: Add gradient and image variants
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,6 +123,11 @@ impl Pipeline {
|
|||
format: wgpu::VertexFormat::Float4,
|
||||
offset: 4 * (2 + 2),
|
||||
},
|
||||
wgpu::VertexAttributeDescriptor {
|
||||
shader_location: 4,
|
||||
format: wgpu::VertexFormat::Uint,
|
||||
offset: 4 * (2 + 2 + 4),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
@ -262,6 +267,7 @@ pub struct Quad {
|
|||
pub position: [f32; 2],
|
||||
pub scale: [f32; 2],
|
||||
pub color: [f32; 4],
|
||||
pub border_radius: u32,
|
||||
}
|
||||
|
||||
impl Quad {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use crate::{quad, Background, Primitive, Quad, Transformation};
|
||||
use iced_native::{renderer::Debugger, Color, Layout, Point, Widget};
|
||||
use crate::{quad, Primitive, Quad, Transformation};
|
||||
use iced_native::{
|
||||
renderer::Debugger, Background, Color, Layout, Point, Widget,
|
||||
};
|
||||
|
||||
use raw_window_handle::HasRawWindowHandle;
|
||||
use wgpu::{
|
||||
|
|
@ -159,20 +161,74 @@ impl Renderer {
|
|||
content,
|
||||
bounds,
|
||||
size,
|
||||
} => self.glyph_brush.borrow_mut().queue(Section {
|
||||
text: &content,
|
||||
screen_position: (bounds.x, bounds.y),
|
||||
bounds: (bounds.width, bounds.height),
|
||||
scale: wgpu_glyph::Scale { x: *size, y: *size },
|
||||
..Default::default()
|
||||
}),
|
||||
Primitive::Quad { bounds, background } => {
|
||||
color,
|
||||
horizontal_alignment,
|
||||
vertical_alignment,
|
||||
} => {
|
||||
let x = match horizontal_alignment {
|
||||
iced_native::text::HorizontalAlignment::Left => bounds.x,
|
||||
iced_native::text::HorizontalAlignment::Center => {
|
||||
bounds.x + bounds.width / 2.0
|
||||
}
|
||||
iced_native::text::HorizontalAlignment::Right => {
|
||||
bounds.x + bounds.width
|
||||
}
|
||||
};
|
||||
|
||||
let y = match vertical_alignment {
|
||||
iced_native::text::VerticalAlignment::Top => bounds.y,
|
||||
iced_native::text::VerticalAlignment::Center => {
|
||||
bounds.y + bounds.height / 2.0
|
||||
}
|
||||
iced_native::text::VerticalAlignment::Bottom => {
|
||||
bounds.y + bounds.height
|
||||
}
|
||||
};
|
||||
|
||||
self.glyph_brush.borrow_mut().queue(Section {
|
||||
text: &content,
|
||||
screen_position: (x, y),
|
||||
bounds: (bounds.width, bounds.height),
|
||||
scale: wgpu_glyph::Scale { x: *size, y: *size },
|
||||
color: color.into_linear(),
|
||||
layout: wgpu_glyph::Layout::default()
|
||||
.h_align(match horizontal_alignment {
|
||||
iced_native::text::HorizontalAlignment::Left => {
|
||||
wgpu_glyph::HorizontalAlign::Left
|
||||
}
|
||||
iced_native::text::HorizontalAlignment::Center => {
|
||||
wgpu_glyph::HorizontalAlign::Center
|
||||
}
|
||||
iced_native::text::HorizontalAlignment::Right => {
|
||||
wgpu_glyph::HorizontalAlign::Right
|
||||
}
|
||||
})
|
||||
.v_align(match vertical_alignment {
|
||||
iced_native::text::VerticalAlignment::Top => {
|
||||
wgpu_glyph::VerticalAlign::Top
|
||||
}
|
||||
iced_native::text::VerticalAlignment::Center => {
|
||||
wgpu_glyph::VerticalAlign::Center
|
||||
}
|
||||
iced_native::text::VerticalAlignment::Bottom => {
|
||||
wgpu_glyph::VerticalAlign::Bottom
|
||||
}
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
Primitive::Quad {
|
||||
bounds,
|
||||
background,
|
||||
border_radius,
|
||||
} => {
|
||||
self.quads.push(Quad {
|
||||
position: [bounds.x, bounds.y],
|
||||
scale: [bounds.width, bounds.height],
|
||||
color: match background {
|
||||
Background::Color(color) => color.into_linear(),
|
||||
},
|
||||
border_radius: u32::from(*border_radius),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,26 @@
|
|||
use crate::{Background, Primitive, Renderer};
|
||||
use iced_native::{button, Button, Color, Layout, Length, Node, Point, Style};
|
||||
use crate::{Primitive, Renderer};
|
||||
use iced_native::{
|
||||
button, Align, Background, Button, Color, Layout, Length, Node, Point,
|
||||
Style,
|
||||
};
|
||||
|
||||
impl button::Renderer for Renderer {
|
||||
fn node<Message>(&self, button: &Button<Message>) -> Node {
|
||||
fn node<Message>(&self, button: &Button<Message, Self>) -> Node {
|
||||
let style = Style::default()
|
||||
.width(button.width)
|
||||
.min_height(Length::Units(30))
|
||||
.padding(button.padding)
|
||||
.min_width(Length::Units(100))
|
||||
.align_self(button.align_self);
|
||||
.align_self(button.align_self)
|
||||
.align_items(Align::Stretch);
|
||||
|
||||
Node::new(style)
|
||||
Node::with_children(style, vec![button.content.node(self)])
|
||||
}
|
||||
|
||||
fn draw<Message>(
|
||||
&mut self,
|
||||
button: &Button<Message>,
|
||||
button: &Button<Message, Self>,
|
||||
layout: Layout<'_>,
|
||||
_cursor_position: Point,
|
||||
cursor_position: Point,
|
||||
) -> Self::Primitive {
|
||||
let bounds = layout.bounds();
|
||||
|
||||
|
|
@ -24,18 +28,21 @@ impl button::Renderer for Renderer {
|
|||
primitives: vec![
|
||||
Primitive::Quad {
|
||||
bounds,
|
||||
background: Background::Color(Color {
|
||||
r: 0.8,
|
||||
b: 0.8,
|
||||
g: 0.8,
|
||||
a: 1.0,
|
||||
}),
|
||||
},
|
||||
Primitive::Text {
|
||||
content: button.label.clone(),
|
||||
size: 20.0,
|
||||
bounds: layout.bounds(),
|
||||
background: button.background.unwrap_or(Background::Color(
|
||||
Color {
|
||||
r: 0.8,
|
||||
b: 0.8,
|
||||
g: 0.8,
|
||||
a: 1.0,
|
||||
},
|
||||
)),
|
||||
border_radius: button.border_radius,
|
||||
},
|
||||
button.content.draw(
|
||||
self,
|
||||
layout.children().next().unwrap(),
|
||||
cursor_position,
|
||||
),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::{Primitive, Renderer};
|
|||
use iced_native::{checkbox, Checkbox, Layout, Node, Point, Style};
|
||||
|
||||
impl checkbox::Renderer for Renderer {
|
||||
fn node<Message>(&mut self, _checkbox: &Checkbox<Message>) -> Node {
|
||||
fn node<Message>(&self, _checkbox: &Checkbox<Message>) -> Node {
|
||||
Node::new(Style::default())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::{Primitive, Renderer};
|
|||
use iced_native::{image, Image, Layout, Node, Style};
|
||||
|
||||
impl image::Renderer<&str> for Renderer {
|
||||
fn node(&mut self, _image: &Image<&str>) -> Node {
|
||||
fn node(&self, _image: &Image<&str>) -> Node {
|
||||
Node::new(Style::default())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::{Primitive, Renderer};
|
|||
use iced_native::{radio, Layout, Node, Point, Radio, Style};
|
||||
|
||||
impl radio::Renderer for Renderer {
|
||||
fn node<Message>(&mut self, _checkbox: &Radio<Message>) -> Node {
|
||||
fn node<Message>(&self, _checkbox: &Radio<Message>) -> Node {
|
||||
Node::new(Style::default())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{Primitive, Renderer};
|
||||
use iced_native::{text, Layout, Node, Style, Text};
|
||||
use iced_native::{text, Color, Layout, Node, Style, Text};
|
||||
|
||||
use wgpu_glyph::{GlyphCruncher, Section};
|
||||
|
||||
|
|
@ -72,6 +72,9 @@ impl text::Renderer for Renderer {
|
|||
content: text.content.clone(),
|
||||
size: f32::from(text.size.unwrap_or(20)),
|
||||
bounds: layout.bounds(),
|
||||
color: text.color.unwrap_or(Color::BLACK),
|
||||
horizontal_alignment: text.horizontal_alignment,
|
||||
vertical_alignment: text.vertical_alignment,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
layout(location = 0) in vec4 v_Color;
|
||||
layout(location = 1) in vec2 v_Pos;
|
||||
layout(location = 2) in vec2 v_Scale;
|
||||
layout(location = 3) in flat uint v_BorderRadius;
|
||||
|
||||
layout(location = 0) out vec4 o_Color;
|
||||
|
||||
|
|
@ -26,8 +27,11 @@ float rounded(in vec2 frag_coord, in vec2 position, in vec2 size, float radius,
|
|||
}
|
||||
|
||||
void main() {
|
||||
o_Color = vec4(
|
||||
v_Color.xyz,
|
||||
v_Color.w * rounded(gl_FragCoord.xy, v_Pos, v_Scale, 5.0, 1.0)
|
||||
);
|
||||
float radius_alpha = 1.0;
|
||||
|
||||
if(v_BorderRadius > 0.0) {
|
||||
radius_alpha = rounded(gl_FragCoord.xy, v_Pos, v_Scale, v_BorderRadius, 1.0);
|
||||
}
|
||||
|
||||
o_Color = vec4(v_Color.xyz, v_Color.w * radius_alpha);
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -4,6 +4,7 @@ layout(location = 0) in vec2 v_Pos;
|
|||
layout(location = 1) in vec2 i_Pos;
|
||||
layout(location = 2) in vec2 i_Scale;
|
||||
layout(location = 3) in vec4 i_Color;
|
||||
layout(location = 4) in uint i_BorderRadius;
|
||||
|
||||
layout (set = 0, binding = 0) uniform Globals {
|
||||
mat4 u_Transform;
|
||||
|
|
@ -12,6 +13,7 @@ layout (set = 0, binding = 0) uniform Globals {
|
|||
layout(location = 0) out vec4 o_Color;
|
||||
layout(location = 1) out vec2 o_Pos;
|
||||
layout(location = 2) out vec2 o_Scale;
|
||||
layout(location = 3) out uint o_BorderRadius;
|
||||
|
||||
void main() {
|
||||
mat4 i_Transform = mat4(
|
||||
|
|
@ -24,6 +26,7 @@ void main() {
|
|||
o_Color = i_Color;
|
||||
o_Pos = i_Pos;
|
||||
o_Scale = i_Scale;
|
||||
o_BorderRadius = i_BorderRadius;
|
||||
|
||||
gl_Position = u_Transform * i_Transform * vec4(v_Pos, 0.0, 1.0);
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue