Skip to content

Commit

Permalink
Add text input widget (#159)
Browse files Browse the repository at this point in the history
  • Loading branch information
Zoxc authored Nov 8, 2023
1 parent bc9de1b commit 3b00b02
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 34 deletions.
25 changes: 4 additions & 21 deletions examples/widget-gallery/src/inputs.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use floem::{
peniko::Color,
reactive::create_rw_signal,
style::CursorStyle,
view::View,
views::{text_input, Decorators},
peniko::Color, reactive::create_rw_signal, style::CursorStyle, view::View, views::Decorators,
widgets::text_input,
};

use crate::form::{form, form_item};
Expand All @@ -14,9 +11,7 @@ pub fn text_input_view() -> impl View {
form({
(
form_item("Simple Input:".to_string(), 120.0, move || {
text_input(text)
.style(|s| s.border(1.0).height(32.0))
.keyboard_navigatable()
text_input(text).keyboard_navigatable()
}),
form_item("Styled Input:".to_string(), 120.0, move || {
text_input(text)
Expand All @@ -39,19 +34,7 @@ pub fn text_input_view() -> impl View {
.keyboard_navigatable()
}),
form_item("Disabled Input:".to_string(), 120.0, move || {
text_input(text)
.style(|s| {
s.border(1.5)
.border_radius(15.0)
.border_color(Color::rgb8(189, 189, 189))
.padding(10.0)
.cursor(CursorStyle::Text)
.disabled(|s| s.background(Color::rgb8(224, 224, 224)))
.hover(|s| s.border_color(Color::rgb8(66, 66, 66)))
.focus(|s| s.border_color(Color::LIGHT_SKY_BLUE))
})
.keyboard_navigatable()
.disabled(|| true)
text_input(text).disabled(|| true)
}),
)
})
Expand Down
4 changes: 2 additions & 2 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ impl AppState {
if self.has_style_for_sel(id, StyleSelector::Focus)
|| self.has_style_for_sel(id, StyleSelector::FocusVisible)
{
self.request_style(id);
self.request_style_recursive(id);
}
if let Some(action) = self.get_event_listener(id, &EventListener::FocusGained) {
(*action)(&Event::FocusGained);
Expand All @@ -656,7 +656,7 @@ impl AppState {
if self.has_style_for_sel(old_id, StyleSelector::Focus)
|| self.has_style_for_sel(old_id, StyleSelector::FocusVisible)
{
self.request_style(old_id);
self.request_style_recursive(old_id);
}
if let Some(action) = self.get_event_listener(old_id, &EventListener::FocusLost) {
(*action)(&Event::FocusLost);
Expand Down
18 changes: 14 additions & 4 deletions src/views/text_input.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::action::exec_after;
use crate::keyboard::{self, KeyEvent};
use crate::prop_extracter;
use crate::reactive::{create_effect, RwSignal};
use crate::style::CursorStyle;
use crate::style::{CursorStyle, TextColor};
use crate::style::{FontProps, PaddingLeft};
use crate::unit::PxPct;
use clipboard::{ClipboardContext, ClipboardProvider};
Expand Down Expand Up @@ -30,6 +31,12 @@ use crate::{

use super::Decorators;

prop_extracter! {
Extracter {
color: TextColor,
}
}

enum InputKind {
SingleLine,
#[allow(unused)]
Expand Down Expand Up @@ -60,10 +67,10 @@ pub struct TextInput {
// This makes sure character under the cursor is always fully visible and correctly aligned,
// and may cause the last character in the opposite direction to be "cut"
clip_offset_x: f64,
color: Option<Color>,
selection: Option<Range<usize>>,
width: f32,
height: f32,
style: Extracter,
font: FontProps,
input_kind: InputKind,
cursor_width: f64, // TODO: make this configurable
Expand Down Expand Up @@ -103,7 +110,7 @@ pub fn text_input(buffer: RwSignal<String>) -> TextInput {
text_node: None,
clipped_text: None,
clip_txt_buf: None,
color: None,
style: Default::default(),
font: FontProps::default(),
cursor_x: 0.0,
selection: None,
Expand Down Expand Up @@ -370,7 +377,7 @@ impl TextInput {
}

pub fn get_text_attrs(&self) -> AttrsList {
let mut attrs = Attrs::new().color(self.color.unwrap_or(Color::BLACK));
let mut attrs = Attrs::new().color(self.style.color().unwrap_or(Color::BLACK));

attrs = attrs.font_size(self.font_size());

Expand Down Expand Up @@ -780,6 +787,9 @@ impl View for TextInput {
self.update_text_layout();
cx.app_state_mut().request_layout(self.id);
}
if self.style.read(cx) {
cx.app_state_mut().request_paint(self.id());
}
}

fn layout(&mut self, cx: &mut crate::context::LayoutCx) -> taffy::prelude::Node {
Expand Down
35 changes: 28 additions & 7 deletions src/widgets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,25 @@
//! This module contains all of the built-in widgets of Floem.
//!
mod checkbox;
use crate::{
style::{Background, Style, Transition},
unit::UnitExt,
views::scroll,
};
use peniko::Color;
use std::rc::Rc;

mod checkbox;
pub use checkbox::*;

mod toggle_button;
pub use toggle_button::*;

mod button;
pub use button::*;
use peniko::Color;

use crate::{
style::{Background, Style, Transition},
unit::UnitExt,
views::scroll,
};
mod text_input;
pub use text_input::*;

pub(crate) struct Theme {
pub(crate) background: Color,
Expand All @@ -36,6 +38,9 @@ pub(crate) fn default_theme() -> Theme {
let focus_hover_bg_color = Color::rgb8(234, 230, 236);
let active_bg_color = Color::rgb8(160, 160, 160);

let light_hover_bg_color = Color::rgb8(250, 252, 248);
let light_focus_hover_bg_color = Color::rgb8(250, 249, 251);

let focus_applied_style = Style::new().border_color(Color::rgb8(114, 74, 140));

let focus_visible_applied_style = Style::new().outline(3.0);
Expand Down Expand Up @@ -81,6 +86,7 @@ pub(crate) fn default_theme() -> Theme {
.active(|s| s.background(active_bg_color))
.transition(Background, Transition::linear(0.04))
.hover(|s| s.background(hover_bg_color))
.focus(|s| s.hover(|s| s.background(focus_hover_bg_color)))
.apply(border_style.clone())
.apply(focus_style.clone())
.disabled(|s| {
Expand All @@ -102,16 +108,31 @@ pub(crate) fn default_theme() -> Theme {
.disabled(|s| {
s.color(Color::GRAY).class(CheckboxClass, |s| {
s.background(Color::rgb8(180, 188, 175).with_alpha_factor(0.3))
.color(Color::GRAY)
.hover(|s| s.background(Color::rgb8(180, 188, 175).with_alpha_factor(0.3)))
})
})
.apply(focus_style.clone());

const FONT_SIZE: f32 = 13.0;

let input_style = Style::new()
.background(Color::WHITE)
.hover(|s| s.background(light_hover_bg_color))
.focus(|s| s.hover(|s| s.background(light_focus_hover_bg_color)))
.apply(border_style.clone())
.apply(focus_style.clone())
.padding_vert(8.0)
.disabled(|s| {
s.background(Color::rgb8(180, 188, 175).with_alpha_factor(0.3))
.color(Color::GRAY)
});

let theme = Style::new()
.class(FocusClass, |_| focus_style)
.class(LabeledCheckboxClass, |_| labeled_checkbox_style)
.class(CheckboxClass, |_| checkbox_style)
.class(TextInputClass, |_| input_style)
.class(ButtonClass, |_| button_style)
.class(scroll::Handle, |s| {
s.border_radius(4.0)
Expand Down
12 changes: 12 additions & 0 deletions src/widgets/text_input.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use crate::{
style_class,
view::View,
views::{self, Decorators},
};
use floem_reactive::RwSignal;

style_class!(pub TextInputClass);

pub fn text_input(buffer: RwSignal<String>) -> impl View {
views::text_input(buffer).class(TextInputClass)
}

0 comments on commit 3b00b02

Please sign in to comment.