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

Add text input widget #159

Merged
merged 1 commit into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}