Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Number input widget #762

Closed
wants to merge 12 commits into from
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ members = [
"examples/todos",
"examples/tour",
"examples/tooltip",
"examples/number_input"
]

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

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

[dependencies]
iced = { path = "../.." }
133 changes: 133 additions & 0 deletions examples/number_input/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
use iced::{
number_input, window, Align, Container, Element, Length, NumberInput, Row,
Sandbox, Settings, Text,
};

#[derive(Default)]
pub struct NumberInputDemo {
state: number_input::State,
value: u8,
}

#[derive(Debug, Clone)]
pub enum Message {
NumInpChanged(u8),
}

fn main() -> iced::Result {
NumberInputDemo::run(Settings {
default_text_size: 14,
window: window::Settings {
size: (250, 200),
..Default::default()
},
..Settings::default()
})
}

impl Sandbox for NumberInputDemo {
type Message = Message;

fn new() -> Self {
Self {
value: 27,
..Self::default()
}
}

fn title(&self) -> String {
String::from("Number Input Demo")
}

fn update(&mut self, message: Message) {
match message {
Message::NumInpChanged(val) => {
self.value = val;
}
}
}

fn view(&mut self) -> Element<Message> {
let lb_minute = Text::new("Number Input:");
let txt_minute = NumberInput::new(
&mut self.state,
self.value,
255,
Message::NumInpChanged,
)
.step(1)
.input_style(style::CustomTextInput)
.style(style::CustomNumInput);

Container::new(
Row::new()
.spacing(10)
.align_items(Align::Center)
.push(lb_minute)
.push(txt_minute),
)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.into()
}
}

mod style {
use iced::Color;
use iced::{number_input, text_input};

const BACKGROUND: Color =
Color::from_rgb(238.0 / 255.0, 238.0 / 255.0, 238.0 / 255.0);
const FOREGROUND: Color =
Color::from_rgb(224.0 / 255.0, 224.0 / 255.0, 224.0 / 255.0);
const HOVERED: Color =
Color::from_rgb(129.0 / 255.0, 129.0 / 255.0, 129.0 / 255.0);
const PRIMARY: Color =
Color::from_rgb(12.0 / 255.0, 46.0 / 251.0, 179.0 / 255.0);

pub struct CustomNumInput;
impl number_input::StyleSheet for CustomNumInput {
fn active(&self) -> number_input::Style {
number_input::Style {
icon_color: PRIMARY,
..number_input::Style::default()
}
}
}

pub struct CustomTextInput;
impl text_input::StyleSheet for CustomTextInput {
fn active(&self) -> text_input::Style {
text_input::Style {
background: BACKGROUND.into(),
border_color: PRIMARY,
border_width: 1.0,
border_radius: 5.5,
..text_input::Style::default()
}
}

fn focused(&self) -> text_input::Style {
let active = self.active();

text_input::Style {
background: FOREGROUND.into(),
..active
}
}

fn placeholder_color(&self) -> Color {
HOVERED
}

fn selection_color(&self) -> Color {
HOVERED
}

fn value_color(&self) -> Color {
Color::BLACK
}
}
}
3 changes: 3 additions & 0 deletions glow/src/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::Renderer;
pub mod button;
pub mod checkbox;
pub mod container;
pub mod number_input;
pub mod pane_grid;
pub mod pick_list;
pub mod progress_bar;
Expand All @@ -29,6 +30,8 @@ pub use checkbox::Checkbox;
#[doc(no_inline)]
pub use container::Container;
#[doc(no_inline)]
pub use number_input::NumberInput;
#[doc(no_inline)]
pub use pane_grid::PaneGrid;
#[doc(no_inline)]
pub use pick_list::PickList;
Expand Down
13 changes: 13 additions & 0 deletions glow/src/widget/number_input.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//! Display fields that can only be filled with numeric type.
//!
//! A [`TextInput`] has some local [`State`].
use crate::Renderer;

pub use iced_graphics::number_input::{Style, StyleSheet};
pub use iced_native::number_input::State;

/// A field that can only be filled with numeric type.
///
/// This is an alias of an `iced_native` text input with an `iced_wgpu::Renderer`.
pub type NumberInput<'a, T, Message> =
iced_native::NumberInput<'a, T, Message, Renderer>;
3 changes: 3 additions & 0 deletions graphics/src/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod button;
pub mod checkbox;
pub mod container;
pub mod image;
pub mod number_input;
pub mod pane_grid;
pub mod pick_list;
pub mod progress_bar;
Expand All @@ -34,6 +35,8 @@ pub use checkbox::Checkbox;
#[doc(no_inline)]
pub use container::Container;
#[doc(no_inline)]
pub use number_input::NumberInput;
#[doc(no_inline)]
pub use pane_grid::PaneGrid;
#[doc(no_inline)]
pub use pick_list::PickList;
Expand Down
130 changes: 130 additions & 0 deletions graphics/src/widget/number_input.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
//! Display fields that can only be filled with numeric type.
//!
//! A [`NumberInput`] has some local [`State`].
use crate::backend::{self, Backend};
use crate::{Primitive, Renderer};
use iced_native::mouse;
use iced_native::number_input::{self, ModifierState};
use iced_native::{
Background, Color, HorizontalAlignment, Point, Rectangle, VerticalAlignment,
};

pub use iced_native::number_input::State;
pub use iced_style::number_input::{Style, StyleSheet};

/// A field that can only be filled with numeric type.
///
/// This is an alias of an `iced_native` number input with an `iced_wgpu::Renderer`.
pub type NumberInput<'a, T, Message, Backend> =
iced_native::NumberInput<'a, T, Message, Renderer<Backend>>;

impl<B> number_input::Renderer for Renderer<B>
where
B: Backend + backend::Text,
{
type Style = Box<dyn StyleSheet>;

const DEFAULT_PADDING: u16 = 5;

fn draw(
&mut self,
cursor_position: Point,
state: &ModifierState,
inc_bounds: Rectangle,
dec_bounds: Rectangle,
is_mouse_over: bool,
is_decrease_disabled: bool,
is_increase_disabled: bool,
(content, _): Self::Output,
style: &<Self as number_input::Renderer>::Style,
font: Self::Font,
) -> Self::Output {
let mouse_over_decrease = dec_bounds.contains(cursor_position);
let mouse_over_increase = inc_bounds.contains(cursor_position);

let decrease_btn_style = if is_decrease_disabled {
style.disabled()
} else if state.decrease_pressed {
style.pressed()
} else {
style.active()
};

let increase_btn_style = if is_increase_disabled {
style.disabled()
} else if state.increase_pressed {
style.pressed()
} else {
style.active()
};

// decrease button section
let decrease_button_rect = Primitive::Quad {
bounds: dec_bounds,
background: decrease_btn_style
.button_background
.unwrap_or(Background::Color(Color::TRANSPARENT)),
border_radius: 3.0,
border_width: 0.,
border_color: Color::TRANSPARENT,
};
let decrease_text = Primitive::Text {
content: String::from("▼"),
bounds: Rectangle {
x: dec_bounds.center_x(),
y: dec_bounds.center_y(),
..dec_bounds
},
font,
size: dec_bounds.height * 0.9,
color: decrease_btn_style.icon_color,
horizontal_alignment: HorizontalAlignment::Center,
vertical_alignment: VerticalAlignment::Center,
};
let decrease_btn = Primitive::Group {
primitives: vec![decrease_button_rect, decrease_text],
};

// increase button section
let increase_button_rect = Primitive::Quad {
bounds: inc_bounds,
background: increase_btn_style
.button_background
.unwrap_or(Background::Color(Color::TRANSPARENT)),
border_radius: 3.0,
border_width: 0.,
border_color: Color::TRANSPARENT,
};
let increase_text = Primitive::Text {
content: String::from("▲"),
bounds: Rectangle {
x: inc_bounds.center_x(),
y: inc_bounds.center_y(),
..inc_bounds
},
font,
size: inc_bounds.height * 0.9,
color: increase_btn_style.icon_color,
horizontal_alignment: HorizontalAlignment::Center,
vertical_alignment: VerticalAlignment::Center,
};
let increase_btn = Primitive::Group {
primitives: vec![increase_button_rect, increase_text],
};

(
Primitive::Group {
primitives: vec![content, decrease_btn, increase_btn],
},
if (mouse_over_decrease && !is_decrease_disabled)
|| (mouse_over_increase && !is_increase_disabled)
{
mouse::Interaction::Pointer
} else if is_mouse_over {
mouse::Interaction::Text
} else {
mouse::Interaction::default()
},
)
}
}
25 changes: 23 additions & 2 deletions native/src/renderer/null.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
button, checkbox, column, container, pane_grid, progress_bar, radio, row,
scrollable, slider, text, text_input, Color, Element, Font,
button, checkbox, column, container, number_input, pane_grid, progress_bar,
radio, row, scrollable, slider, text, text_input, Color, Element, Font,
HorizontalAlignment, Layout, Point, Rectangle, Renderer, Size,
VerticalAlignment,
};
Expand Down Expand Up @@ -285,3 +285,24 @@ impl pane_grid::Renderer for Null {
) {
}
}

impl number_input::Renderer for Null {
type Style = ();

const DEFAULT_PADDING: u16 = 7;

fn draw(
&mut self,
_: Point,
_: &number_input::ModifierState,
_: Rectangle,
_: Rectangle,
_: bool,
_: bool,
_: bool,
_: Self::Output,
_: &<Self as number_input::Renderer>::Style,
_: <Self as text::Renderer>::Font,
) -> Self::Output {
}
}
3 changes: 3 additions & 0 deletions native/src/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub mod checkbox;
pub mod column;
pub mod container;
pub mod image;
pub mod number_input;
pub mod pane_grid;
pub mod pick_list;
pub mod progress_bar;
Expand All @@ -49,6 +50,8 @@ pub use container::Container;
#[doc(no_inline)]
pub use image::Image;
#[doc(no_inline)]
pub use number_input::NumberInput;
#[doc(no_inline)]
pub use pane_grid::PaneGrid;
#[doc(no_inline)]
pub use pick_list::PickList;
Expand Down
Loading