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>
impl<T: TextStorage> Label<T>
source§impl<T: Data> Label<T>
impl<T: Data> Label<T>
sourcepub fn new(text: impl Into<LabelText<T>>) -> Self
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?
More examples
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)
}
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,
)
}
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)
}
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)
}
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/lens.rs
- examples/blocking_function.rs
- examples/multiwin.rs
- examples/event_viewer.rs
- examples/switches.rs
- examples/text.rs
- examples/input_region.rs
- examples/transparency.rs
- examples/split_demo.rs
- examples/panels.rs
- examples/flex.rs
- examples/view_switcher.rs
- examples/layout.rs
- examples/game_of_life.rs
- examples/styled_text.rs
- examples/list.rs
- examples/sub_window.rs
sourcepub fn dynamic(text: impl Fn(&T, &Env) -> String + 'static) -> Self
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?
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
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))
}
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)
}
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)
}
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)
}
sourcepub fn set_text(&mut self, text: impl Into<LabelText<T>>)
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.
sourcepub fn with_text_color(self, color: impl Into<KeyOrValue<Color>>) -> Self
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?
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
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()
}
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()
}
sourcepub fn with_text_size(self, size: impl Into<KeyOrValue<f64>>) -> Self
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?
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
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)
}
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)
}
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()
}
}
sourcepub fn with_font(self, font: impl Into<KeyOrValue<FontDescriptor>>) -> Self
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?
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()
}
sourcepub fn with_line_break_mode(self, mode: LineBreaking) -> Self
pub fn with_line_break_mode(self, mode: LineBreaking) -> Self
Builder-style method to set the LineBreaking
behaviour.
Examples found in repository?
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
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),
}
}
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()
}
sourcepub fn with_text_alignment(self, alignment: TextAlignment) -> Self
pub fn with_text_alignment(self, alignment: TextAlignment) -> Self
Builder-style method to set the TextAlignment
.
sourcepub fn draw_at(&self, ctx: &mut PaintCtx<'_, '_, '_>, origin: impl Into<Point>)
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>>§
sourcepub fn set_text_color(&mut self, color: impl Into<KeyOrValue<Color>>)
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.
sourcepub fn set_text_size(&mut self, size: impl Into<KeyOrValue<f64>>)
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.
sourcepub fn set_font(&mut self, font: impl Into<KeyOrValue<FontDescriptor>>)
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.
sourcepub fn set_line_break_mode(&mut self, mode: LineBreaking)
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?
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);
}
sourcepub fn set_text_alignment(&mut self, alignment: TextAlignment)
pub fn set_text_alignment(&mut self, alignment: TextAlignment)
Set the TextAlignment
for this layout.
Examples found in repository?
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);
}
sourcepub fn draw_at(&self, ctx: &mut PaintCtx<'_, '_, '_>, origin: impl Into<Point>)
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.
sourcepub fn baseline_offset(&self) -> f64
pub fn baseline_offset(&self) -> f64
Return the offset of the first baseline relative to the bottom of the widget.