TextBox

Struct TextBox 

Source
pub struct TextBox<T> {
    pub handles_tab_notifications: bool,
    /* private fields */
}
Expand description

A widget that allows user text input.

§Editing values

If the text you are editing represents a value of some other type, such as a number, you should use a ValueTextBox and an appropriate Formatter. You can create a ValueTextBox by passing the appropriate Formatter to TextBox::with_formatter.

Fields§

§handles_tab_notifications: bool

if true (the default), this textbox will attempt to change focus on tab.

You can override this in a controller if you want to customize tab behaviour.

Implementations§

Source§

impl<T: EditableText + TextStorage> TextBox<T>

Source

pub fn new() -> Self

Create a new TextBox widget.

§Examples
use druid::widget::TextBox;
use druid::{ WidgetExt, Data, Lens };

#[derive(Clone, Data, Lens)]
struct AppState {
    name: String,
}

let _ = TextBox::new()
    .with_placeholder("placeholder text")
    .lens(AppState::name);
Examples found in repository?
examples/invalidation.rs (line 51)
49fn build_widget() -> impl Widget<AppState> {
50    let mut col = Flex::column();
51    col.add_child(TextBox::new().lens(AppState::label).padding(3.0));
52    for i in 0..30 {
53        col.add_child(Button::new(format!("Button {i}")).padding(3.0));
54    }
55    Split::columns(Scroll::new(col), CircleView.lens(AppState::circles)).debug_invalidation()
56}
More examples
Hide additional examples
examples/textbox.rs (line 79)
67fn build_root_widget() -> impl Widget<AppState> {
68    let blurb = Label::new(EXPLAINER)
69        .with_line_break_mode(druid::widget::LineBreaking::WordWrap)
70        .padding(8.0)
71        .border(Color::grey(0.6), 2.0)
72        .rounded(5.0);
73
74    Flex::column()
75        .cross_axis_alignment(druid::widget::CrossAxisAlignment::Start)
76        .with_child(blurb)
77        .with_spacer(24.0)
78        .with_child(
79            TextBox::new()
80                .with_placeholder("Single")
81                .lens(AppState::single),
82        )
83        .with_default_spacer()
84        .with_flex_child(
85            TextBox::multiline()
86                .with_placeholder("Multi")
87                .lens(AppState::multi)
88                .expand_width(),
89            1.0,
90        )
91        .padding(8.0)
92}
examples/hello.rs (line 63)
51fn build_root_widget() -> impl Widget<HelloState> {
52    // a label that will determine its text based on the current app data.
53    let label = Label::new(|data: &HelloState, _env: &Env| {
54        if data.name.is_empty() {
55            "Hello anybody!?".to_string()
56        } else {
57            format!("Hello {}!", data.name)
58        }
59    })
60    .with_text_size(32.0);
61
62    // a textbox that modifies `name`.
63    let textbox = TextBox::new()
64        .with_placeholder("Who are we greeting?")
65        .with_text_size(18.0)
66        .fix_width(TEXT_BOX_WIDTH)
67        .lens(HelloState::name);
68
69    // arrange the two widgets vertically, with some padding
70    Flex::column()
71        .with_child(label)
72        .with_spacer(VERTICAL_WIDGET_SPACING)
73        .with_child(textbox)
74        .align_vertical(UnitPoint::CENTER)
75}
examples/lens.rs (line 47)
44fn ui_builder() -> impl Widget<MyComplexState> {
45    // `TextBox` is of type `Widget<String>`
46    // via `.lens` we get it to be of type `Widget<MyComplexState>`
47    let searchbar = TextBox::new().lens(MyComplexState::term_lens);
48
49    // `Slider` is of type `Widget<f64>`
50    // via `.lens` we get it to be of type `Widget<MyComplexState>`
51    let slider = Slider::new().lens(MyComplexState::scale);
52
53    let label = Label::new(|d: &MyComplexState, _: &Env| format!("{}: {:.2}", d.term, d.scale));
54
55    Flex::column()
56        .cross_axis_alignment(CrossAxisAlignment::Center)
57        .with_child(label)
58        .with_default_spacer()
59        .with_child(
60            Flex::row()
61                .cross_axis_alignment(CrossAxisAlignment::Center)
62                .with_child(searchbar)
63                .with_default_spacer()
64                .with_child(slider),
65        )
66        .center()
67}
examples/flex.rs (line 217)
207fn make_spacer_select() -> impl Widget<Params> {
208    Flex::column()
209        .cross_axis_alignment(CrossAxisAlignment::Start)
210        .with_child(Label::new("Insert Spacers:"))
211        .with_default_spacer()
212        .with_child(RadioGroup::column(SPACER_OPTIONS.to_vec()).lens(Params::spacers))
213        .with_default_spacer()
214        .with_child(
215            Flex::row()
216                .with_child(
217                    TextBox::new()
218                        .with_formatter(ParseFormatter::new())
219                        .lens(Params::spacer_size)
220                        .fix_width(60.0),
221                )
222                .with_spacer(druid::theme::WIDGET_CONTROL_COMPONENT_PADDING)
223                .with_child(
224                    Stepper::new()
225                        .with_range(2.0, 50.0)
226                        .with_step(2.0)
227                        .lens(Params::spacer_size),
228                ),
229        )
230}
231
232fn space_if_needed<T: Data>(flex: &mut Flex<T>, params: &Params) {
233    match params.spacers {
234        Spacers::None => (),
235        Spacers::Default => flex.add_default_spacer(),
236        Spacers::Fixed => flex.add_spacer(params.spacer_size),
237        Spacers::Flex => flex.add_flex_spacer(1.0),
238    }
239}
240
241fn build_widget(state: &Params) -> Box<dyn Widget<AppState>> {
242    let mut flex = match state.axis {
243        FlexType::Column => Flex::column(),
244        FlexType::Row => Flex::row(),
245    }
246    .cross_axis_alignment(state.cross_alignment)
247    .main_axis_alignment(state.main_alignment)
248    .must_fill_main_axis(state.fill_major_axis);
249
250    flex.add_child(
251        TextBox::new()
252            .with_placeholder("Sample text")
253            .lens(DemoState::input_text),
254    );
255    space_if_needed(&mut flex, state);
256
257    flex.add_child(
258        Button::new("Clear").on_click(|_ctx, data: &mut DemoState, _env| {
259            data.input_text.clear();
260            data.enabled = false;
261            data.volume = 0.0;
262        }),
263    );
264
265    space_if_needed(&mut flex, state);
266
267    flex.add_child(
268        Label::new(|data: &DemoState, _: &Env| data.input_text.clone()).with_text_size(32.0),
269    );
270    space_if_needed(&mut flex, state);
271    flex.add_child(Checkbox::new("Demo").lens(DemoState::enabled));
272    space_if_needed(&mut flex, state);
273    flex.add_child(Switch::new().lens(DemoState::enabled));
274    space_if_needed(&mut flex, state);
275    flex.add_child(Slider::new().lens(DemoState::volume));
276    space_if_needed(&mut flex, state);
277    flex.add_child(ProgressBar::new().lens(DemoState::volume));
278    space_if_needed(&mut flex, state);
279    flex.add_child(
280        Stepper::new()
281            .with_range(0.0, 1.0)
282            .with_step(0.1)
283            .with_wraparound(true)
284            .lens(DemoState::volume),
285    );
286
287    let mut flex = SizedBox::new(flex);
288    if state.fix_minor_axis {
289        match state.axis {
290            FlexType::Row => flex = flex.height(200.),
291            FlexType::Column => flex = flex.width(200.),
292        }
293    }
294    if state.fix_major_axis {
295        match state.axis {
296            FlexType::Row => flex = flex.width(600.),
297            FlexType::Column => flex = flex.height(300.),
298        }
299    }
300
301    let flex = flex
302        .padding(8.0)
303        .border(Color::grey(0.6), 2.0)
304        .rounded(5.0)
305        .lens(AppState::demo_state);
306
307    if state.debug_layout {
308        flex.debug_paint_layout().boxed()
309    } else {
310        flex.boxed()
311    }
312}
examples/open_save.rs (line 60)
39fn ui_builder() -> impl Widget<String> {
40    let rs = FileSpec::new("Rust source", &["rs"]);
41    let txt = FileSpec::new("Text file", &["txt"]);
42    let other = FileSpec::new("Bogus file", &["foo", "bar", "baz"]);
43    // The options can also be generated at runtime,
44    // so to show that off we create a String for the default save name.
45    let default_save_name = String::from("MyFile.txt");
46    let save_dialog_options = FileDialogOptions::new()
47        .allowed_types(vec![rs, txt, other])
48        .default_type(txt)
49        .default_name(default_save_name)
50        .name_label("Target")
51        .title("Choose a target for this lovely file")
52        .button_text("Export");
53    let open_dialog_options = save_dialog_options
54        .clone()
55        .default_name("MySavedFile.txt")
56        .name_label("Source")
57        .title("Where did you put that file?")
58        .button_text("Import");
59
60    let input = TextBox::new();
61    let save = Button::new("Save").on_click(move |ctx, _, _| {
62        ctx.submit_command(druid::commands::SHOW_SAVE_PANEL.with(save_dialog_options.clone()))
63    });
64    let open = Button::new("Open").on_click(move |ctx, _, _| {
65        ctx.submit_command(druid::commands::SHOW_OPEN_PANEL.with(open_dialog_options.clone()))
66    });
67
68    let mut col = Flex::column();
69    col.add_child(input);
70    col.add_spacer(8.0);
71    col.add_child(save);
72    col.add_child(open);
73    Align::centered(col)
74}
Source

pub fn multiline() -> Self

Create a new multi-line TextBox.

§Examples
let multiline = TextBox::multiline()
    .lens(AppState::name);
Examples found in repository?
examples/markdown_preview.rs (line 128)
115fn build_root_widget() -> impl Widget<AppState> {
116    let label = Scroll::new(
117        RawLabel::new()
118            .with_text_color(Color::BLACK)
119            .with_line_break_mode(LineBreaking::WordWrap)
120            .lens(AppState::rendered)
121            .expand_width()
122            .padding((SPACER_SIZE * 4.0, SPACER_SIZE)),
123    )
124    .vertical()
125    .background(Color::grey8(222))
126    .expand();
127
128    let textbox = TextBox::multiline()
129        .lens(AppState::raw)
130        .controller(RichTextRebuilder)
131        .expand()
132        .padding(5.0);
133
134    Split::columns(label, textbox)
135}
More examples
Hide additional examples
examples/textbox.rs (line 85)
67fn build_root_widget() -> impl Widget<AppState> {
68    let blurb = Label::new(EXPLAINER)
69        .with_line_break_mode(druid::widget::LineBreaking::WordWrap)
70        .padding(8.0)
71        .border(Color::grey(0.6), 2.0)
72        .rounded(5.0);
73
74    Flex::column()
75        .cross_axis_alignment(druid::widget::CrossAxisAlignment::Start)
76        .with_child(blurb)
77        .with_spacer(24.0)
78        .with_child(
79            TextBox::new()
80                .with_placeholder("Single")
81                .lens(AppState::single),
82        )
83        .with_default_spacer()
84        .with_flex_child(
85            TextBox::multiline()
86                .with_placeholder("Multi")
87                .lens(AppState::multi)
88                .expand_width(),
89            1.0,
90        )
91        .padding(8.0)
92}
examples/event_viewer.rs (line 232)
231fn interactive_area() -> impl Widget<AppState> {
232    let text_box = TextBox::multiline()
233        .with_text_color(Color::rgb8(0xf0, 0xf0, 0xea))
234        .fix_size(INTERACTIVE_AREA_DIM, INTERACTIVE_AREA_DIM)
235        .lens(AppState::text_input)
236        .controller(EventLogger {
237            filter: |event| matches!(event, Event::KeyDown(_) | Event::KeyUp(_)),
238        });
239
240    let mouse_box = SizedBox::empty()
241        .fix_size(INTERACTIVE_AREA_DIM, INTERACTIVE_AREA_DIM)
242        .background(CURSOR_BACKGROUND_COLOR)
243        .rounded(5.0)
244        .border(INTERACTIVE_AREA_BORDER, 1.0)
245        .controller(EventLogger {
246            filter: |event| {
247                matches!(
248                    event,
249                    Event::MouseDown(_) | Event::MouseUp(_) | Event::Wheel(_)
250                )
251            },
252        });
253
254    Flex::row()
255        .with_flex_spacer(1.0)
256        .with_child(text_box)
257        .with_flex_spacer(1.0)
258        .with_child(mouse_box)
259        .with_flex_spacer(1.0)
260        .padding(10.0)
261}
examples/styled_text.rs (line 145)
72fn ui_builder() -> impl Widget<AppData> {
73    let my_painter = Painter::new(|ctx, _, _| {
74        let bounds = ctx.size().to_rect();
75        if ctx.is_hot() {
76            ctx.fill(bounds, &Color::rgba8(0, 0, 0, 128));
77        }
78
79        if ctx.is_active() {
80            ctx.stroke(bounds, &Color::WHITE, 2.0);
81        }
82    });
83
84    // This is Druid's default text style.
85    // It's set by theme::LABEL_COLOR and theme::UI_FONT
86    let label =
87        Label::new(|data: &String, _env: &_| format!("Default: {data}")).lens(AppData::text);
88
89    // The text_color, text_size, and font builder methods can override the
90    // defaults provided by the theme by passing in a Key or a concrete value.
91    //
92    // In this example, text_color receives a Key from the theme, text_size
93    // gets a custom key which we set with the env_scope wrapper, and the
94    // default font key (theme::FONT_NAME) is overridden in the env_scope
95    // wrapper. (Like text_color and text_size, the font can be set using the
96    // with_font builder method, but overriding here makes it easy to fall back
97    // to the default font)
98    let styled_label = Label::new(|data: &AppData, _env: &_| format!("{data}"))
99        .with_text_color(theme::PRIMARY_LIGHT)
100        .with_font(MY_CUSTOM_FONT)
101        .background(my_painter)
102        .on_click(|_, data, _| {
103            data.size *= 1.1;
104        })
105        .env_scope(|env: &mut druid::Env, data: &AppData| {
106            let new_font = if data.mono {
107                FontDescriptor::new(FontFamily::MONOSPACE)
108            } else {
109                FontDescriptor::new(FontFamily::SYSTEM_UI)
110            }
111            .with_size(data.size);
112            env.set(MY_CUSTOM_FONT, new_font);
113        });
114
115    let labels = Scroll::new(
116        Flex::column()
117            .cross_axis_alignment(CrossAxisAlignment::Start)
118            .with_child(label)
119            .with_default_spacer()
120            .with_child(styled_label),
121    )
122    .expand_height()
123    .fix_width(COLUMN_WIDTH);
124
125    let stepper = Stepper::new()
126        .with_range(0.0, 100.0)
127        .with_step(1.0)
128        .with_wraparound(false)
129        .lens(AppData::size);
130
131    // TODO: Replace Parse usage with TextBox::with_formatter
132    #[allow(deprecated)]
133    let stepper_textbox = LensWrap::new(
134        Parse::new(TextBox::new()),
135        AppData::size.map(|x| Some(*x), |x, y| *x = y.unwrap_or(24.0)),
136    );
137
138    let mono_checkbox = Checkbox::new("Monospace").lens(AppData::mono);
139    let stepper_row = Flex::row()
140        .with_child(stepper_textbox)
141        .with_child(stepper)
142        .with_default_spacer()
143        .with_child(mono_checkbox);
144
145    let input = TextBox::multiline()
146        .with_placeholder("Your sample text here :)")
147        .fix_width(COLUMN_WIDTH)
148        .fix_height(140.0)
149        .lens(AppData::text);
150
151    Flex::column()
152        .main_axis_alignment(MainAxisAlignment::Center)
153        .with_default_spacer()
154        .with_flex_child(labels, 1.0)
155        .with_default_spacer()
156        .with_child(input)
157        .with_default_spacer()
158        .with_child(stepper_row)
159        .with_default_spacer()
160}
Source

pub fn with_line_wrapping(self, wrap_lines: bool) -> Self

If true (and this is a multiline text box) lines will be wrapped at the maximum layout width.

If false, lines will not be wrapped, and horizontal scrolling will be enabled.

§Examples
//will scroll horizontally
let scroll_text_box = TextBox::new()
    .with_line_wrapping(false)
    .lens(AppState::name);

//will wrap only for a single line
let wrap_text_box = TextBox::new()
    .with_line_wrapping(true)
    .lens(AppState::name);

//will scroll as well as having multiple lines
let scroll_multi_line_text_box = TextBox::multiline()
    .with_line_wrapping(false)
    .lens(AppState::name);

//will wrap for each line
let wrap_multi_line_text_box = TextBox::multiline()
    .with_line_wrapping(true) // this is default and can be removed for the same result
    .lens(AppState::name);
Source§

impl<T> TextBox<T>

Source

pub fn with_text_size(self, size: impl Into<KeyOrValue<f64>>) -> Self

Builder-style method for setting the text size.

The argument can be either an f64 or a Key<f64>.

§Examples
let text_box = TextBox::new()
    .with_text_size(14.)
    .lens(AppState::name);
use druid::Key;

const FONT_SIZE : Key<f64> = Key::new("font-size");

let text_box = TextBox::new()
    .with_text_size(FONT_SIZE)
    .lens(AppState::name);
Examples found in repository?
examples/hello.rs (line 65)
51fn build_root_widget() -> impl Widget<HelloState> {
52    // a label that will determine its text based on the current app data.
53    let label = Label::new(|data: &HelloState, _env: &Env| {
54        if data.name.is_empty() {
55            "Hello anybody!?".to_string()
56        } else {
57            format!("Hello {}!", data.name)
58        }
59    })
60    .with_text_size(32.0);
61
62    // a textbox that modifies `name`.
63    let textbox = TextBox::new()
64        .with_placeholder("Who are we greeting?")
65        .with_text_size(18.0)
66        .fix_width(TEXT_BOX_WIDTH)
67        .lens(HelloState::name);
68
69    // arrange the two widgets vertically, with some padding
70    Flex::column()
71        .with_child(label)
72        .with_spacer(VERTICAL_WIDGET_SPACING)
73        .with_child(textbox)
74        .align_vertical(UnitPoint::CENTER)
75}
More examples
Hide additional examples
examples/transparency.rs (line 86)
62fn build_root_widget() -> impl Widget<HelloState> {
63    // Draw red circle, and two semi-transparent rectangles
64    let circle_and_rects = Painter::new(|ctx, _data, _env| {
65        let boundaries = ctx.size().to_rect();
66        let center = (boundaries.width() / 2., boundaries.height() / 2.);
67        let circle = Circle::new(center, center.0.min(center.1));
68        ctx.fill(circle, &Color::RED);
69
70        let rect1 = Rect::new(0., 0., boundaries.width() / 2., boundaries.height() / 2.);
71        ctx.fill(rect1, &Color::rgba8(0x0, 0xff, 0, 125));
72
73        let rect2 = Rect::new(
74            boundaries.width() / 2.,
75            boundaries.height() / 2.,
76            boundaries.width(),
77            boundaries.height(),
78        );
79        ctx.fill(rect2, &Color::rgba8(0x0, 0x0, 0xff, 125));
80    });
81
82    // This textbox modifies the label, idea here is to test that the background
83    // invalidation works when you type to the textbox
84    let textbox = TextBox::new()
85        .with_placeholder("Type to test clearing")
86        .with_text_size(18.0)
87        .lens(HelloState::name)
88        .fix_width(250.);
89
90    let label = Label::new(|data: &HelloState, _env: &Env| {
91        if data.name.is_empty() {
92            "Text: ".to_string()
93        } else {
94            format!("Text: {}!", data.name)
95        }
96    })
97    .with_text_color(Color::RED)
98    .with_text_size(32.0);
99
100    Flex::column()
101        .with_flex_child(circle_and_rects.expand().controller(DragController), 10.0)
102        .with_spacer(4.0)
103        .with_child(textbox)
104        .with_spacer(4.0)
105        .with_child(label)
106}
Source

pub fn with_text_alignment(self, alignment: TextAlignment) -> Self

Builder-style method to set the TextAlignment.

This is only relevant when the TextBox is not multiline, in which case it determines how the text is positioned inside the TextBox when it does not fill the available space.

§Note:

This does not behave exactly like TextAlignment does when used with label; in particular this does not account for reading direction. This means that TextAlignment::Start (the default) always means left aligned, and TextAlignment::End always means right aligned.

This should be considered a bug, but it will not be fixed until proper BiDi support is implemented.

§Examples
use druid::TextAlignment;

let text_box = TextBox::new()
    .with_text_alignment(TextAlignment::Center)
    .lens(AppState::name);
Source

pub fn with_font(self, font: impl Into<KeyOrValue<FontDescriptor>>) -> Self

Builder-style method for setting the font.

The argument can be a FontDescriptor or a Key<FontDescriptor> that refers to a font defined in the Env.

§Examples
use druid::{ FontDescriptor, FontFamily, Key };

const FONT : Key<FontDescriptor> = Key::new("font");

let text_box = TextBox::new()
    .with_font(FontDescriptor::new(FontFamily::MONOSPACE))
    .lens(AppState::name);

let text_box = TextBox::new()
    .with_font(FONT)
    .lens(AppState::name);
Source

pub fn with_text_color(self, color: impl Into<KeyOrValue<Color>>) -> Self

Builder-style method for setting the text color.

The argument can be either a Color or a Key<Color>.

§Examples
use druid::{ Color, Key };

const COLOR : Key<Color> = Key::new("color");

let text_box = TextBox::new()
    .with_text_color(Color::RED)
    .lens(AppState::name);

let text_box = TextBox::new()
    .with_text_color(COLOR)
    .lens(AppState::name);
Examples found in repository?
examples/event_viewer.rs (line 233)
231fn interactive_area() -> impl Widget<AppState> {
232    let text_box = TextBox::multiline()
233        .with_text_color(Color::rgb8(0xf0, 0xf0, 0xea))
234        .fix_size(INTERACTIVE_AREA_DIM, INTERACTIVE_AREA_DIM)
235        .lens(AppState::text_input)
236        .controller(EventLogger {
237            filter: |event| matches!(event, Event::KeyDown(_) | Event::KeyUp(_)),
238        });
239
240    let mouse_box = SizedBox::empty()
241        .fix_size(INTERACTIVE_AREA_DIM, INTERACTIVE_AREA_DIM)
242        .background(CURSOR_BACKGROUND_COLOR)
243        .rounded(5.0)
244        .border(INTERACTIVE_AREA_BORDER, 1.0)
245        .controller(EventLogger {
246            filter: |event| {
247                matches!(
248                    event,
249                    Event::MouseDown(_) | Event::MouseUp(_) | Event::Wheel(_)
250                )
251            },
252        });
253
254    Flex::row()
255        .with_flex_spacer(1.0)
256        .with_child(text_box)
257        .with_flex_spacer(1.0)
258        .with_child(mouse_box)
259        .with_flex_spacer(1.0)
260        .padding(10.0)
261}
Source

pub fn set_text_size(&mut self, size: impl Into<KeyOrValue<f64>>)

Set the text size.

The argument can be either an f64 or a Key<f64>.

Source

pub fn set_font(&mut self, font: impl Into<KeyOrValue<FontDescriptor>>)

Set the font.

The argument can be a FontDescriptor or a Key<FontDescriptor> that refers to a font defined in the Env.

Source

pub fn set_text_alignment(&mut self, alignment: TextAlignment)

Set the TextAlignment for this `TextBox``.

This is only relevant when the TextBox is not multiline, in which case it determines how the text is positioned inside the TextBox when it does not fill the available space.

§Note:

This does not behave exactly like TextAlignment does when used with label; in particular this does not account for reading direction. This means that TextAlignment::Start (the default) always means left aligned, and TextAlignment::End always means right aligned.

This should be considered a bug, but it will not be fixed until proper BiDi support is implemented.

Source

pub fn set_text_color(&mut self, color: impl Into<KeyOrValue<Color>>)

Set the text color.

The argument can be either a Color or a Key<Color>.

If you change this property, you are responsible for calling request_layout to ensure the label is updated.

Source

pub fn text_position(&self) -> Point

The point, relative to the origin, where this text box draws its TextLayout.

This is exposed in case the user wants to do additional drawing based on properties of the text.

This is not valid until layout has been called.

Source§

impl<T: Data> TextBox<T>

Source

pub fn with_placeholder(self, placeholder: impl Into<LabelText<T>>) -> Self

Builder-style method to set the TextBox’s placeholder text.

Examples found in repository?
examples/textbox.rs (line 80)
67fn build_root_widget() -> impl Widget<AppState> {
68    let blurb = Label::new(EXPLAINER)
69        .with_line_break_mode(druid::widget::LineBreaking::WordWrap)
70        .padding(8.0)
71        .border(Color::grey(0.6), 2.0)
72        .rounded(5.0);
73
74    Flex::column()
75        .cross_axis_alignment(druid::widget::CrossAxisAlignment::Start)
76        .with_child(blurb)
77        .with_spacer(24.0)
78        .with_child(
79            TextBox::new()
80                .with_placeholder("Single")
81                .lens(AppState::single),
82        )
83        .with_default_spacer()
84        .with_flex_child(
85            TextBox::multiline()
86                .with_placeholder("Multi")
87                .lens(AppState::multi)
88                .expand_width(),
89            1.0,
90        )
91        .padding(8.0)
92}
More examples
Hide additional examples
examples/hello.rs (line 64)
51fn build_root_widget() -> impl Widget<HelloState> {
52    // a label that will determine its text based on the current app data.
53    let label = Label::new(|data: &HelloState, _env: &Env| {
54        if data.name.is_empty() {
55            "Hello anybody!?".to_string()
56        } else {
57            format!("Hello {}!", data.name)
58        }
59    })
60    .with_text_size(32.0);
61
62    // a textbox that modifies `name`.
63    let textbox = TextBox::new()
64        .with_placeholder("Who are we greeting?")
65        .with_text_size(18.0)
66        .fix_width(TEXT_BOX_WIDTH)
67        .lens(HelloState::name);
68
69    // arrange the two widgets vertically, with some padding
70    Flex::column()
71        .with_child(label)
72        .with_spacer(VERTICAL_WIDGET_SPACING)
73        .with_child(textbox)
74        .align_vertical(UnitPoint::CENTER)
75}
examples/transparency.rs (line 85)
62fn build_root_widget() -> impl Widget<HelloState> {
63    // Draw red circle, and two semi-transparent rectangles
64    let circle_and_rects = Painter::new(|ctx, _data, _env| {
65        let boundaries = ctx.size().to_rect();
66        let center = (boundaries.width() / 2., boundaries.height() / 2.);
67        let circle = Circle::new(center, center.0.min(center.1));
68        ctx.fill(circle, &Color::RED);
69
70        let rect1 = Rect::new(0., 0., boundaries.width() / 2., boundaries.height() / 2.);
71        ctx.fill(rect1, &Color::rgba8(0x0, 0xff, 0, 125));
72
73        let rect2 = Rect::new(
74            boundaries.width() / 2.,
75            boundaries.height() / 2.,
76            boundaries.width(),
77            boundaries.height(),
78        );
79        ctx.fill(rect2, &Color::rgba8(0x0, 0x0, 0xff, 125));
80    });
81
82    // This textbox modifies the label, idea here is to test that the background
83    // invalidation works when you type to the textbox
84    let textbox = TextBox::new()
85        .with_placeholder("Type to test clearing")
86        .with_text_size(18.0)
87        .lens(HelloState::name)
88        .fix_width(250.);
89
90    let label = Label::new(|data: &HelloState, _env: &Env| {
91        if data.name.is_empty() {
92            "Text: ".to_string()
93        } else {
94            format!("Text: {}!", data.name)
95        }
96    })
97    .with_text_color(Color::RED)
98    .with_text_size(32.0);
99
100    Flex::column()
101        .with_flex_child(circle_and_rects.expand().controller(DragController), 10.0)
102        .with_spacer(4.0)
103        .with_child(textbox)
104        .with_spacer(4.0)
105        .with_child(label)
106}
examples/sub_window.rs (line 344)
332fn build_root_widget() -> impl Widget<HelloState> {
333    let label = EnvScope::new(
334        |env, _t| env.set(theme::TEXT_COLOR, env.get(theme::PRIMARY_LIGHT)),
335        ControllerHost::new(
336            Label::new(|data: &HelloState, _env: &Env| {
337                format!("Hello {}! {} ", data.name, data.sub.my_stuff)
338            }),
339            TooltipController::new("Tips! Are good"),
340        ),
341    );
342    // a textbox that modifies `name`.
343    let textbox = TextBox::new()
344        .with_placeholder("Who are we greeting?")
345        .fix_width(TEXT_BOX_WIDTH)
346        .lens(HelloState::sub.then(SubState::my_stuff));
347
348    let button = Button::new("Make sub window")
349        .on_click(|ctx, data: &mut SubState, env| {
350            let tb = TextBox::new().lens(SubState::my_stuff);
351            let drag_thing = Label::new("Drag me").controller(DragWindowController::new());
352            let col = Flex::column().with_child(drag_thing).with_child(tb);
353
354            ctx.new_sub_window(
355                WindowConfig::default()
356                    .show_titlebar(false)
357                    .window_size(Size::new(100., 100.))
358                    .set_level(WindowLevel::AppWindow),
359                col,
360                data.clone(),
361                env.clone(),
362            );
363        })
364        .center()
365        .lens(HelloState::sub);
366
367    let check_box =
368        ControllerHost::new(Checkbox::new("Closeable?"), CancelClose).lens(HelloState::closeable);
369    // arrange the two widgets vertically, with some padding
370    let layout = Flex::column()
371        .with_child(label)
372        .with_flex_child(ScreenThing.lens(Unit::default()).padding(5.), 1.)
373        .with_spacer(VERTICAL_WIDGET_SPACING)
374        .with_child(textbox)
375        .with_child(button)
376        .with_child(check_box);
377
378    // center the two widgets in the available space
379    Align::centered(layout)
380}
examples/flex.rs (line 252)
241fn build_widget(state: &Params) -> Box<dyn Widget<AppState>> {
242    let mut flex = match state.axis {
243        FlexType::Column => Flex::column(),
244        FlexType::Row => Flex::row(),
245    }
246    .cross_axis_alignment(state.cross_alignment)
247    .main_axis_alignment(state.main_alignment)
248    .must_fill_main_axis(state.fill_major_axis);
249
250    flex.add_child(
251        TextBox::new()
252            .with_placeholder("Sample text")
253            .lens(DemoState::input_text),
254    );
255    space_if_needed(&mut flex, state);
256
257    flex.add_child(
258        Button::new("Clear").on_click(|_ctx, data: &mut DemoState, _env| {
259            data.input_text.clear();
260            data.enabled = false;
261            data.volume = 0.0;
262        }),
263    );
264
265    space_if_needed(&mut flex, state);
266
267    flex.add_child(
268        Label::new(|data: &DemoState, _: &Env| data.input_text.clone()).with_text_size(32.0),
269    );
270    space_if_needed(&mut flex, state);
271    flex.add_child(Checkbox::new("Demo").lens(DemoState::enabled));
272    space_if_needed(&mut flex, state);
273    flex.add_child(Switch::new().lens(DemoState::enabled));
274    space_if_needed(&mut flex, state);
275    flex.add_child(Slider::new().lens(DemoState::volume));
276    space_if_needed(&mut flex, state);
277    flex.add_child(ProgressBar::new().lens(DemoState::volume));
278    space_if_needed(&mut flex, state);
279    flex.add_child(
280        Stepper::new()
281            .with_range(0.0, 1.0)
282            .with_step(0.1)
283            .with_wraparound(true)
284            .lens(DemoState::volume),
285    );
286
287    let mut flex = SizedBox::new(flex);
288    if state.fix_minor_axis {
289        match state.axis {
290            FlexType::Row => flex = flex.height(200.),
291            FlexType::Column => flex = flex.width(200.),
292        }
293    }
294    if state.fix_major_axis {
295        match state.axis {
296            FlexType::Row => flex = flex.width(600.),
297            FlexType::Column => flex = flex.height(300.),
298        }
299    }
300
301    let flex = flex
302        .padding(8.0)
303        .border(Color::grey(0.6), 2.0)
304        .rounded(5.0)
305        .lens(AppState::demo_state);
306
307    if state.debug_layout {
308        flex.debug_paint_layout().boxed()
309    } else {
310        flex.boxed()
311    }
312}
examples/styled_text.rs (line 146)
72fn ui_builder() -> impl Widget<AppData> {
73    let my_painter = Painter::new(|ctx, _, _| {
74        let bounds = ctx.size().to_rect();
75        if ctx.is_hot() {
76            ctx.fill(bounds, &Color::rgba8(0, 0, 0, 128));
77        }
78
79        if ctx.is_active() {
80            ctx.stroke(bounds, &Color::WHITE, 2.0);
81        }
82    });
83
84    // This is Druid's default text style.
85    // It's set by theme::LABEL_COLOR and theme::UI_FONT
86    let label =
87        Label::new(|data: &String, _env: &_| format!("Default: {data}")).lens(AppData::text);
88
89    // The text_color, text_size, and font builder methods can override the
90    // defaults provided by the theme by passing in a Key or a concrete value.
91    //
92    // In this example, text_color receives a Key from the theme, text_size
93    // gets a custom key which we set with the env_scope wrapper, and the
94    // default font key (theme::FONT_NAME) is overridden in the env_scope
95    // wrapper. (Like text_color and text_size, the font can be set using the
96    // with_font builder method, but overriding here makes it easy to fall back
97    // to the default font)
98    let styled_label = Label::new(|data: &AppData, _env: &_| format!("{data}"))
99        .with_text_color(theme::PRIMARY_LIGHT)
100        .with_font(MY_CUSTOM_FONT)
101        .background(my_painter)
102        .on_click(|_, data, _| {
103            data.size *= 1.1;
104        })
105        .env_scope(|env: &mut druid::Env, data: &AppData| {
106            let new_font = if data.mono {
107                FontDescriptor::new(FontFamily::MONOSPACE)
108            } else {
109                FontDescriptor::new(FontFamily::SYSTEM_UI)
110            }
111            .with_size(data.size);
112            env.set(MY_CUSTOM_FONT, new_font);
113        });
114
115    let labels = Scroll::new(
116        Flex::column()
117            .cross_axis_alignment(CrossAxisAlignment::Start)
118            .with_child(label)
119            .with_default_spacer()
120            .with_child(styled_label),
121    )
122    .expand_height()
123    .fix_width(COLUMN_WIDTH);
124
125    let stepper = Stepper::new()
126        .with_range(0.0, 100.0)
127        .with_step(1.0)
128        .with_wraparound(false)
129        .lens(AppData::size);
130
131    // TODO: Replace Parse usage with TextBox::with_formatter
132    #[allow(deprecated)]
133    let stepper_textbox = LensWrap::new(
134        Parse::new(TextBox::new()),
135        AppData::size.map(|x| Some(*x), |x, y| *x = y.unwrap_or(24.0)),
136    );
137
138    let mono_checkbox = Checkbox::new("Monospace").lens(AppData::mono);
139    let stepper_row = Flex::row()
140        .with_child(stepper_textbox)
141        .with_child(stepper)
142        .with_default_spacer()
143        .with_child(mono_checkbox);
144
145    let input = TextBox::multiline()
146        .with_placeholder("Your sample text here :)")
147        .fix_width(COLUMN_WIDTH)
148        .fix_height(140.0)
149        .lens(AppData::text);
150
151    Flex::column()
152        .main_axis_alignment(MainAxisAlignment::Center)
153        .with_default_spacer()
154        .with_flex_child(labels, 1.0)
155        .with_default_spacer()
156        .with_child(input)
157        .with_default_spacer()
158        .with_child(stepper_row)
159        .with_default_spacer()
160}
Source

pub fn set_placeholder(&mut self, placeholder: impl Into<LabelText<T>>)

Set the TextBox’s placeholder text.

Source§

impl<T> TextBox<T>

Source

pub fn text(&self) -> &TextComponent<T>

An immutable reference to the inner TextComponent.

Using this correctly is difficult; please see the TextComponent docs for more information.

Source

pub fn text_mut(&mut self) -> &mut TextComponent<T>

A mutable reference to the inner TextComponent.

Using this correctly is difficult; please see the TextComponent docs for more information.

Source§

impl TextBox<String>

Source

pub fn with_formatter<T: Data>( self, formatter: impl Formatter<T> + 'static, ) -> ValueTextBox<T>

Turn this TextBox into a ValueTextBox, using the Formatter to manage the value.

For simple value formatting, you can use the ParseFormatter.

Examples found in repository?
examples/flex.rs (line 218)
207fn make_spacer_select() -> impl Widget<Params> {
208    Flex::column()
209        .cross_axis_alignment(CrossAxisAlignment::Start)
210        .with_child(Label::new("Insert Spacers:"))
211        .with_default_spacer()
212        .with_child(RadioGroup::column(SPACER_OPTIONS.to_vec()).lens(Params::spacers))
213        .with_default_spacer()
214        .with_child(
215            Flex::row()
216                .with_child(
217                    TextBox::new()
218                        .with_formatter(ParseFormatter::new())
219                        .lens(Params::spacer_size)
220                        .fix_width(60.0),
221                )
222                .with_spacer(druid::theme::WIDGET_CONTROL_COMPONENT_PADDING)
223                .with_child(
224                    Stepper::new()
225                        .with_range(2.0, 50.0)
226                        .with_step(2.0)
227                        .lens(Params::spacer_size),
228                ),
229        )
230}

Trait Implementations§

Source§

impl<T: TextStorage + EditableText> Default for TextBox<T>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<T: TextStorage + EditableText> Widget<T> for TextBox<T>

Source§

fn event( &mut self, ctx: &mut EventCtx<'_, '_>, event: &Event, data: &mut T, env: &Env, )

Handle an event. Read more
Source§

fn lifecycle( &mut self, ctx: &mut LifeCycleCtx<'_, '_>, event: &LifeCycle, data: &T, env: &Env, )

Handle a life cycle notification. Read more
Source§

fn update(&mut self, ctx: &mut UpdateCtx<'_, '_>, old: &T, data: &T, env: &Env)

Update the widget’s appearance in response to a change in the app’s Data or Env. Read more
Source§

fn layout( &mut self, ctx: &mut LayoutCtx<'_, '_>, bc: &BoxConstraints, data: &T, env: &Env, ) -> Size

Compute layout. Read more
Source§

fn paint(&mut self, ctx: &mut PaintCtx<'_, '_, '_>, data: &T, env: &Env)

Paint the widget appearance. Read more
Source§

fn compute_max_intrinsic( &mut self, axis: Axis, ctx: &mut LayoutCtx<'_, '_>, bc: &BoxConstraints, data: &T, env: &Env, ) -> f64

Computes max intrinsic/preferred dimension of a widget on the provided axis. Read more

Auto Trait Implementations§

§

impl<T> !Freeze for TextBox<T>

§

impl<T> !RefUnwindSafe for TextBox<T>

§

impl<T> !Send for TextBox<T>

§

impl<T> !Sync for TextBox<T>

§

impl<T> Unpin for TextBox<T>
where T: Unpin,

§

impl<T> !UnwindSafe for TextBox<T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> RoundFrom<T> for T

Source§

fn round_from(x: T) -> T

Performs the conversion.
Source§

impl<T, U> RoundInto<U> for T
where U: RoundFrom<T>,

Source§

fn round_into(self) -> U

Performs the conversion.
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, W> TestWidgetExt<T> for W
where T: Data, W: Widget<T> + 'static,

Source§

fn record(self, recording: &Recording) -> Recorder<Self>

Available on non-WebAssembly only.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T, W> WidgetExt<T> for W
where T: Data, W: Widget<T> + 'static,

Source§

fn padding(self, insets: impl Into<KeyOrValue<Insets>>) -> Padding<T, Self>

Wrap this widget in a Padding widget with the given Insets. Read more
Source§

fn center(self) -> Align<T>

Wrap this widget in an Align widget, configured to center it.
Source§

fn align_left(self) -> Align<T>

Wrap this widget in an Align widget, configured to align left.
Source§

fn align_right(self) -> Align<T>

Wrap this widget in an Align widget, configured to align right.
Source§

fn align_vertical(self, align: UnitPoint) -> Align<T>

Wrap this widget in an Align widget, configured to align vertically.
Source§

fn align_horizontal(self, align: UnitPoint) -> Align<T>

Wrap this widget in an Align widget, configured to align horizontally.
Source§

fn fix_width(self, width: impl Into<KeyOrValue<f64>>) -> SizedBox<T>

Wrap this widget in a SizedBox with an explicit width.
Source§

fn fix_height(self, height: impl Into<KeyOrValue<f64>>) -> SizedBox<T>

Wrap this widget in a SizedBox with an explicit height.
Source§

fn fix_size( self, width: impl Into<KeyOrValue<f64>>, height: impl Into<KeyOrValue<f64>>, ) -> SizedBox<T>

Wrap this widget in an SizedBox with an explicit width and height
Source§

fn expand(self) -> SizedBox<T>

Wrap this widget in a SizedBox with an infinite width and height. Read more
Source§

fn expand_width(self) -> SizedBox<T>

Wrap this widget in a SizedBox with an infinite width. Read more
Source§

fn expand_height(self) -> SizedBox<T>

Wrap this widget in a SizedBox with an infinite width. Read more
Source§

fn background(self, brush: impl Into<BackgroundBrush<T>>) -> Container<T>

Wrap this widget in a Container with the provided background brush. Read more
Source§

fn foreground(self, brush: impl Into<BackgroundBrush<T>>) -> Container<T>

Wrap this widget in a Container with the provided foreground brush. Read more
Source§

fn border( self, color: impl Into<KeyOrValue<Color>>, width: impl Into<KeyOrValue<f64>>, ) -> Container<T>

Wrap this widget in a Container with the given border. Read more
Source§

fn env_scope(self, f: impl Fn(&mut Env, &T) + 'static) -> EnvScope<T, Self>

Wrap this widget in a EnvScope widget, modifying the parent Env with the provided closure.
Source§

fn controller<C: Controller<T, Self>>( self, controller: C, ) -> ControllerHost<Self, C>

Wrap this widget with the provided Controller.
Source§

fn on_added( self, f: impl Fn(&mut Self, &mut LifeCycleCtx<'_, '_>, &T, &Env) + 'static, ) -> ControllerHost<Self, Added<T, Self>>

Provide a closure that will be called when this widget is added to the widget tree. Read more
Source§

fn on_click( self, f: impl Fn(&mut EventCtx<'_, '_>, &mut T, &Env) + 'static, ) -> ControllerHost<Self, Click<T>>

Control the events of this widget with a Click widget. The closure provided will be called when the widget is clicked with the left mouse button. Read more
Source§

fn debug_paint_layout(self) -> EnvScope<T, Self>

Draw the layout Rects of this widget and its children.
Source§

fn debug_widget_id(self) -> EnvScope<T, Self>

Display the WidgetIds for this widget and its children, when hot. Read more
Source§

fn debug_invalidation(self) -> DebugInvalidation<T, Self>

Draw a color-changing rectangle over this widget, allowing you to see the invalidation regions.
Source§

fn debug_widget(self) -> EnvScope<T, Self>

Set the DEBUG_WIDGET env variable for this widget (and its descendants). Read more
Source§

fn lens<S: Data, L: Lens<S, T>>(self, lens: L) -> LensWrap<S, T, L, Self>

Wrap this widget in a LensWrap widget for the provided Lens.
Source§

fn with_id(self, id: WidgetId) -> IdentityWrapper<Self>

Assign the widget a specific WidgetId. Read more
Source§

fn boxed(self) -> Box<dyn Widget<T>>

Wrap this widget in a Box.
Source§

fn scroll(self) -> Scroll<T, Self>

Wrap this widget in a Scroll widget.
Source§

fn disabled_if( self, disabled_if: impl Fn(&T, &Env) -> bool + 'static, ) -> DisabledIf<T, Self>

Wrap this widget in a DisabledIf widget. Read more
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more