Draft basic styling for TextInput
This commit is contained in:
parent
d96ced8e2d
commit
5af4159848
@ -97,6 +97,8 @@ impl scrollable::Renderer for Null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
@ -124,6 +126,7 @@ 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 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the style the [`Container`].
|
/// Sets the style of the [`Container`].
|
||||||
///
|
///
|
||||||
/// [`Container`]: struct.Container.html
|
/// [`Container`]: struct.Container.html
|
||||||
pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self {
|
pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self {
|
||||||
|
@ -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;
|
|||||||
/// ```
|
/// ```
|
||||||
/// ![Text input drawn by `iced_wgpu`](https://github.com/hecrj/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/text_input.png?raw=true)
|
/// ![Text input drawn by `iced_wgpu`](https://github.com/hecrj/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/text_input.png?raw=true)
|
||||||
#[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:
|
||||||
@ -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 {
|
||||||
@ -359,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(
|
||||||
@ -369,6 +382,7 @@ where
|
|||||||
&self.placeholder,
|
&self.placeholder,
|
||||||
&self.value,
|
&self.value,
|
||||||
&self.state,
|
&self.state,
|
||||||
|
&self.style,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -376,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);
|
||||||
@ -393,6 +407,8 @@ 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 {
|
||||||
|
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
|
||||||
@ -441,17 +457,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)
|
||||||
}
|
}
|
||||||
|
@ -38,16 +38,6 @@ pub mod widget {
|
|||||||
pub use iced_winit::scrollable::State;
|
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 {
|
pub mod slider {
|
||||||
//! Display an interactive selector of a single value from a range of
|
//! Display an interactive selector of a single value from a range of
|
||||||
//! values.
|
//! values.
|
||||||
|
@ -12,6 +12,12 @@ pub struct Style {
|
|||||||
/// A set of rules that dictate the style of a container.
|
/// A set of rules that dictate the style of a container.
|
||||||
pub trait StyleSheet {
|
pub trait StyleSheet {
|
||||||
/// Produces the style of a container.
|
/// Produces the style of a container.
|
||||||
|
fn style(&self) -> Style;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Default;
|
||||||
|
|
||||||
|
impl StyleSheet for Default {
|
||||||
fn style(&self) -> Style {
|
fn style(&self) -> Style {
|
||||||
Style {
|
Style {
|
||||||
text_color: None,
|
text_color: None,
|
||||||
@ -21,10 +27,6 @@ pub trait StyleSheet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Default;
|
|
||||||
|
|
||||||
impl StyleSheet for Default {}
|
|
||||||
|
|
||||||
impl std::default::Default for Box<dyn StyleSheet> {
|
impl std::default::Default for Box<dyn StyleSheet> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Box::new(Default)
|
Box::new(Default)
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
pub mod button;
|
pub mod button;
|
||||||
pub mod container;
|
pub mod container;
|
||||||
|
pub mod text_input;
|
||||||
|
72
style/src/text_input.rs
Normal file
72
style/src/text_input.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
//! 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
|
||||||
|
/// Produces the style of an hovered text input.
|
||||||
|
fn hovered(&self) -> Style {
|
||||||
|
self.focused()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn placeholder_color(&self) -> Color;
|
||||||
|
|
||||||
|
fn value_color(&self) -> Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
@ -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,20 +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 style = if state.is_focused() {
|
||||||
|
style_sheet.focused()
|
||||||
|
} else if is_mouse_over {
|
||||||
|
style_sheet.hovered()
|
||||||
|
} else {
|
||||||
|
style_sheet.active()
|
||||||
|
};
|
||||||
|
|
||||||
let input = Primitive::Quad {
|
let input = Primitive::Quad {
|
||||||
bounds,
|
bounds,
|
||||||
background: Background::Color(Color::WHITE),
|
background: style.background,
|
||||||
border_radius: 5,
|
border_radius: style.border_radius,
|
||||||
border_width: 1,
|
border_width: style.border_width,
|
||||||
border_color: if is_mouse_over || state.is_focused() {
|
border_color: style.border_color,
|
||||||
[0.5, 0.5, 0.5]
|
|
||||||
} else {
|
|
||||||
[0.7, 0.7, 0.7]
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let text = value.to_string();
|
let text = value.to_string();
|
||||||
@ -86,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,
|
||||||
@ -117,7 +123,7 @@ 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_width: 0,
|
||||||
border_color: Color::TRANSPARENT,
|
border_color: Color::TRANSPARENT,
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
pub mod button;
|
pub mod button;
|
||||||
pub mod container;
|
pub mod container;
|
||||||
|
pub mod text_input;
|
||||||
|
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>;
|
Loading…
Reference in New Issue
Block a user