summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón <hector0193@gmail.com>2023-04-12 04:51:19 +0200
committerLibravatar GitHub <noreply@github.com>2023-04-12 04:51:19 +0200
commitce8e92ca7a4ed0f4fe284c9042f863f7c83ba03a (patch)
treef9be0c6e0d8f9e2af6170f4370677918c4b43a2a
parentca828f03f5aab9efacc9d63d4149363333035a0c (diff)
parent7e7e66586d990788ffd77b17e98357e74252f497 (diff)
downloadiced-ce8e92ca7a4ed0f4fe284c9042f863f7c83ba03a.tar.gz
iced-ce8e92ca7a4ed0f4fe284c9042f863f7c83ba03a.tar.bz2
iced-ce8e92ca7a4ed0f4fe284c9042f863f7c83ba03a.zip
Merge pull request #1744 from JungleTryne/disable-text-input
Add functionality to make `TextInput` disabled
-rw-r--r--core/src/mouse/interaction.rs1
-rw-r--r--examples/component/src/main.rs2
-rw-r--r--examples/integration_wgpu/src/controls.rs9
-rw-r--r--examples/lazy/src/main.rs9
-rw-r--r--examples/modal/src/main.rs14
-rw-r--r--examples/qr_code/src/main.rs12
-rw-r--r--examples/styling/src/main.rs11
-rw-r--r--examples/toast/src/main.rs6
-rw-r--r--examples/todos/src/main.rs29
-rw-r--r--examples/tour/src/main.rs11
-rw-r--r--examples/websocket/src/main.rs9
-rw-r--r--native/src/widget/helpers.rs3
-rw-r--r--native/src/widget/text_input.rs91
-rw-r--r--style/src/text_input.rs6
-rw-r--r--style/src/theme.rs24
-rw-r--r--winit/src/conversion.rs1
16 files changed, 143 insertions, 95 deletions
diff --git a/core/src/mouse/interaction.rs b/core/src/mouse/interaction.rs
index 57da93fe..072033fd 100644
--- a/core/src/mouse/interaction.rs
+++ b/core/src/mouse/interaction.rs
@@ -12,4 +12,5 @@ pub enum Interaction {
Grabbing,
ResizingHorizontally,
ResizingVertically,
+ NotAllowed,
}
diff --git a/examples/component/src/main.rs b/examples/component/src/main.rs
index bbf549e7..21c2747c 100644
--- a/examples/component/src/main.rs
+++ b/examples/component/src/main.rs
@@ -141,8 +141,8 @@ mod numeric_input {
.map(u32::to_string)
.as_deref()
.unwrap_or(""),
- Event::InputChanged,
)
+ .on_input(Event::InputChanged)
.padding(10),
button("+", Event::IncrementPressed),
]
diff --git a/examples/integration_wgpu/src/controls.rs b/examples/integration_wgpu/src/controls.rs
index 533cb6e2..42623b15 100644
--- a/examples/integration_wgpu/src/controls.rs
+++ b/examples/integration_wgpu/src/controls.rs
@@ -100,11 +100,10 @@ impl Program for Controls {
.size(14)
.style(Color::WHITE),
)
- .push(text_input(
- "Placeholder",
- text,
- Message::TextChanged,
- )),
+ .push(
+ text_input("Placeholder", text)
+ .on_input(Message::TextChanged),
+ ),
),
)
.into()
diff --git a/examples/lazy/src/main.rs b/examples/lazy/src/main.rs
index 6512106f..55b13bcf 100644
--- a/examples/lazy/src/main.rs
+++ b/examples/lazy/src/main.rs
@@ -214,12 +214,9 @@ impl Sandbox for App {
column![
scrollable(options).height(Length::Fill),
row![
- text_input(
- "Add a new option",
- &self.input,
- Message::InputChanged,
- )
- .on_submit(Message::AddItem(self.input.clone())),
+ text_input("Add a new option", &self.input)
+ .on_input(Message::InputChanged)
+ .on_submit(Message::AddItem(self.input.clone())),
button(text(format!("Toggle Order ({})", self.order)))
.on_press(Message::ToggleOrder)
]
diff --git a/examples/modal/src/main.rs b/examples/modal/src/main.rs
index 54555684..49038475 100644
--- a/examples/modal/src/main.rs
+++ b/examples/modal/src/main.rs
@@ -133,18 +133,16 @@ impl Application for App {
column![
column![
text("Email").size(12),
- text_input(
- "abc@123.com",
- &self.email,
- Message::Email
- )
- .on_submit(Message::Submit)
- .padding(5),
+ text_input("abc@123.com", &self.email,)
+ .on_input(Message::Email)
+ .on_submit(Message::Submit)
+ .padding(5),
]
.spacing(5),
column![
text("Password").size(12),
- text_input("", &self.password, Message::Password)
+ text_input("", &self.password)
+ .on_input(Message::Password)
.on_submit(Message::Submit)
.password()
.padding(5),
diff --git a/examples/qr_code/src/main.rs b/examples/qr_code/src/main.rs
index d8041745..867ebfa4 100644
--- a/examples/qr_code/src/main.rs
+++ b/examples/qr_code/src/main.rs
@@ -49,13 +49,11 @@ impl Sandbox for QRGenerator {
.size(70)
.style(Color::from([0.5, 0.5, 0.5]));
- let input = text_input(
- "Type the data of your QR code here...",
- &self.data,
- Message::DataChanged,
- )
- .size(30)
- .padding(15);
+ let input =
+ text_input("Type the data of your QR code here...", &self.data)
+ .on_input(Message::DataChanged)
+ .size(30)
+ .padding(15);
let mut content = column![title, input]
.width(700)
diff --git a/examples/styling/src/main.rs b/examples/styling/src/main.rs
index 448c9792..e2015bac 100644
--- a/examples/styling/src/main.rs
+++ b/examples/styling/src/main.rs
@@ -90,13 +90,10 @@ impl Sandbox for Styling {
},
);
- let text_input = text_input(
- "Type something...",
- &self.input_value,
- Message::InputChanged,
- )
- .padding(10)
- .size(20);
+ let text_input = text_input("Type something...", &self.input_value)
+ .on_input(Message::InputChanged)
+ .padding(10)
+ .size(20);
let button = button("Submit")
.padding(10)
diff --git a/examples/toast/src/main.rs b/examples/toast/src/main.rs
index e74b3ee6..b4b4e007 100644
--- a/examples/toast/src/main.rs
+++ b/examples/toast/src/main.rs
@@ -119,13 +119,15 @@ impl Application for App {
column![
subtitle(
"Title",
- text_input("", &self.editing.title, Message::Title)
+ text_input("", &self.editing.title)
+ .on_input(Message::Title)
.on_submit(Message::Add)
.into()
),
subtitle(
"Message",
- text_input("", &self.editing.body, Message::Body)
+ text_input("", &self.editing.body)
+ .on_input(Message::Body)
.on_submit(Message::Add)
.into()
),
diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs
index 6361667e..99cdb8f9 100644
--- a/examples/todos/src/main.rs
+++ b/examples/todos/src/main.rs
@@ -204,15 +204,12 @@ impl Application for Todos {
.style(Color::from([0.5, 0.5, 0.5]))
.horizontal_alignment(alignment::Horizontal::Center);
- let input = text_input(
- "What needs to be done?",
- input_value,
- Message::InputChanged,
- )
- .id(INPUT_ID.clone())
- .padding(15)
- .size(30)
- .on_submit(Message::CreateTask);
+ let input = text_input("What needs to be done?", input_value)
+ .id(INPUT_ID.clone())
+ .on_input(Message::InputChanged)
+ .on_submit(Message::CreateTask)
+ .padding(15)
+ .size(30);
let controls = view_controls(tasks, *filter);
let filtered_tasks =
@@ -375,14 +372,12 @@ impl Task {
.into()
}
TaskState::Editing => {
- let text_input = text_input(
- "Describe your task...",
- &self.description,
- TaskMessage::DescriptionEdited,
- )
- .id(Self::text_input_id(i))
- .on_submit(TaskMessage::FinishEdition)
- .padding(10);
+ let text_input =
+ text_input("Describe your task...", &self.description)
+ .id(Self::text_input_id(i))
+ .on_input(TaskMessage::DescriptionEdited)
+ .on_submit(TaskMessage::FinishEdition)
+ .padding(10);
row![
text_input,
diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs
index 90868877..16ee19c0 100644
--- a/examples/tour/src/main.rs
+++ b/examples/tour/src/main.rs
@@ -570,13 +570,10 @@ impl<'a> Step {
bytes: include_bytes!("../fonts/icons.ttf"),
};
- let mut text_input = text_input(
- "Type something to continue...",
- value,
- StepMessage::InputChanged,
- )
- .padding(10)
- .size(30);
+ let mut text_input = text_input("Type something to continue...", value)
+ .on_input(StepMessage::InputChanged)
+ .padding(10)
+ .size(30);
if is_showing_icon {
text_input = text_input.icon(text_input::Icon {
diff --git a/examples/websocket/src/main.rs b/examples/websocket/src/main.rs
index e617b8ce..920189f5 100644
--- a/examples/websocket/src/main.rs
+++ b/examples/websocket/src/main.rs
@@ -125,12 +125,9 @@ impl Application for WebSocket {
};
let new_message_input = {
- let mut input = text_input(
- "Type a message...",
- &self.new_message,
- Message::NewMessageChanged,
- )
- .padding(10);
+ let mut input = text_input("Type a message...", &self.new_message)
+ .on_input(Message::NewMessageChanged)
+ .padding(10);
let mut button = button(
text("Send")
diff --git a/native/src/widget/helpers.rs b/native/src/widget/helpers.rs
index d13eca75..0363fc99 100644
--- a/native/src/widget/helpers.rs
+++ b/native/src/widget/helpers.rs
@@ -171,14 +171,13 @@ where
pub fn text_input<'a, Message, Renderer>(
placeholder: &str,
value: &str,
- on_change: impl Fn(String) -> Message + 'a,
) -> widget::TextInput<'a, Message, Renderer>
where
Message: Clone,
Renderer: crate::text::Renderer,
Renderer::Theme: widget::text_input::StyleSheet,
{
- widget::TextInput::new(placeholder, value, on_change)
+ widget::TextInput::new(placeholder, value)
}
/// Creates a new [`Slider`].
diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs
index fd61a849..8627aa98 100644
--- a/native/src/widget/text_input.rs
+++ b/native/src/widget/text_input.rs
@@ -46,8 +46,8 @@ pub use iced_style::text_input::{Appearance, StyleSheet};
/// let input = TextInput::new(
/// "This is the placeholder...",
/// value,
-/// Message::TextInputChanged,
/// )
+/// .on_input(Message::TextInputChanged)
/// .padding(10);
/// ```
/// ![Text input drawn by `iced_wgpu`](https://github.com/iced-rs/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/text_input.png?raw=true)
@@ -65,7 +65,7 @@ where
width: Length,
padding: Padding,
size: Option<f32>,
- on_change: Box<dyn Fn(String) -> Message + 'a>,
+ on_input: Option<Box<dyn Fn(String) -> Message + 'a>>,
on_paste: Option<Box<dyn Fn(String) -> Message + 'a>>,
on_submit: Option<Message>,
icon: Option<Icon<Renderer::Font>>,
@@ -82,12 +82,8 @@ where
///
/// It expects:
/// - a placeholder,
- /// - the current value, and
- /// - a function that produces a message when the [`TextInput`] changes.
- pub fn new<F>(placeholder: &str, value: &str, on_change: F) -> Self
- where
- F: 'a + Fn(String) -> Message,
- {
+ /// - the current value
+ pub fn new(placeholder: &str, value: &str) -> Self {
TextInput {
id: None,
placeholder: String::from(placeholder),
@@ -97,7 +93,7 @@ where
width: Length::Fill,
padding: Padding::new(5.0),
size: None,
- on_change: Box::new(on_change),
+ on_input: None,
on_paste: None,
on_submit: None,
icon: None,
@@ -117,6 +113,25 @@ where
self
}
+ /// Sets the message that should be produced when some text is typed into
+ /// the [`TextInput`].
+ ///
+ /// If this method is not called, the [`TextInput`] will be disabled.
+ pub fn on_input<F>(mut self, callback: F) -> Self
+ where
+ F: 'a + Fn(String) -> Message,
+ {
+ self.on_input = Some(Box::new(callback));
+ self
+ }
+
+ /// Sets the message that should be produced when the [`TextInput`] is
+ /// focused and the enter key is pressed.
+ pub fn on_submit(mut self, message: Message) -> Self {
+ self.on_submit = Some(message);
+ self
+ }
+
/// Sets the message that should be produced when some text is pasted into
/// the [`TextInput`].
pub fn on_paste(
@@ -159,13 +174,6 @@ where
self
}
- /// Sets the message that should be produced when the [`TextInput`] is
- /// focused and the enter key is pressed.
- pub fn on_submit(mut self, message: Message) -> Self {
- self.on_submit = Some(message);
- self
- }
-
/// Sets the style of the [`TextInput`].
pub fn style(
mut self,
@@ -198,6 +206,7 @@ where
&self.placeholder,
self.size,
&self.font,
+ self.on_input.is_none(),
self.is_secure,
self.icon.as_ref(),
&self.style,
@@ -220,6 +229,18 @@ where
tree::State::new(State::new())
}
+ fn diff(&self, tree: &mut Tree) {
+ let state = tree.state.downcast_mut::<State>();
+
+ // Unfocus text input if it becomes disabled
+ if self.on_input.is_none() {
+ state.last_click = None;
+ state.is_focused = None;
+ state.is_pasting = None;
+ state.is_dragging = false;
+ }
+ }
+
fn width(&self) -> Length {
self.width
}
@@ -277,7 +298,7 @@ where
self.size,
&self.font,
self.is_secure,
- self.on_change.as_ref(),
+ self.on_input.as_deref(),
self.on_paste.as_deref(),
&self.on_submit,
|| tree.state.downcast_mut::<State>(),
@@ -304,6 +325,7 @@ where
&self.placeholder,
self.size,
&self.font,
+ self.on_input.is_none(),
self.is_secure,
self.icon.as_ref(),
&self.style,
@@ -318,7 +340,7 @@ where
_viewport: &Rectangle,
_renderer: &Renderer,
) -> mouse::Interaction {
- mouse_interaction(layout, cursor_position)
+ mouse_interaction(layout, cursor_position, self.on_input.is_none())
}
}
@@ -492,7 +514,7 @@ pub fn update<'a, Message, Renderer>(
size: Option<f32>,
font: &Renderer::Font,
is_secure: bool,
- on_change: &dyn Fn(String) -> Message,
+ on_input: Option<&dyn Fn(String) -> Message>,
on_paste: Option<&dyn Fn(String) -> Message>,
on_submit: &Option<Message>,
state: impl FnOnce() -> &'a mut State,
@@ -505,7 +527,8 @@ where
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))
| Event::Touch(touch::Event::FingerPressed { .. }) => {
let state = state();
- let is_clicked = layout.bounds().contains(cursor_position);
+ let is_clicked =
+ layout.bounds().contains(cursor_position) && on_input.is_some();
state.is_focused = if is_clicked {
state.is_focused.or_else(|| {
@@ -635,6 +658,8 @@ where
let state = state();
if let Some(focus) = &mut state.is_focused {
+ let Some(on_input) = on_input else { return event::Status::Ignored };
+
if state.is_pasting.is_none()
&& !state.keyboard_modifiers.command()
&& !c.is_control()
@@ -643,7 +668,7 @@ where
editor.insert(c);
- let message = (on_change)(editor.contents());
+ let message = (on_input)(editor.contents());
shell.publish(message);
focus.updated_at = Instant::now();
@@ -656,6 +681,8 @@ where
let state = state();
if let Some(focus) = &mut state.is_focused {
+ let Some(on_input) = on_input else { return event::Status::Ignored };
+
let modifiers = state.keyboard_modifiers;
focus.updated_at = Instant::now();
@@ -681,7 +708,7 @@ where
let mut editor = Editor::new(value, &mut state.cursor);
editor.backspace();
- let message = (on_change)(editor.contents());
+ let message = (on_input)(editor.contents());
shell.publish(message);
}
keyboard::KeyCode::Delete => {
@@ -701,7 +728,7 @@ where
let mut editor = Editor::new(value, &mut state.cursor);
editor.delete();
- let message = (on_change)(editor.contents());
+ let message = (on_input)(editor.contents());
shell.publish(message);
}
keyboard::KeyCode::Left => {
@@ -776,7 +803,7 @@ where
let mut editor = Editor::new(value, &mut state.cursor);
editor.delete();
- let message = (on_change)(editor.contents());
+ let message = (on_input)(editor.contents());
shell.publish(message);
}
keyboard::KeyCode::V => {
@@ -803,7 +830,7 @@ where
let message = if let Some(paste) = &on_paste {
(paste)(editor.contents())
} else {
- (on_change)(editor.contents())
+ (on_input)(editor.contents())
};
shell.publish(message);
@@ -897,6 +924,7 @@ pub fn draw<Renderer>(
placeholder: &str,
size: Option<f32>,
font: &Renderer::Font,
+ is_disabled: bool,
is_secure: bool,
icon: Option<&Icon<Renderer::Font>>,
style: &<Renderer::Theme as StyleSheet>::Style,
@@ -914,7 +942,9 @@ pub fn draw<Renderer>(
let is_mouse_over = bounds.contains(cursor_position);
- let appearance = if state.is_focused() {
+ let appearance = if is_disabled {
+ theme.disabled(style)
+ } else if state.is_focused() {
theme.focused(style)
} else if is_mouse_over {
theme.hovered(style)
@@ -1057,6 +1087,8 @@ pub fn draw<Renderer>(
content: if text.is_empty() { placeholder } else { &text },
color: if text.is_empty() {
theme.placeholder_color(style)
+ } else if is_disabled {
+ theme.disabled_color(style)
} else {
theme.value_color(style)
},
@@ -1085,9 +1117,14 @@ pub fn draw<Renderer>(
pub fn mouse_interaction(
layout: Layout<'_>,
cursor_position: Point,
+ is_disabled: bool,
) -> mouse::Interaction {
if layout.bounds().contains(cursor_position) {
- mouse::Interaction::Text
+ if is_disabled {
+ mouse::Interaction::NotAllowed
+ } else {
+ mouse::Interaction::Text
+ }
} else {
mouse::Interaction::default()
}
diff --git a/style/src/text_input.rs b/style/src/text_input.rs
index 73b05852..2616ad5a 100644
--- a/style/src/text_input.rs
+++ b/style/src/text_input.rs
@@ -33,6 +33,9 @@ pub trait StyleSheet {
/// Produces the [`Color`] of the value of a text input.
fn value_color(&self, style: &Self::Style) -> Color;
+ /// Produces the [`Color`] of the value of a disabled text input.
+ fn disabled_color(&self, style: &Self::Style) -> Color;
+
/// Produces the [`Color`] of the selection of a text input.
fn selection_color(&self, style: &Self::Style) -> Color;
@@ -40,4 +43,7 @@ pub trait StyleSheet {
fn hovered(&self, style: &Self::Style) -> Appearance {
self.focused(style)
}
+
+ /// Produces the style of a disabled text input.
+ fn disabled(&self, style: &Self::Style) -> Appearance;
}
diff --git a/style/src/theme.rs b/style/src/theme.rs
index 0d974a19..6bd82a96 100644
--- a/style/src/theme.rs
+++ b/style/src/theme.rs
@@ -1093,4 +1093,28 @@ impl text_input::StyleSheet for Theme {
palette.primary.weak.color
}
+
+ fn disabled(&self, style: &Self::Style) -> text_input::Appearance {
+ if let TextInput::Custom(custom) = style {
+ return custom.disabled(self);
+ }
+
+ let palette = self.extended_palette();
+
+ text_input::Appearance {
+ background: palette.background.weak.color.into(),
+ border_radius: 2.0,
+ border_width: 1.0,
+ border_color: palette.background.strong.color,
+ icon_color: palette.background.strong.color,
+ }
+ }
+
+ fn disabled_color(&self, style: &Self::Style) -> Color {
+ if let TextInput::Custom(custom) = style {
+ return custom.disabled_color(self);
+ }
+
+ self.placeholder_color(style)
+ }
}
diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index 1b2ead36..d2dc9c06 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -236,6 +236,7 @@ pub fn mouse_interaction(
winit::window::CursorIcon::EwResize
}
Interaction::ResizingVertically => winit::window::CursorIcon::NsResize,
+ Interaction::NotAllowed => winit::window::CursorIcon::NotAllowed,
}
}