Skip to content

Commit

Permalink
Make TextBox generic over its data
Browse files Browse the repository at this point in the history
This data must be TextStorage + EditableText, which means
that *currently* it is only String, but just imagine
what the future might hold?

Discussion: there's still something funny going on with
the TextStorage trait; this stuff as written isn't
suitable for use with xi_rope, which was sort of the
whole point.
  • Loading branch information
cmyr committed Oct 5, 2020
1 parent d520d32 commit 73cd9d3
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 30 deletions.
4 changes: 2 additions & 2 deletions docs/book_examples/src/custom_widgets_md.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ impl TextBoxActionController {
}
}

impl Controller<String, TextBox> for TextBoxActionController {
impl Controller<String, TextBox<String>> for TextBoxActionController {
fn event(
&mut self,
child: &mut TextBox,
child: &mut TextBox<String>,
ctx: &mut EventCtx,
event: &Event,
data: &mut String,
Expand Down
38 changes: 19 additions & 19 deletions druid/src/widget/textbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
use std::time::Duration;

use crate::kurbo::{Affine, Insets, Point, Size, Vec2};
use crate::text::{BasicTextInput, EditAction, Editor, TextInput, TextLayout};
use crate::text::{
BasicTextInput, EditAction, EditableText, Editor, TextInput, TextLayout, TextStorage,
};
use crate::theme;
use crate::widget::prelude::*;
use crate::{
Expand All @@ -32,9 +34,9 @@ const CURSOR_BLINK_DURATION: Duration = Duration::from_millis(500);

/// A widget that allows user text input.
#[derive(Debug, Clone)]
pub struct TextBox {
pub struct TextBox<T> {
placeholder: TextLayout<String>,
editor: Editor<String>,
editor: Editor<T>,
// this can be Box<dyn TextInput> in the future
input_handler: BasicTextInput,
hscroll_offset: f64,
Expand All @@ -45,13 +47,15 @@ pub struct TextBox {
multiline: bool,
}

impl TextBox {
impl TextBox<()> {
/// Perform an `EditAction`. The payload *must* be an `EditAction`.
pub const PERFORM_EDIT: Selector<EditAction> =
Selector::new("druid-builtin.textbox.perform-edit");
}

impl<T> TextBox<T> {
/// Create a new TextBox widget
pub fn new() -> TextBox {
pub fn new() -> Self {
let mut placeholder = TextLayout::from_text("");
placeholder.set_text_color(theme::PLACEHOLDER_COLOR);
Self {
Expand All @@ -67,7 +71,7 @@ impl TextBox {
}

/// Create a new multi-line `TextBox`.
pub fn multiline() -> TextBox {
pub fn multiline() -> Self {
let mut this = TextBox::new();
this.editor.set_multiline(true);
this.multiline = true;
Expand Down Expand Up @@ -127,7 +131,9 @@ impl TextBox {
self.editor.layout().set_font(font.clone());
self.placeholder.set_font(font);
}
}

impl<T: TextStorage + EditableText> TextBox<T> {
/// Calculate a stateful scroll offset
fn update_hscroll(&mut self, self_width: f64) {
let cursor_x = self.editor.cursor_line().p0.x;
Expand Down Expand Up @@ -162,8 +168,8 @@ impl TextBox {
}
}

impl Widget<String> for TextBox {
fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut String, _env: &Env) {
impl<T: TextStorage + EditableText> Widget<T> for TextBox<T> {
fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut T, _env: &Env) {
self.suppress_adjust_hscroll = false;
match event {
Event::MouseDown(mouse) => {
Expand Down Expand Up @@ -237,7 +243,7 @@ impl Widget<String> for TextBox {
}
}

fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &String, env: &Env) {
fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &T, env: &Env) {
match event {
LifeCycle::WidgetAdded => {
ctx.register_for_focus();
Expand All @@ -252,7 +258,7 @@ impl Widget<String> for TextBox {
}
}

fn update(&mut self, ctx: &mut UpdateCtx, _: &String, data: &String, env: &Env) {
fn update(&mut self, ctx: &mut UpdateCtx, _: &T, data: &T, env: &Env) {
self.editor.update(ctx, data, env);
if !self.suppress_adjust_hscroll && !self.multiline {
self.update_hscroll(ctx.size().width);
Expand All @@ -262,13 +268,7 @@ impl Widget<String> for TextBox {
}
}

fn layout(
&mut self,
ctx: &mut LayoutCtx,
bc: &BoxConstraints,
_data: &String,
env: &Env,
) -> Size {
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, _data: &T, env: &Env) -> Size {
self.placeholder.rebuild_if_needed(ctx.text(), env);
if self.multiline {
self.editor
Expand All @@ -286,7 +286,7 @@ impl Widget<String> for TextBox {
bc.constrain((width, height))
}

fn paint(&mut self, ctx: &mut PaintCtx, data: &String, env: &Env) {
fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env) {
let size = ctx.size();
let text_size = self.editor.layout().size();
let background_color = env.get(theme::BACKGROUND_LIGHT);
Expand Down Expand Up @@ -357,7 +357,7 @@ impl Widget<String> for TextBox {
}
}

impl Default for TextBox {
impl<T> Default for TextBox<T> {
fn default() -> Self {
TextBox::new()
}
Expand Down
18 changes: 9 additions & 9 deletions druid/src/widget/widget_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,21 +286,21 @@ impl<T: Data, W> EnvScope<T, W> {
#[cfg(test)]
mod tests {
use super::*;
use crate::widget::TextBox;
use crate::widget::Slider;
use crate::Color;

#[test]
fn container_reuse() {
// this should be Container<Align<Container<TextBox>>>
let widget = TextBox::new()
// this should be Container<Align<Container<Slider>>>
let widget = Slider::new()
.background(Color::BLACK)
.align_left()
.border(Color::BLACK, 1.0);
assert!(widget.border_is_some());
assert!(!widget.background_is_some());

// this should be Container<TextBox>
let widget = TextBox::new()
// this should be Container<Slider>
let widget = Slider::new()
.background(Color::BLACK)
.border(Color::BLACK, 1.0);
assert!(widget.background_is_some());
Expand All @@ -309,12 +309,12 @@ mod tests {

#[test]
fn sized_box_reuse() {
// this should be SizedBox<Align<SizedBox<TextBox>>>
let widget = TextBox::new().fix_height(10.0).align_left().fix_width(1.0);
// this should be SizedBox<Align<SizedBox<Slider>>>
let widget = Slider::new().fix_height(10.0).align_left().fix_width(1.0);
assert_eq!(widget.width_and_height(), (Some(1.0), None));

// this should be SizedBox<TextBox>
let widget = TextBox::new().fix_height(10.0).fix_width(1.0);
// this should be SizedBox<Slider>
let widget = Slider::new().fix_height(10.0).fix_width(1.0);
assert_eq!(widget.width_and_height(), (Some(1.0), Some(10.0)));
}
}

0 comments on commit 73cd9d3

Please sign in to comment.