Skip to content

Commit

Permalink
Creating typed_input (a text input but sending message only when it i…
Browse files Browse the repository at this point in the history
…s valid for the given type) Adding suport for dots in number input
  • Loading branch information
Ultraxime committed Jul 19, 2024
2 parents 38df62a + 0ab9259 commit e8b325c
Show file tree
Hide file tree
Showing 8 changed files with 454 additions and 45 deletions.
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ tab_bar = []
tabs = ["tab_bar"]
time_picker = ["chrono", "icons", "iced/canvas"]
wrap = []
number_input = ["num-format", "num-traits"]
number_input = ["num-format", "num-traits", "typed_input"]
typed_input = []
selection_list = []
menu = []
quad = []
Expand Down Expand Up @@ -82,6 +83,7 @@ members = [
"examples/badge",
"examples/card",
"examples/number_input",
"examples/typed_input",
"examples/date_picker",
"examples/color_picker",
"examples/grid",
Expand Down
3 changes: 2 additions & 1 deletion examples/number_input/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ fn main() -> iced::Result {
impl NumberInputDemo {
fn update(&mut self, message: self::Message) {
let Message::NumInpChanged(val) = message;
println!("Value changed to {:?}", val);
self.value = val;
}

fn view(&self) -> Element<Message> {
let lb_minute = Text::new("Number Input:");
let txt_minute = number_input(self.value, 0.0..250.0, Message::NumInpChanged)
let txt_minute = number_input(self.value, -10.0..250.0, Message::NumInpChanged)
.style(number_input::number_input::primary)
.step(0.5);

Expand Down
15 changes: 15 additions & 0 deletions examples/typed_input/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "typed_input"
version = "0.1.0"
authors = ["Ultraxime <[email protected]>"]
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
iced_aw = { workspace = true, features = [
"typed_input",
"icons",
] }

iced.workspace=true
55 changes: 55 additions & 0 deletions examples/typed_input/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use iced::{
widget::{Container, Row, Text},
Alignment, Element, Length,
};
use iced_aw::widgets::typed_input;

#[derive(Default, Debug)]
pub struct TypedInputDemo {
value: f32,
}

#[derive(Debug, Clone)]
pub enum Message {
TypedInpChanged(f32),
}

fn main() -> iced::Result {
iced::application(
"Typed Input example",
TypedInputDemo::update,
TypedInputDemo::view,
)
.window_size(iced::Size {
width: 250.0,
height: 200.0,
})
.font(iced_aw::BOOTSTRAP_FONT_BYTES)
.run()
}

impl TypedInputDemo {
fn update(&mut self, message: self::Message) {
let Message::TypedInpChanged(val) = message;
println!("Value changed to {:?}", val);
self.value = val;
}

fn view(&self) -> Element<Message> {
let lb_minute = Text::new("Typed Input:");
let txt_minute = typed_input::TypedInput::new(self.value, Message::TypedInpChanged);

Container::new(
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.push(lb_minute)
.push(txt_minute),
)
.width(Length::Fill)
.height(Length::Fill)
.center_x(Length::Fill)
.center_y(Length::Fill)
.into()
}
}
3 changes: 3 additions & 0 deletions src/widgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ pub mod number_input;
pub type NumberInput<'a, T, Message, Theme, Renderer> =
number_input::NumberInput<'a, T, Message, Theme, Renderer>;

#[cfg(feature = "typed_input")]
pub mod typed_input;

#[cfg(feature = "card")]
pub mod card;
#[cfg(feature = "card")]
Expand Down
98 changes: 55 additions & 43 deletions src/widgets/number_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use iced::{
widget::{
text::LineHeight,
text_input::{self, cursor, Value},
Column, Container, Row, Text, TextInput,
Column, Container, Row, Text,
},
Alignment, Background, Border, Color, Element, Event, Length, Padding, Pixels, Point,
Rectangle, Shadow, Size,
Expand All @@ -37,6 +37,7 @@ pub use crate::{
StyleFn,

Check failure on line 37 in src/widgets/number_input.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced_aw/iced_aw/src/widgets/number_input.rs
},
};
use crate::widgets::typed_input::TypedInput;

/// The default padding
const DEFAULT_PADDING: f32 = 5.0;
Expand Down Expand Up @@ -81,7 +82,7 @@ where
/// The text size of the [`NumberInput`].
size: Option<f32>,
/// The underlying element of the [`NumberInput`].
content: TextInput<'a, Message, Theme, Renderer>,
content: TypedInput<'a, T, Message, Theme, Renderer>,
/// The ``on_change`` event of the [`NumberInput`].
on_change: Box<dyn Fn(T) -> Message>,
/// The style of the [`NumberInput`].
Expand Down Expand Up @@ -116,9 +117,6 @@ where
T: 'static,
{
let padding = DEFAULT_PADDING;
let convert_to_num = move |s: String| {
on_changed(T::from_str(&s).unwrap_or(if s.is_empty() { T::zero() } else { value }))
};

Self {
value,
Expand All @@ -127,8 +125,7 @@ where
max: Self::set_max(bounds.end_bound()),
padding,
size: None,
content: TextInput::new("", format!("{value}").as_str())
.on_input(convert_to_num)
content: TypedInput::new(value, on_changed)
.padding(padding)
.width(Length::Fixed(127.0))
.class(Theme::default_input()),
Expand Down Expand Up @@ -346,7 +343,7 @@ where
.shrink(padding);
let content = self
.content
.layout(&mut tree.children[0], renderer, &limits, None);
.layout(&mut tree.children[0], renderer, &limits);
let limits2 = Limits::new(Size::new(0.0, 0.0), content.size());
let txt_size = self.size.unwrap_or_else(|| renderer.default_size().0);

Expand Down Expand Up @@ -456,10 +453,15 @@ where

let child = state.children.get_mut(0).expect("fail to get child");
let text_input = child
.children
.get_mut(0)
.expect("fail to get text input")
.state
.downcast_mut::<text_input::State<Renderer::Paragraph>>();
let modifiers = state.state.downcast_mut::<ModifierState>();

let current_text = self.content.text().to_string();

Check warning on line 463 in src/widgets/number_input.rs

View workflow job for this annotation

GitHub Actions / all

`to_string()` called on a `&str`

let mut forward_to_text = |event, shell, child, clipboard| {
self.content.on_event(
child, event, content, cursor, renderer, clipboard, shell, viewport,
Expand All @@ -485,39 +487,43 @@ where
forward_to_text(event, shell, child, clipboard)
} else if text == "\u{8}" {
// Backspace
if T::zero().eq(&self.value) {
event::Status::Ignored
} else {
let mut new_val = self.value.to_string();
match text_input.cursor().state(&Value::new(&new_val)) {
cursor::State::Index(idx)
if idx >= 1 && idx <= new_val.len() =>
{
_ = new_val.remove(idx - 1);
}
cursor::State::Selection { start, end }
if start <= new_val.len() && end <= new_val.len() =>
{
new_val.replace_range(start.min(end)..start.max(end), "");
}
_ => return event::Status::Ignored,
if current_text == T::zero().to_string() {
return event::Status::Ignored;
}

Check failure on line 492 in src/widgets/number_input.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced_aw/iced_aw/src/widgets/number_input.rs
let mut new_val = current_text;
match text_input.cursor().state(&Value::new(&new_val)) {
cursor::State::Index(idx)
if idx >= 1 && idx <= new_val.len() =>
{
_ = new_val.remove(idx - 1);
}

if new_val.is_empty() {
new_val = T::zero().to_string();
cursor::State::Selection { start, end }
if start <= new_val.len() && end <= new_val.len() =>
{
new_val.replace_range(start.min(end)..start.max(end), "");
}
_ => return event::Status::Ignored,
}

match T::from_str(&new_val) {
Ok(val)
if (self.min..self.max).contains(&val)
&& val != self.value =>
{
self.value = val;
forward_to_text(event, shell, child, clipboard)
}
Ok(_) => event::Status::Captured,
_ => event::Status::Ignored,
if new_val.is_empty() {
new_val = T::zero().to_string();
}

Check failure on line 511 in src/widgets/number_input.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced_aw/iced_aw/src/widgets/number_input.rs
match T::from_str(&new_val) {
Ok(val)
if (self.min..self.max).contains(&val)
&& val != self.value =>
{
self.value = val;
forward_to_text(event, shell, child, clipboard)
}

Check failure on line 519 in src/widgets/number_input.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced_aw/iced_aw/src/widgets/number_input.rs
Ok(val)
if (self.min..self.max).contains(&val) =>
{
forward_to_text(event, shell, child, clipboard)
}
Ok(_) => event::Status::Captured,
_ => event::Status::Ignored,
}
} else {
let input = if text == "\u{16}" {
Expand All @@ -526,15 +532,15 @@ where
Some(paste) => paste,
None => return event::Status::Ignored,
}
} else if text.parse::<i64>().is_err() && text != "-" {
} else if text.parse::<i64>().is_err() && text != "-" && text != "." {
return event::Status::Ignored;
} else {
text.to_string()
};

let input = input.trim();

let mut new_val = self.value.to_string();
let mut new_val = current_text;
match text_input.cursor().state(&Value::new(&new_val)) {
cursor::State::Index(idx) if idx <= new_val.len() => {
new_val.insert_str(idx, input);
Expand All @@ -554,7 +560,11 @@ where
self.value = val;

Check failure on line 560 in src/widgets/number_input.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced_aw/iced_aw/src/widgets/number_input.rs
forward_to_text(event, shell, child, clipboard)
}
Ok(_) => event::Status::Captured,
Ok(val)
if (self.min..self.max).contains(&val) =>
forward_to_text(event, shell, child, clipboard),
Ok(_) =>
event::Status::Captured,
_ => event::Status::Ignored,
}
}
Expand All @@ -569,7 +579,9 @@ where
event::Status::Captured

Check failure on line 579 in src/widgets/number_input.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced_aw/iced_aw/src/widgets/number_input.rs
}
keyboard::Key::Named(
keyboard::key::Named::ArrowLeft | keyboard::key::Named::ArrowRight,
keyboard::key::Named::ArrowLeft | keyboard::key::Named::ArrowRight |
keyboard::key::Named::Home |
keyboard::key::Named::End,
) => forward_to_text(event, shell, child, clipboard),
_ => event::Status::Ignored,
},
Expand Down Expand Up @@ -661,7 +673,7 @@ where
state: &Tree,
renderer: &mut Renderer,
theme: &Theme,
_style: &renderer::Style,
style: &renderer::Style,
layout: Layout<'_>,
cursor: Cursor,
viewport: &Rectangle,
Expand All @@ -684,9 +696,9 @@ where
&state.children[0],
renderer,
theme,
style,
content_layout,
cursor,
None,
viewport,
);
let is_decrease_disabled = self.value <= self.min || self.min == self.max;
Expand Down
Loading

0 comments on commit e8b325c

Please sign in to comment.