Struct druid::widget::Label

source ·
pub struct Label<T> { /* private fields */ }
Expand description

A label that displays static or dynamic text.

This type manages an inner RawLabel, updating its text based on the current Data and Env as required.

If your Data is already text, you may use a RawLabel directly. As a convenience, you can create a RawLabel with the Label::raw constructor method.

A label is the easiest way to display text in Druid. A label is instantiated with some LabelText type, such as an ArcStr or a LocalizedString, and also has methods for setting the default font, font-size, text color, and other attributes.

In addition to being a Widget, Label is also regularly used as a component in other widgets that wish to display text; to facilitate this it has a draw_at method that allows the caller to easily draw the label’s text at the desired position on screen.

Examples

Make a label to say something very important:


let font = FontDescriptor::new(FontFamily::SYSTEM_UI)
    .with_weight(FontWeight::BOLD)
    .with_size(48.0);

let important_label = Label::new("WATCH OUT!")
    .with_font(font)
    .with_text_color(Color::rgb(1.0, 0.2, 0.2));

Implementations§

source§

impl<T: TextStorage> Label<T>

source

pub fn raw() -> RawLabel<T>

Create a new RawLabel.

This can display text Data directly.

source§

impl<T: Data> Label<T>

source

pub fn new(text: impl Into<LabelText<T>>) -> Self

Construct a new Label widget.

use druid::LocalizedString;
use druid::widget::Label;

// Construct a new Label using static string.
let _: Label<u32> = Label::new("Hello world");

// Construct a new Label using localized string.
let text = LocalizedString::new("hello-counter").with_arg("count", |data: &u32, _env| (*data).into());
let _: Label<u32> = Label::new(text);

// Construct a new dynamic Label. Text will be updated when data changes.
let _: Label<u32> = Label::new(|data: &u32, _env: &_| format!("Hello world: {}", data));
Examples found in repository?
examples/disabled.rs (line 39)
37
38
39
40
41
42
fn named_child(name: &str, widget: impl Widget<AppData> + 'static) -> impl Widget<AppData> {
    Flex::row()
        .with_child(Label::new(name))
        .with_default_spacer()
        .with_child(widget)
}
More examples
Hide additional examples
examples/tabs.rs (line 107)
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
    fn group<T: Data, W: Widget<T> + 'static>(text: &str, w: W) -> impl Widget<T> {
        Flex::column()
            .cross_axis_alignment(CrossAxisAlignment::Start)
            .with_child(
                Label::new(text)
                    .background(theme::PLACEHOLDER_COLOR)
                    .expand_width(),
            )
            .with_default_spacer()
            .with_child(w)
            .with_default_spacer()
            .border(Color::WHITE, 0.5)
    }

    let axis_picker = group(
        "Tab bar axis",
        RadioGroup::column(vec![
            ("Horizontal", Axis::Horizontal),
            ("Vertical", Axis::Vertical),
        ])
        .lens(TabConfig::axis),
    );

    let cross_picker = group(
        "Tab bar edge",
        RadioGroup::column(vec![
            ("Leading", TabsEdge::Leading),
            ("Trailing", TabsEdge::Trailing),
        ])
        .lens(TabConfig::edge),
    );

    let transit_picker = group(
        "Transition",
        RadioGroup::column(vec![
            ("Instant", TabsTransition::Instant),
            (
                "Slide",
                TabsTransition::Slide(Duration::from_millis(250).as_nanos() as u64),
            ),
        ])
        .lens(TabConfig::transition),
    );

    let sidebar = Flex::column()
        .main_axis_alignment(MainAxisAlignment::Start)
        .cross_axis_alignment(CrossAxisAlignment::Start)
        .with_child(axis_picker)
        .with_default_spacer()
        .with_child(cross_picker)
        .with_default_spacer()
        .with_child(transit_picker)
        .with_flex_spacer(1.)
        .fix_width(200.0)
        .lens(AppState::tab_config);

    let vs = ViewSwitcher::new(
        |app_s: &AppState, _| app_s.tab_config.clone(),
        |tc: &TabConfig, _, _| Box::new(build_tab_widget(tc)),
    );
    Flex::row().with_child(sidebar).with_flex_child(vs, 1.0)
}

#[derive(Clone, Data)]
struct NumberedTabs;

impl TabsPolicy for NumberedTabs {
    type Key = usize;
    type Build = ();
    type Input = DynamicTabData;
    type LabelWidget = Label<DynamicTabData>;
    type BodyWidget = Label<DynamicTabData>;

    fn tabs_changed(&self, old_data: &DynamicTabData, data: &DynamicTabData) -> bool {
        old_data.tabs_key() != data.tabs_key()
    }

    fn tabs(&self, data: &DynamicTabData) -> Vec<Self::Key> {
        data.tab_labels.iter().copied().collect()
    }

    fn tab_info(&self, key: Self::Key, _data: &DynamicTabData) -> TabInfo<DynamicTabData> {
        TabInfo::new(format!("Tab {key:?}"), true)
    }

    fn tab_body(&self, key: Self::Key, _data: &DynamicTabData) -> Label<DynamicTabData> {
        Label::new(format!("Dynamic tab body {key:?}"))
    }

    fn close_tab(&self, key: Self::Key, data: &mut DynamicTabData) {
        if let Some(idx) = data.tab_labels.index_of(&key) {
            data.remove_tab(idx)
        }
    }

    fn tab_label(
        &self,
        _key: Self::Key,
        info: TabInfo<Self::Input>,
        _data: &Self::Input,
    ) -> Self::LabelWidget {
        Self::default_make_label(info)
    }
}

fn build_tab_widget(tab_config: &TabConfig) -> impl Widget<AppState> {
    let dyn_tabs = Tabs::for_policy(NumberedTabs)
        .with_axis(tab_config.axis)
        .with_edge(tab_config.edge)
        .with_transition(tab_config.transition)
        .lens(AppState::advanced);

    let control_dynamic = Flex::column()
        .cross_axis_alignment(CrossAxisAlignment::Start)
        .with_child(Label::new("Control dynamic tabs"))
        .with_child(Button::new("Add a tab").on_click(|_c, d: &mut DynamicTabData, _e| d.add_tab()))
        .with_child(Label::new(|adv: &DynamicTabData, _e: &Env| {
            format!("Highest tab number is {}", adv.highest_tab)
        }))
        .with_spacer(20.)
        .lens(AppState::advanced);

    let first_static_tab = Flex::row()
        .with_child(Label::new("Rename tab:"))
        .with_child(TextBox::new().lens(AppState::first_tab_name));

    let main_tabs = Tabs::new()
        .with_axis(tab_config.axis)
        .with_edge(tab_config.edge)
        .with_transition(tab_config.transition)
        .with_tab(
            |app_state: &AppState, _: &Env| app_state.first_tab_name.to_string(),
            first_static_tab,
        )
        .with_tab("Dynamic", control_dynamic)
        .with_tab("Page 3", Label::new("Page 3 content"))
        .with_tab("Page 4", Label::new("Page 4 content"))
        .with_tab("Page 5", Label::new("Page 5 content"))
        .with_tab("Page 6", Label::new("Page 6 content"))
        .with_tab_index(1);

    Split::rows(main_tabs, dyn_tabs).draggable(true)
}
examples/calc.rs (line 136)
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
fn op_button_label(op: char, label: String) -> impl Widget<CalcState> {
    let painter = Painter::new(|ctx, _, env| {
        let bounds = ctx.size().to_rect();

        ctx.fill(bounds, &env.get(theme::PRIMARY_DARK));

        if ctx.is_hot() {
            ctx.stroke(bounds.inset(-0.5), &Color::WHITE, 1.0);
        }

        if ctx.is_active() {
            ctx.fill(bounds, &env.get(theme::PRIMARY_LIGHT));
        }
    });

    Label::new(label)
        .with_text_size(24.)
        .center()
        .background(painter)
        .expand()
        .on_click(move |_ctx, data: &mut CalcState, _env| data.op(op))
}

fn op_button(op: char) -> impl Widget<CalcState> {
    op_button_label(op, op.to_string())
}

fn digit_button(digit: u8) -> impl Widget<CalcState> {
    let painter = Painter::new(|ctx, _, env| {
        let bounds = ctx.size().to_rect();

        ctx.fill(bounds, &env.get(theme::BACKGROUND_LIGHT));

        if ctx.is_hot() {
            ctx.stroke(bounds.inset(-0.5), &Color::WHITE, 1.0);
        }

        if ctx.is_active() {
            ctx.fill(bounds, &Color::rgb8(0x71, 0x71, 0x71));
        }
    });

    Label::new(format!("{digit}"))
        .with_text_size(24.)
        .center()
        .background(painter)
        .expand()
        .on_click(move |_ctx, data: &mut CalcState, _env| data.digit(digit))
}

fn flex_row<T: Data>(
    w1: impl Widget<T> + 'static,
    w2: impl Widget<T> + 'static,
    w3: impl Widget<T> + 'static,
    w4: impl Widget<T> + 'static,
) -> impl Widget<T> {
    Flex::row()
        .with_flex_child(w1, 1.0)
        .with_spacer(1.0)
        .with_flex_child(w2, 1.0)
        .with_spacer(1.0)
        .with_flex_child(w3, 1.0)
        .with_spacer(1.0)
        .with_flex_child(w4, 1.0)
}

fn build_calc() -> impl Widget<CalcState> {
    let display = Label::new(|data: &String, _env: &_| data.clone())
        .with_text_size(32.0)
        .lens(CalcState::value)
        .padding(5.0);
    Flex::column()
        .with_flex_spacer(0.2)
        .with_child(display)
        .with_flex_spacer(0.2)
        .cross_axis_alignment(CrossAxisAlignment::End)
        .with_flex_child(
            flex_row(
                op_button_label('c', "CE".to_string()),
                op_button('C'),
                op_button('⌫'),
                op_button('÷'),
            ),
            1.0,
        )
        .with_spacer(1.0)
        .with_flex_child(
            flex_row(
                digit_button(7),
                digit_button(8),
                digit_button(9),
                op_button('×'),
            ),
            1.0,
        )
        .with_spacer(1.0)
        .with_flex_child(
            flex_row(
                digit_button(4),
                digit_button(5),
                digit_button(6),
                op_button('−'),
            ),
            1.0,
        )
        .with_spacer(1.0)
        .with_flex_child(
            flex_row(
                digit_button(1),
                digit_button(2),
                digit_button(3),
                op_button('+'),
            ),
            1.0,
        )
        .with_spacer(1.0)
        .with_flex_child(
            flex_row(
                op_button('±'),
                digit_button(0),
                op_button('.'),
                op_button('='),
            ),
            1.0,
        )
}
examples/either.rs (line 45)
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
fn ui_builder() -> impl Widget<AppState> {
    // Our UI consists of a column with a button and an `Either` widget
    let button = Checkbox::new("Toggle slider")
        .lens(AppState::which)
        .padding(5.0);

    // The `Either` widget has two children, only one of which is visible at a time.
    // To determine which child is visible, you pass it a closure that takes the
    // `Data` and the `Env` and returns a bool; if it returns `true`, the first
    // widget will be visible, and if `false`, the second.
    let either = Either::new(
        |data, _env| data.which,
        Slider::new().lens(AppState::value).padding(5.0),
        Label::new("Click to reveal slider").padding(5.0),
    );
    Flex::column().with_child(button).with_child(either)
}
examples/textbox.rs (line 68)
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
fn build_root_widget() -> impl Widget<AppState> {
    let blurb = Label::new(EXPLAINER)
        .with_line_break_mode(druid::widget::LineBreaking::WordWrap)
        .padding(8.0)
        .border(Color::grey(0.6), 2.0)
        .rounded(5.0);

    Flex::column()
        .cross_axis_alignment(druid::widget::CrossAxisAlignment::Start)
        .with_child(blurb)
        .with_spacer(24.0)
        .with_child(
            TextBox::new()
                .with_placeholder("Single")
                .lens(AppState::single),
        )
        .with_default_spacer()
        .with_flex_child(
            TextBox::multiline()
                .with_placeholder("Multi")
                .lens(AppState::multi)
                .expand_width(),
            1.0,
        )
        .padding(8.0)
}
examples/hello.rs (lines 53-59)
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
fn build_root_widget() -> impl Widget<HelloState> {
    // a label that will determine its text based on the current app data.
    let label = Label::new(|data: &HelloState, _env: &Env| {
        if data.name.is_empty() {
            "Hello anybody!?".to_string()
        } else {
            format!("Hello {}!", data.name)
        }
    })
    .with_text_size(32.0);

    // a textbox that modifies `name`.
    let textbox = TextBox::new()
        .with_placeholder("Who are we greeting?")
        .with_text_size(18.0)
        .fix_width(TEXT_BOX_WIDTH)
        .lens(HelloState::name);

    // arrange the two widgets vertically, with some padding
    Flex::column()
        .with_child(label)
        .with_spacer(VERTICAL_WIDGET_SPACING)
        .with_child(textbox)
        .align_vertical(UnitPoint::CENTER)
}
source

pub fn dynamic(text: impl Fn(&T, &Env) -> String + 'static) -> Self

Construct a new dynamic label.

The contents of this label are generated from the data using a closure.

This is provided as a convenience; a closure can also be passed to new, but due to limitations of the implementation of that method, the types in the closure need to be annotated, which is not true for this method.

Examples

The following are equivalent.

use druid::Env;
use druid::widget::Label;
let label1: Label<u32> = Label::new(|data: &u32, _: &Env| format!("total is {}", data));
let label2: Label<u32> = Label::dynamic(|data, _| format!("total is {}", data));
Examples found in repository?
examples/z_stack.rs (lines 47-52)
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
fn build_root_widget() -> impl Widget<State> {
    ZStack::new(
        Button::from_label(Label::dynamic(|state: &State, _| {
            format!(
                "Very large button with text! Count up (currently {})",
                state.counter
            )
        }))
        .on_click(|_, state: &mut State, _| state.counter += 1),
    )
    .with_child(
        Button::new("Reset").on_click(|_, state: &mut State, _| state.counter = 0),
        Vec2::new(1.0, 1.0),
        Vec2::ZERO,
        UnitPoint::LEFT,
        Vec2::new(10.0, 0.0),
    )
}
More examples
Hide additional examples
examples/event_viewer.rs (line 306)
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
fn make_list_item() -> impl Widget<LoggedEvent> {
    Flex::row()
        .with_child(Label::dynamic(|d: &LoggedEvent, _| d.number()).fix_width(PROPERTIES[0].1))
        .with_default_spacer()
        .with_child(Label::dynamic(|d: &LoggedEvent, _| d.name()).fix_width(PROPERTIES[1].1))
        .with_default_spacer()
        .with_child(Label::dynamic(|d: &LoggedEvent, _| d.mouse_pos()).fix_width(PROPERTIES[2].1))
        .with_default_spacer()
        .with_child(Label::dynamic(|d: &LoggedEvent, _| d.wheel_delta()).fix_width(PROPERTIES[3].1))
        .with_default_spacer()
        .with_child(
            Label::dynamic(|d: &LoggedEvent, _| d.mouse_button()).fix_width(PROPERTIES[4].1),
        )
        .with_default_spacer()
        .with_child(Label::dynamic(|d: &LoggedEvent, _| d.click_count()).fix_width(PROPERTIES[5].1))
        .with_default_spacer()
        .with_child(Label::dynamic(|d: &LoggedEvent, _| d.is_repeat()).fix_width(PROPERTIES[6].1))
        .with_default_spacer()
        .with_child(Label::dynamic(|d: &LoggedEvent, _| d.key()).fix_width(PROPERTIES[7].1))
        .with_default_spacer()
        .with_child(Label::dynamic(|d: &LoggedEvent, _| d.code()).fix_width(PROPERTIES[8].1))
        .with_default_spacer()
        .with_child(Label::dynamic(|d: &LoggedEvent, _| d.modifiers()).fix_width(PROPERTIES[9].1))
        .with_default_spacer()
        .with_child(Label::dynamic(|d: &LoggedEvent, _| d.location()).fix_width(PROPERTIES[10].1))
}
examples/slider.rs (lines 57-59)
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
fn build_root_widget() -> impl Widget<AppState> {
    let range = Flex::row()
        .with_child(Label::dynamic(|value: &(f64, f64), _| {
            format!("Value Range: {value:?}")
        }))
        .with_default_spacer()
        .with_child(
            RangeSlider::new()
                .with_range(0.0, 20.0)
                .with_step(1.0)
                .track_color(KeyOrValue::Concrete(Color::RED))
                .fix_width(250.0),
        )
        .lens(AppState::range);

    let value = Flex::row()
        .with_child(Label::dynamic(|value: &AppState, _| {
            format!("Value: {:?}", value.value)
        }))
        .with_default_spacer()
        .with_child(ViewSwitcher::new(
            |data: &AppState, _| data.range,
            |range, _, _| {
                Slider::new()
                    .with_range(range.0, range.1)
                    .track_color(KeyOrValue::Concrete(Color::RED))
                    .knob_style(KnobStyle::Wedge)
                    .axis(Axis::Vertical)
                    .with_step(0.25)
                    .annotated(1.0, 0.25)
                    .fix_height(250.0)
                    .lens(AppState::value)
                    .boxed()
            },
        ));

    // arrange the two widgets vertically, with some padding
    Flex::column()
        .with_child(range)
        .with_spacer(VERTICAL_WIDGET_SPACING)
        .with_child(value)
        .cross_axis_alignment(CrossAxisAlignment::End)
        .align_vertical(UnitPoint::RIGHT)
        .padding(20.0)
}
examples/identity.rs (line 73)
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
fn make_ui() -> impl Widget<OurData> {
    // We can also generate these dynamically whenever we need it.
    let id_two = WidgetId::next();
    // We have a column with 2 labels and 2 buttons.
    // Each of the 2 labels only has access to its own counter and is given a `WidgetId`.
    // Both labels have a controller, this handles commands send to children.
    // The 2 buttons send a command when clicked. Both send the exact same command.
    // The key diference is that they both give a different `WidgetId` as target.
    // This means that only the corresponding controller gets the command, and increments their counter.
    Flex::column()
        .with_child(
            Label::dynamic(|data, _| format!("One: {data}"))
                .controller(LabelControler)
                .with_id(ID_ONE)
                .lens(OurData::counter_one)
                .padding(2.0),
        )
        .with_child(
            Label::dynamic(|data, _| format!("Two: {data}"))
                .controller(LabelControler)
                .with_id(id_two)
                .lens(OurData::counter_two)
                .padding(2.0),
        )
        .with_child(
            Button::<OurData>::new("Increment one")
                .on_click(|ctx, _data, _env| ctx.submit_command(INCREMENT.to(ID_ONE)))
                .padding(2.0),
        )
        .with_child(
            Button::<OurData>::new("Increment two")
                .on_click(move |ctx, _data, _env| ctx.submit_command(INCREMENT.to(id_two)))
                .padding(2.0),
        )
        .padding(10.0)
}
examples/disabled.rs (line 101)
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
fn main_widget() -> impl Widget<AppData> {
    Flex::column()
        .with_child(named_child("text:", TextBox::new().lens(AppData::text)))
        .with_default_spacer()
        .with_child(
            named_child("text (disabled):", TextBox::new().lens(AppData::text))
                .disabled_if(|data, _| data.disabled),
        )
        .with_default_spacer()
        .with_child(named_child("text:", TextBox::new().lens(AppData::text)))
        .with_default_spacer()
        .with_child(
            named_child("text (disabled):", TextBox::new().lens(AppData::text))
                .disabled_if(|data, _| data.disabled),
        )
        .with_default_spacer()
        .with_default_spacer()
        .with_child(
            named_child(
                "value (disabled):",
                Slider::new().with_range(0.0, 10.0).lens(AppData::value),
            )
            .disabled_if(|data, _| data.disabled),
        )
        .with_default_spacer()
        .with_child(
            named_child(
                "value (disabled):",
                Stepper::new()
                    .with_range(0.0, 10.0)
                    .with_step(0.5)
                    .lens(AppData::value),
            )
            .disabled_if(|data, _| data.disabled),
        )
        .with_default_spacer()
        .with_child(
            named_child(
                "option (disabled):",
                Checkbox::new("option").lens(AppData::option),
            )
            .disabled_if(|data, _| data.disabled),
        )
        .with_default_spacer()
        .with_child(
            named_child("option (disabled):", Switch::new().lens(AppData::option))
                .disabled_if(|data, _| data.disabled),
        )
        .with_default_spacer()
        .with_child(
            Flex::row()
                .with_child(
                    Button::new("-")
                        .on_click(|_, data: &mut f64, _| *data -= 1.0)
                        .disabled_if(|data, _| *data < 1.0),
                )
                .with_default_spacer()
                .with_child(Label::dynamic(|data: &f64, _| data.to_string()))
                .with_default_spacer()
                .with_child(
                    Button::new("+")
                        .on_click(|_, data: &mut f64, _| *data += 1.0)
                        .disabled_if(|data, _| *data > 9.0),
                )
                .lens(AppData::value)
                .disabled_if(|data: &AppData, _| data.disabled),
        )
        .with_default_spacer()
        .with_default_spacer()
        .with_default_spacer()
        .with_child(Checkbox::new("disabled").lens(AppData::disabled))
        .with_default_spacer()
        .cross_axis_alignment(CrossAxisAlignment::End)
        .align_horizontal(UnitPoint::CENTER)
}
source

pub fn text(&self) -> ArcStr

Return the current value of the label’s text.

source

pub fn set_text(&mut self, text: impl Into<LabelText<T>>)

Set the label’s text.

Note

If you change this property, at runtime, you must ensure that update is called in order to correctly recompute the text. If you are unsure, call request_update explicitly.

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 found in repository?
examples/transparency.rs (line 97)
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
fn build_root_widget() -> impl Widget<HelloState> {
    // Draw red circle, and two semi-transparent rectangles
    let circle_and_rects = Painter::new(|ctx, _data, _env| {
        let boundaries = ctx.size().to_rect();
        let center = (boundaries.width() / 2., boundaries.height() / 2.);
        let circle = Circle::new(center, center.0.min(center.1));
        ctx.fill(circle, &Color::RED);

        let rect1 = Rect::new(0., 0., boundaries.width() / 2., boundaries.height() / 2.);
        ctx.fill(rect1, &Color::rgba8(0x0, 0xff, 0, 125));

        let rect2 = Rect::new(
            boundaries.width() / 2.,
            boundaries.height() / 2.,
            boundaries.width(),
            boundaries.height(),
        );
        ctx.fill(rect2, &Color::rgba8(0x0, 0x0, 0xff, 125));
    });

    // This textbox modifies the label, idea here is to test that the background
    // invalidation works when you type to the textbox
    let textbox = TextBox::new()
        .with_placeholder("Type to test clearing")
        .with_text_size(18.0)
        .lens(HelloState::name)
        .fix_width(250.);

    let label = Label::new(|data: &HelloState, _env: &Env| {
        if data.name.is_empty() {
            "Text: ".to_string()
        } else {
            format!("Text: {}!", data.name)
        }
    })
    .with_text_color(Color::RED)
    .with_text_size(32.0);

    Flex::column()
        .with_flex_child(circle_and_rects.expand().controller(DragController), 10.0)
        .with_spacer(4.0)
        .with_child(textbox)
        .with_spacer(4.0)
        .with_child(label)
}
More examples
Hide additional examples
examples/layout.rs (line 66)
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
fn build_app() -> impl Widget<u32> {
    // Usually we put all the widgets in one big tree using builder-style
    // methods. Sometimes we split them up in declarations to increase
    // readability. In this case we also have some recurring elements,
    // we add those in a loop later on.
    let mut col = Flex::column().with_child(
        // The `Flex`'s first child is another Flex! In this case it is
        // a row.
        Flex::row()
            // The row has its own children.
            .with_child(
                Label::new("One")
                    .fix_width(60.0)
                    .background(Color::rgb8(0x77, 0x77, 0))
                    .border(Color::WHITE, 3.0)
                    .center(),
            )
            // Spacing element that will fill all available space in
            // between label and a button. Notice that weight is non-zero.
            // We could have achieved a similar result with expanding the
            // width and setting the main-axis-allignment to SpaceBetween.
            .with_flex_spacer(1.0)
            .with_child(Button::new("Two").padding(20.))
            // After we added all the children, we can set some more
            // values using builder-style methods. Since these methods
            // dont return the original `Flex` but a SizedBox and Container
            // respectively, we have to put these at the end.
            .fix_height(100.0)
            //turquoise
            .background(Color::rgb8(0, 0x77, 0x88)),
    );

    for i in 0..5 {
        // Give a larger weight to one of the buttons for it to
        // occupy more space.
        let weight = if i == 2 { 3.0 } else { 1.0 };
        // call `expand_height` to force the buttons to use all their provided flex
        col.add_flex_child(Button::new(format!("Button #{i}")).expand_height(), weight);
    }

    // aspect ratio box
    let aspect_ratio_label = Label::new("This is an aspect-ratio box. Notice how the text will overflow if the box becomes too small.")
        .with_text_color(Color::BLACK)
        .with_line_break_mode(LineBreaking::WordWrap)
        .center();
    let aspect_ratio_box = AspectRatioBox::new(aspect_ratio_label, 4.0)
        .border(Color::BLACK, 1.0)
        .background(Color::WHITE);
    col.add_flex_child(aspect_ratio_box.center(), 1.0);

    // This method asks Druid to draw colored rectangles around our widgets,
    // so we can visually inspect their layout rectangles.
    col.debug_paint_layout()
}
examples/styled_text.rs (line 99)
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
fn ui_builder() -> impl Widget<AppData> {
    let my_painter = Painter::new(|ctx, _, _| {
        let bounds = ctx.size().to_rect();
        if ctx.is_hot() {
            ctx.fill(bounds, &Color::rgba8(0, 0, 0, 128));
        }

        if ctx.is_active() {
            ctx.stroke(bounds, &Color::WHITE, 2.0);
        }
    });

    // This is Druid's default text style.
    // It's set by theme::LABEL_COLOR and theme::UI_FONT
    let label =
        Label::new(|data: &String, _env: &_| format!("Default: {data}")).lens(AppData::text);

    // The text_color, text_size, and font builder methods can override the
    // defaults provided by the theme by passing in a Key or a concrete value.
    //
    // In this example, text_color receives a Key from the theme, text_size
    // gets a custom key which we set with the env_scope wrapper, and the
    // default font key (theme::FONT_NAME) is overridden in the env_scope
    // wrapper. (Like text_color and text_size, the font can be set using the
    // with_font builder method, but overriding here makes it easy to fall back
    // to the default font)
    let styled_label = Label::new(|data: &AppData, _env: &_| format!("{data}"))
        .with_text_color(theme::PRIMARY_LIGHT)
        .with_font(MY_CUSTOM_FONT)
        .background(my_painter)
        .on_click(|_, data, _| {
            data.size *= 1.1;
        })
        .env_scope(|env: &mut druid::Env, data: &AppData| {
            let new_font = if data.mono {
                FontDescriptor::new(FontFamily::MONOSPACE)
            } else {
                FontDescriptor::new(FontFamily::SYSTEM_UI)
            }
            .with_size(data.size);
            env.set(MY_CUSTOM_FONT, new_font);
        });

    let labels = Scroll::new(
        Flex::column()
            .cross_axis_alignment(CrossAxisAlignment::Start)
            .with_child(label)
            .with_default_spacer()
            .with_child(styled_label),
    )
    .expand_height()
    .fix_width(COLUMN_WIDTH);

    let stepper = Stepper::new()
        .with_range(0.0, 100.0)
        .with_step(1.0)
        .with_wraparound(false)
        .lens(AppData::size);

    // TODO: Replace Parse usage with TextBox::with_formatter
    #[allow(deprecated)]
    let stepper_textbox = LensWrap::new(
        Parse::new(TextBox::new()),
        AppData::size.map(|x| Some(*x), |x, y| *x = y.unwrap_or(24.0)),
    );

    let mono_checkbox = Checkbox::new("Monospace").lens(AppData::mono);
    let stepper_row = Flex::row()
        .with_child(stepper_textbox)
        .with_child(stepper)
        .with_default_spacer()
        .with_child(mono_checkbox);

    let input = TextBox::multiline()
        .with_placeholder("Your sample text here :)")
        .fix_width(COLUMN_WIDTH)
        .fix_height(140.0)
        .lens(AppData::text);

    Flex::column()
        .main_axis_alignment(MainAxisAlignment::Center)
        .with_default_spacer()
        .with_flex_child(labels, 1.0)
        .with_default_spacer()
        .with_child(input)
        .with_default_spacer()
        .with_child(stepper_row)
        .with_default_spacer()
}
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 found in repository?
examples/calc.rs (line 137)
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
fn op_button_label(op: char, label: String) -> impl Widget<CalcState> {
    let painter = Painter::new(|ctx, _, env| {
        let bounds = ctx.size().to_rect();

        ctx.fill(bounds, &env.get(theme::PRIMARY_DARK));

        if ctx.is_hot() {
            ctx.stroke(bounds.inset(-0.5), &Color::WHITE, 1.0);
        }

        if ctx.is_active() {
            ctx.fill(bounds, &env.get(theme::PRIMARY_LIGHT));
        }
    });

    Label::new(label)
        .with_text_size(24.)
        .center()
        .background(painter)
        .expand()
        .on_click(move |_ctx, data: &mut CalcState, _env| data.op(op))
}

fn op_button(op: char) -> impl Widget<CalcState> {
    op_button_label(op, op.to_string())
}

fn digit_button(digit: u8) -> impl Widget<CalcState> {
    let painter = Painter::new(|ctx, _, env| {
        let bounds = ctx.size().to_rect();

        ctx.fill(bounds, &env.get(theme::BACKGROUND_LIGHT));

        if ctx.is_hot() {
            ctx.stroke(bounds.inset(-0.5), &Color::WHITE, 1.0);
        }

        if ctx.is_active() {
            ctx.fill(bounds, &Color::rgb8(0x71, 0x71, 0x71));
        }
    });

    Label::new(format!("{digit}"))
        .with_text_size(24.)
        .center()
        .background(painter)
        .expand()
        .on_click(move |_ctx, data: &mut CalcState, _env| data.digit(digit))
}

fn flex_row<T: Data>(
    w1: impl Widget<T> + 'static,
    w2: impl Widget<T> + 'static,
    w3: impl Widget<T> + 'static,
    w4: impl Widget<T> + 'static,
) -> impl Widget<T> {
    Flex::row()
        .with_flex_child(w1, 1.0)
        .with_spacer(1.0)
        .with_flex_child(w2, 1.0)
        .with_spacer(1.0)
        .with_flex_child(w3, 1.0)
        .with_spacer(1.0)
        .with_flex_child(w4, 1.0)
}

fn build_calc() -> impl Widget<CalcState> {
    let display = Label::new(|data: &String, _env: &_| data.clone())
        .with_text_size(32.0)
        .lens(CalcState::value)
        .padding(5.0);
    Flex::column()
        .with_flex_spacer(0.2)
        .with_child(display)
        .with_flex_spacer(0.2)
        .cross_axis_alignment(CrossAxisAlignment::End)
        .with_flex_child(
            flex_row(
                op_button_label('c', "CE".to_string()),
                op_button('C'),
                op_button('⌫'),
                op_button('÷'),
            ),
            1.0,
        )
        .with_spacer(1.0)
        .with_flex_child(
            flex_row(
                digit_button(7),
                digit_button(8),
                digit_button(9),
                op_button('×'),
            ),
            1.0,
        )
        .with_spacer(1.0)
        .with_flex_child(
            flex_row(
                digit_button(4),
                digit_button(5),
                digit_button(6),
                op_button('−'),
            ),
            1.0,
        )
        .with_spacer(1.0)
        .with_flex_child(
            flex_row(
                digit_button(1),
                digit_button(2),
                digit_button(3),
                op_button('+'),
            ),
            1.0,
        )
        .with_spacer(1.0)
        .with_flex_child(
            flex_row(
                op_button('±'),
                digit_button(0),
                op_button('.'),
                op_button('='),
            ),
            1.0,
        )
}
More examples
Hide additional examples
examples/hello.rs (line 60)
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
fn build_root_widget() -> impl Widget<HelloState> {
    // a label that will determine its text based on the current app data.
    let label = Label::new(|data: &HelloState, _env: &Env| {
        if data.name.is_empty() {
            "Hello anybody!?".to_string()
        } else {
            format!("Hello {}!", data.name)
        }
    })
    .with_text_size(32.0);

    // a textbox that modifies `name`.
    let textbox = TextBox::new()
        .with_placeholder("Who are we greeting?")
        .with_text_size(18.0)
        .fix_width(TEXT_BOX_WIDTH)
        .lens(HelloState::name);

    // arrange the two widgets vertically, with some padding
    Flex::column()
        .with_child(label)
        .with_spacer(VERTICAL_WIDGET_SPACING)
        .with_child(textbox)
        .align_vertical(UnitPoint::CENTER)
}
examples/transparency.rs (line 98)
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
fn build_root_widget() -> impl Widget<HelloState> {
    // Draw red circle, and two semi-transparent rectangles
    let circle_and_rects = Painter::new(|ctx, _data, _env| {
        let boundaries = ctx.size().to_rect();
        let center = (boundaries.width() / 2., boundaries.height() / 2.);
        let circle = Circle::new(center, center.0.min(center.1));
        ctx.fill(circle, &Color::RED);

        let rect1 = Rect::new(0., 0., boundaries.width() / 2., boundaries.height() / 2.);
        ctx.fill(rect1, &Color::rgba8(0x0, 0xff, 0, 125));

        let rect2 = Rect::new(
            boundaries.width() / 2.,
            boundaries.height() / 2.,
            boundaries.width(),
            boundaries.height(),
        );
        ctx.fill(rect2, &Color::rgba8(0x0, 0x0, 0xff, 125));
    });

    // This textbox modifies the label, idea here is to test that the background
    // invalidation works when you type to the textbox
    let textbox = TextBox::new()
        .with_placeholder("Type to test clearing")
        .with_text_size(18.0)
        .lens(HelloState::name)
        .fix_width(250.);

    let label = Label::new(|data: &HelloState, _env: &Env| {
        if data.name.is_empty() {
            "Text: ".to_string()
        } else {
            format!("Text: {}!", data.name)
        }
    })
    .with_text_color(Color::RED)
    .with_text_size(32.0);

    Flex::column()
        .with_flex_child(circle_and_rects.expand().controller(DragController), 10.0)
        .with_spacer(4.0)
        .with_child(textbox)
        .with_spacer(4.0)
        .with_child(label)
}
examples/flex.rs (line 268)
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
fn build_widget(state: &Params) -> Box<dyn Widget<AppState>> {
    let mut flex = match state.axis {
        FlexType::Column => Flex::column(),
        FlexType::Row => Flex::row(),
    }
    .cross_axis_alignment(state.cross_alignment)
    .main_axis_alignment(state.main_alignment)
    .must_fill_main_axis(state.fill_major_axis);

    flex.add_child(
        TextBox::new()
            .with_placeholder("Sample text")
            .lens(DemoState::input_text),
    );
    space_if_needed(&mut flex, state);

    flex.add_child(
        Button::new("Clear").on_click(|_ctx, data: &mut DemoState, _env| {
            data.input_text.clear();
            data.enabled = false;
            data.volume = 0.0;
        }),
    );

    space_if_needed(&mut flex, state);

    flex.add_child(
        Label::new(|data: &DemoState, _: &Env| data.input_text.clone()).with_text_size(32.0),
    );
    space_if_needed(&mut flex, state);
    flex.add_child(Checkbox::new("Demo").lens(DemoState::enabled));
    space_if_needed(&mut flex, state);
    flex.add_child(Switch::new().lens(DemoState::enabled));
    space_if_needed(&mut flex, state);
    flex.add_child(Slider::new().lens(DemoState::volume));
    space_if_needed(&mut flex, state);
    flex.add_child(ProgressBar::new().lens(DemoState::volume));
    space_if_needed(&mut flex, state);
    flex.add_child(
        Stepper::new()
            .with_range(0.0, 1.0)
            .with_step(0.1)
            .with_wraparound(true)
            .lens(DemoState::volume),
    );

    let mut flex = SizedBox::new(flex);
    if state.fix_minor_axis {
        match state.axis {
            FlexType::Row => flex = flex.height(200.),
            FlexType::Column => flex = flex.width(200.),
        }
    }
    if state.fix_major_axis {
        match state.axis {
            FlexType::Row => flex = flex.width(600.),
            FlexType::Column => flex = flex.height(300.),
        }
    }

    let flex = flex
        .padding(8.0)
        .border(Color::grey(0.6), 2.0)
        .rounded(5.0)
        .lens(AppState::demo_state);

    if state.debug_layout {
        flex.debug_paint_layout().boxed()
    } else {
        flex.boxed()
    }
}
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 found in repository?
examples/styled_text.rs (line 100)
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
fn ui_builder() -> impl Widget<AppData> {
    let my_painter = Painter::new(|ctx, _, _| {
        let bounds = ctx.size().to_rect();
        if ctx.is_hot() {
            ctx.fill(bounds, &Color::rgba8(0, 0, 0, 128));
        }

        if ctx.is_active() {
            ctx.stroke(bounds, &Color::WHITE, 2.0);
        }
    });

    // This is Druid's default text style.
    // It's set by theme::LABEL_COLOR and theme::UI_FONT
    let label =
        Label::new(|data: &String, _env: &_| format!("Default: {data}")).lens(AppData::text);

    // The text_color, text_size, and font builder methods can override the
    // defaults provided by the theme by passing in a Key or a concrete value.
    //
    // In this example, text_color receives a Key from the theme, text_size
    // gets a custom key which we set with the env_scope wrapper, and the
    // default font key (theme::FONT_NAME) is overridden in the env_scope
    // wrapper. (Like text_color and text_size, the font can be set using the
    // with_font builder method, but overriding here makes it easy to fall back
    // to the default font)
    let styled_label = Label::new(|data: &AppData, _env: &_| format!("{data}"))
        .with_text_color(theme::PRIMARY_LIGHT)
        .with_font(MY_CUSTOM_FONT)
        .background(my_painter)
        .on_click(|_, data, _| {
            data.size *= 1.1;
        })
        .env_scope(|env: &mut druid::Env, data: &AppData| {
            let new_font = if data.mono {
                FontDescriptor::new(FontFamily::MONOSPACE)
            } else {
                FontDescriptor::new(FontFamily::SYSTEM_UI)
            }
            .with_size(data.size);
            env.set(MY_CUSTOM_FONT, new_font);
        });

    let labels = Scroll::new(
        Flex::column()
            .cross_axis_alignment(CrossAxisAlignment::Start)
            .with_child(label)
            .with_default_spacer()
            .with_child(styled_label),
    )
    .expand_height()
    .fix_width(COLUMN_WIDTH);

    let stepper = Stepper::new()
        .with_range(0.0, 100.0)
        .with_step(1.0)
        .with_wraparound(false)
        .lens(AppData::size);

    // TODO: Replace Parse usage with TextBox::with_formatter
    #[allow(deprecated)]
    let stepper_textbox = LensWrap::new(
        Parse::new(TextBox::new()),
        AppData::size.map(|x| Some(*x), |x, y| *x = y.unwrap_or(24.0)),
    );

    let mono_checkbox = Checkbox::new("Monospace").lens(AppData::mono);
    let stepper_row = Flex::row()
        .with_child(stepper_textbox)
        .with_child(stepper)
        .with_default_spacer()
        .with_child(mono_checkbox);

    let input = TextBox::multiline()
        .with_placeholder("Your sample text here :)")
        .fix_width(COLUMN_WIDTH)
        .fix_height(140.0)
        .lens(AppData::text);

    Flex::column()
        .main_axis_alignment(MainAxisAlignment::Center)
        .with_default_spacer()
        .with_flex_child(labels, 1.0)
        .with_default_spacer()
        .with_child(input)
        .with_default_spacer()
        .with_child(stepper_row)
        .with_default_spacer()
}
source

pub fn with_line_break_mode(self, mode: LineBreaking) -> Self

Builder-style method to set the LineBreaking behaviour.

Examples found in repository?
examples/textbox.rs (line 69)
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
fn build_root_widget() -> impl Widget<AppState> {
    let blurb = Label::new(EXPLAINER)
        .with_line_break_mode(druid::widget::LineBreaking::WordWrap)
        .padding(8.0)
        .border(Color::grey(0.6), 2.0)
        .rounded(5.0);

    Flex::column()
        .cross_axis_alignment(druid::widget::CrossAxisAlignment::Start)
        .with_child(blurb)
        .with_spacer(24.0)
        .with_child(
            TextBox::new()
                .with_placeholder("Single")
                .lens(AppState::single),
        )
        .with_default_spacer()
        .with_flex_child(
            TextBox::multiline()
                .with_placeholder("Multi")
                .lens(AppState::multi)
                .expand_width(),
            1.0,
        )
        .padding(8.0)
}
More examples
Hide additional examples
examples/input_region.rs (line 50)
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
    pub fn new() -> Self {
        let info_label = Label::new(INFO_TEXT)
            .with_line_break_mode(LineBreaking::WordWrap)
            .padding(20.0)
            .background(Color::rgba(0.2, 0.2, 0.2, 1.0));
        let toggle_input_region = Button::new("Toggle Input Region")
            .on_click(|ctx, data: &mut bool, _: &Env| {
                *data = !*data;
                tracing::debug!("Setting input region toggle to: {}", *data);
                ctx.request_layout();
            })
            .lens(AppState::limit_input_region);
        let toggle_titlebar = Button::new("Toggle TitleBar")
            .on_click(|ctx, data: &mut bool, _: &Env| {
                *data = !*data;
                tracing::debug!("Setting titlebar visibility to: {}", *data);
                ctx.window().show_titlebar(*data);
                ctx.request_layout();
            })
            .lens(AppState::show_titlebar);
        let toggle_always_on_top = Button::new("Toggle Always On Top")
            .on_click(|ctx, data: &mut bool, _: &Env| {
                *data = !*data;
                tracing::debug!("Setting always on top to: {}", *data);
                ctx.window().set_always_on_top(*data);
            })
            .lens(AppState::always_on_top);
        let controls_flex = Flex::row()
            .with_child(toggle_input_region)
            .with_child(toggle_titlebar)
            .with_child(toggle_always_on_top);
        Self {
            info_label: WidgetPod::new(info_label),
            controls: WidgetPod::new(controls_flex),
        }
    }
examples/layout.rs (line 67)
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
fn build_app() -> impl Widget<u32> {
    // Usually we put all the widgets in one big tree using builder-style
    // methods. Sometimes we split them up in declarations to increase
    // readability. In this case we also have some recurring elements,
    // we add those in a loop later on.
    let mut col = Flex::column().with_child(
        // The `Flex`'s first child is another Flex! In this case it is
        // a row.
        Flex::row()
            // The row has its own children.
            .with_child(
                Label::new("One")
                    .fix_width(60.0)
                    .background(Color::rgb8(0x77, 0x77, 0))
                    .border(Color::WHITE, 3.0)
                    .center(),
            )
            // Spacing element that will fill all available space in
            // between label and a button. Notice that weight is non-zero.
            // We could have achieved a similar result with expanding the
            // width and setting the main-axis-allignment to SpaceBetween.
            .with_flex_spacer(1.0)
            .with_child(Button::new("Two").padding(20.))
            // After we added all the children, we can set some more
            // values using builder-style methods. Since these methods
            // dont return the original `Flex` but a SizedBox and Container
            // respectively, we have to put these at the end.
            .fix_height(100.0)
            //turquoise
            .background(Color::rgb8(0, 0x77, 0x88)),
    );

    for i in 0..5 {
        // Give a larger weight to one of the buttons for it to
        // occupy more space.
        let weight = if i == 2 { 3.0 } else { 1.0 };
        // call `expand_height` to force the buttons to use all their provided flex
        col.add_flex_child(Button::new(format!("Button #{i}")).expand_height(), weight);
    }

    // aspect ratio box
    let aspect_ratio_label = Label::new("This is an aspect-ratio box. Notice how the text will overflow if the box becomes too small.")
        .with_text_color(Color::BLACK)
        .with_line_break_mode(LineBreaking::WordWrap)
        .center();
    let aspect_ratio_box = AspectRatioBox::new(aspect_ratio_label, 4.0)
        .border(Color::BLACK, 1.0)
        .background(Color::WHITE);
    col.add_flex_child(aspect_ratio_box.center(), 1.0);

    // This method asks Druid to draw colored rectangles around our widgets,
    // so we can visually inspect their layout rectangles.
    col.debug_paint_layout()
}
source

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

Builder-style method to set the TextAlignment.

source

pub fn draw_at(&self, ctx: &mut PaintCtx<'_, '_, '_>, origin: impl Into<Point>)

Draw this label’s text at the provided Point, without internal padding.

This is a convenience for widgets that want to use Label as a way of managing a dynamic or localized string, but want finer control over where the text is drawn.

Methods from Deref<Target = RawLabel<ArcStr>>§

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 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>.

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

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.

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

source

pub fn set_line_break_mode(&mut self, mode: LineBreaking)

Set the LineBreaking behaviour.

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

Examples found in repository?
examples/text.rs (line 72)
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
    fn update(
        &mut self,
        child: &mut RawLabel<AppState>,
        ctx: &mut UpdateCtx,
        old_data: &AppState,
        data: &AppState,
        env: &Env,
    ) {
        if old_data.line_break_mode != data.line_break_mode {
            child.set_line_break_mode(data.line_break_mode);
            ctx.request_layout();
        }
        if old_data.alignment != data.alignment {
            child.set_text_alignment(data.alignment);
            ctx.request_layout();
        }
        child.update(ctx, old_data, data, env);
    }
source

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

Set the TextAlignment for this layout.

Examples found in repository?
examples/text.rs (line 76)
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
    fn update(
        &mut self,
        child: &mut RawLabel<AppState>,
        ctx: &mut UpdateCtx,
        old_data: &AppState,
        data: &AppState,
        env: &Env,
    ) {
        if old_data.line_break_mode != data.line_break_mode {
            child.set_line_break_mode(data.line_break_mode);
            ctx.request_layout();
        }
        if old_data.alignment != data.alignment {
            child.set_text_alignment(data.alignment);
            ctx.request_layout();
        }
        child.update(ctx, old_data, data, env);
    }
source

pub fn draw_at(&self, ctx: &mut PaintCtx<'_, '_, '_>, origin: impl Into<Point>)

Draw this label’s text at the provided Point, without internal padding.

This is a convenience for widgets that want to use Label as a way of managing a dynamic or localized string, but want finer control over where the text is drawn.

source

pub fn baseline_offset(&self) -> f64

Return the offset of the first baseline relative to the bottom of the widget.

Trait Implementations§

source§

impl<T> Deref for Label<T>

§

type Target = RawLabel<Arc<str>>

The resulting type after dereferencing.
source§

fn deref(&self) -> &Self::Target

Dereferences the value.
source§

impl<T> DerefMut for Label<T>

source§

fn deref_mut(&mut self) -> &mut Self::Target

Mutably dereferences the value.
source§

impl<T: Data> Widget<T> for Label<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_data: &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> !RefUnwindSafe for Label<T>

§

impl<T> !Send for Label<T>

§

impl<T> !Sync for Label<T>

§

impl<T> Unpin for Label<T>

§

impl<T> !UnwindSafe for Label<T>

Blanket Implementations§

source§

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

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

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

const: unstable · source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

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

const: unstable · source§

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

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

const: unstable · 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 Twhere U: From<T>,

const: unstable · 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.

§

impl<T> RoundFrom<T> for T

§

fn round_from(x: T) -> T

Performs the conversion.
§

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

§

fn round_into(self) -> U

Performs the conversion.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

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

source§

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

source§

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

§

type Error = Infallible

The type returned in the event of a conversion error.
const: unstable · source§

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

Performs the conversion.
source§

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

§

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

The type returned in the event of a conversion error.
const: unstable · source§

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

Performs the conversion.
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