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 {
|
||||
type Style = ();
|
||||
|
||||
fn default_size(&self) -> u16 {
|
||||
20
|
||||
}
|
||||
@ -124,6 +126,7 @@ impl text_input::Renderer for Null {
|
||||
_placeholder: &str,
|
||||
_value: &text_input::Value,
|
||||
_state: &text_input::State,
|
||||
_style: &Self::Style,
|
||||
) -> Self::Output {
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the style the [`Container`].
|
||||
/// Sets the style of the [`Container`].
|
||||
///
|
||||
/// [`Container`]: struct.Container.html
|
||||
pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self {
|
||||
|
@ -15,8 +15,9 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use iced_native::{text_input, TextInput};
|
||||
/// # use iced_native::{text_input, renderer::Null};
|
||||
/// #
|
||||
/// # pub type TextInput<'a, Message> = iced_native::TextInput<'a, Message, Null>;
|
||||
/// #[derive(Debug, Clone)]
|
||||
/// enum Message {
|
||||
/// TextInputChanged(String),
|
||||
@ -35,7 +36,7 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||
/// ```
|
||||
/// ![Text input drawn by `iced_wgpu`](https://github.com/hecrj/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/text_input.png?raw=true)
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct TextInput<'a, Message> {
|
||||
pub struct TextInput<'a, Message, Renderer: self::Renderer> {
|
||||
state: &'a mut State,
|
||||
placeholder: String,
|
||||
value: Value,
|
||||
@ -46,9 +47,10 @@ pub struct TextInput<'a, Message> {
|
||||
size: Option<u16>,
|
||||
on_change: Box<dyn Fn(String) -> Message>,
|
||||
on_submit: Option<Message>,
|
||||
style: Renderer::Style,
|
||||
}
|
||||
|
||||
impl<'a, Message> TextInput<'a, Message> {
|
||||
impl<'a, Message, Renderer: self::Renderer> TextInput<'a, Message, Renderer> {
|
||||
/// Creates a new [`TextInput`].
|
||||
///
|
||||
/// It expects:
|
||||
@ -79,6 +81,7 @@ impl<'a, Message> TextInput<'a, Message> {
|
||||
size: None,
|
||||
on_change: Box::new(on_change),
|
||||
on_submit: None,
|
||||
style: Renderer::Style::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,11 +133,20 @@ impl<'a, Message> TextInput<'a, Message> {
|
||||
self.on_submit = Some(message);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the style of the [`TextInput`].
|
||||
///
|
||||
/// [`TextInput`]: struct.TextInput.html
|
||||
pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self {
|
||||
self.style = style.into();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> Widget<Message, Renderer> for TextInput<'a, Message>
|
||||
impl<'a, Message, Renderer> Widget<Message, Renderer>
|
||||
for TextInput<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: self::Renderer,
|
||||
Renderer: 'static + self::Renderer,
|
||||
Message: Clone + std::fmt::Debug,
|
||||
{
|
||||
fn width(&self) -> Length {
|
||||
@ -359,6 +371,7 @@ where
|
||||
&self.placeholder,
|
||||
&self.value.secure(),
|
||||
&self.state,
|
||||
&self.style,
|
||||
)
|
||||
} else {
|
||||
renderer.draw(
|
||||
@ -369,6 +382,7 @@ where
|
||||
&self.placeholder,
|
||||
&self.value,
|
||||
&self.state,
|
||||
&self.style,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -376,7 +390,7 @@ where
|
||||
fn hash_layout(&self, state: &mut Hasher) {
|
||||
use std::{any::TypeId, hash::Hash};
|
||||
|
||||
TypeId::of::<TextInput<'static, ()>>().hash(state);
|
||||
TypeId::of::<TextInput<'static, (), Renderer>>().hash(state);
|
||||
|
||||
self.width.hash(state);
|
||||
self.max_width.hash(state);
|
||||
@ -393,6 +407,8 @@ where
|
||||
/// [`TextInput`]: struct.TextInput.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer + Sized {
|
||||
type Style: Default;
|
||||
|
||||
/// Returns the default size of the text of the [`TextInput`].
|
||||
///
|
||||
/// [`TextInput`]: struct.TextInput.html
|
||||
@ -441,17 +457,18 @@ pub trait Renderer: crate::Renderer + Sized {
|
||||
placeholder: &str,
|
||||
value: &Value,
|
||||
state: &State,
|
||||
style: &Self::Style,
|
||||
) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> From<TextInput<'a, Message>>
|
||||
impl<'a, Message, Renderer> From<TextInput<'a, Message, Renderer>>
|
||||
for Element<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: 'static + self::Renderer,
|
||||
Message: 'static + Clone + std::fmt::Debug,
|
||||
{
|
||||
fn from(
|
||||
text_input: TextInput<'a, Message>,
|
||||
text_input: TextInput<'a, Message, Renderer>,
|
||||
) -> Element<'a, Message, Renderer> {
|
||||
Element::new(text_input)
|
||||
}
|
||||
|
@ -38,16 +38,6 @@ pub mod widget {
|
||||
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.
|
||||
|
@ -12,6 +12,12 @@ pub struct Style {
|
||||
/// 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,
|
||||
@ -21,10 +27,6 @@ pub trait StyleSheet {
|
||||
}
|
||||
}
|
||||
|
||||
struct Default;
|
||||
|
||||
impl StyleSheet for Default {}
|
||||
|
||||
impl std::default::Default for Box<dyn StyleSheet> {
|
||||
fn default() -> Self {
|
||||
Box::new(Default)
|
||||
|
@ -1,2 +1,3 @@
|
||||
pub mod button;
|
||||
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::{
|
||||
text_input, Background, Color, Font, HorizontalAlignment, MouseCursor,
|
||||
@ -7,6 +7,8 @@ use iced_native::{
|
||||
use std::f32;
|
||||
|
||||
impl text_input::Renderer for Renderer {
|
||||
type Style = Box<dyn StyleSheet>;
|
||||
|
||||
fn default_size(&self) -> u16 {
|
||||
// TODO: Make this configurable
|
||||
20
|
||||
@ -61,20 +63,24 @@ impl text_input::Renderer for Renderer {
|
||||
placeholder: &str,
|
||||
value: &text_input::Value,
|
||||
state: &text_input::State,
|
||||
style_sheet: &Self::Style,
|
||||
) -> Self::Output {
|
||||
let is_mouse_over = bounds.contains(cursor_position);
|
||||
|
||||
let style = if state.is_focused() {
|
||||
style_sheet.focused()
|
||||
} else if is_mouse_over {
|
||||
style_sheet.hovered()
|
||||
} else {
|
||||
style_sheet.active()
|
||||
};
|
||||
|
||||
let input = Primitive::Quad {
|
||||
bounds,
|
||||
background: Background::Color(Color::WHITE),
|
||||
border_radius: 5,
|
||||
border_width: 1,
|
||||
border_color: if is_mouse_over || state.is_focused() {
|
||||
[0.5, 0.5, 0.5]
|
||||
} else {
|
||||
[0.7, 0.7, 0.7]
|
||||
}
|
||||
.into(),
|
||||
background: style.background,
|
||||
border_radius: style.border_radius,
|
||||
border_width: style.border_width,
|
||||
border_color: style.border_color,
|
||||
};
|
||||
|
||||
let text = value.to_string();
|
||||
@ -86,9 +92,9 @@ impl text_input::Renderer for Renderer {
|
||||
text.clone()
|
||||
},
|
||||
color: if text.is_empty() {
|
||||
[0.7, 0.7, 0.7]
|
||||
style_sheet.placeholder_color()
|
||||
} else {
|
||||
[0.3, 0.3, 0.3]
|
||||
style_sheet.value_color()
|
||||
}
|
||||
.into(),
|
||||
font: Font::Default,
|
||||
@ -117,7 +123,7 @@ impl text_input::Renderer for Renderer {
|
||||
width: 1.0,
|
||||
height: text_bounds.height,
|
||||
},
|
||||
background: Background::Color(Color::BLACK),
|
||||
background: Background::Color(style_sheet.value_color()),
|
||||
border_radius: 0,
|
||||
border_width: 0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
|
@ -1,2 +1,3 @@
|
||||
pub mod button;
|
||||
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