Skip to content

Commit b594779

Browse files
committed
Label + Button layout/alignment fixes
1 parent 33447db commit b594779

File tree

5 files changed

+40
-53
lines changed

5 files changed

+40
-53
lines changed

src/dialog.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ enum MessageLevel {
128128
Info,
129129
}
130130

131-
/// The behavior of a button in a [`Dialog`].
131+
/// The behavior of a button in a dialog.
132132
pub trait ButtonBehavior: Send + 'static {
133133
/// Invokes the behavior. Returns whether the dialog containing this button
134134
/// should close or remain open.

src/widgets/button.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ use crate::styles::components::{
1717
AutoFocusableControls, CornerRadius, DefaultActiveBackgroundColor,
1818
DefaultActiveForegroundColor, DefaultBackgroundColor, DefaultDisabledBackgroundColor,
1919
DefaultDisabledForegroundColor, DefaultForegroundColor, DefaultHoveredBackgroundColor,
20-
DefaultHoveredForegroundColor, Easing, HighlightColor, IntrinsicPadding, OpaqueWidgetColor,
21-
OutlineColor, OutlineWidth, SurfaceColor, TextColor,
20+
DefaultHoveredForegroundColor, Easing, HighlightColor, HorizontalAlignment, IntrinsicPadding,
21+
OpaqueWidgetColor, OutlineColor, OutlineWidth, SurfaceColor, TextColor,
2222
};
23-
use crate::styles::{ColorExt, Styles};
23+
use crate::styles::{ColorExt, HorizontalAlign, Styles};
2424
use crate::widget::{
2525
EventHandling, MakeWidget, Notify, SharedCallback, Widget, WidgetLayout, WidgetRef, HANDLED,
2626
};
@@ -38,6 +38,7 @@ pub struct Button {
3838
pub kind: Value<ButtonKind>,
3939
focusable: bool,
4040
per_window: WindowLocal<PerWindow>,
41+
label_align: Dynamic<HorizontalAlign>,
4142
}
4243

4344
#[derive(Debug, Default)]
@@ -139,12 +140,14 @@ pub struct ButtonColors {
139140
impl Button {
140141
/// Returns a new button with the provided label.
141142
pub fn new(content: impl MakeWidget) -> Self {
143+
let label_align = Dynamic::<HorizontalAlign>::default();
142144
Self {
143-
content: content.into_ref(),
145+
content: content.with(&HorizontalAlignment, &label_align).into_ref(),
144146
on_click: None,
145147
per_window: WindowLocal::default(),
146148
kind: Value::Constant(ButtonKind::default()),
147149
focusable: true,
150+
label_align,
148151
}
149152
}
150153

@@ -527,12 +530,19 @@ impl Widget for Button {
527530
let double_padding = padding * 2;
528531
let mounted = self.content.mounted(context);
529532
let available_space = available_space.map(|space| space - double_padding);
533+
let align = context.get(&ButtonLabelAlignment);
534+
self.label_align.set(align);
530535
let layout = context.for_other(&mounted).layout(available_space);
531536
let size = available_space.fit_measured(layout.size);
532-
context.set_child_layout(
533-
&mounted,
534-
Rect::new(Point::squared(padding), size).into_signed(),
537+
let mut position = Rect::new(Point::squared(padding), size).into_signed();
538+
position.origin.x += align.alignment_offset(
539+
layout.size.width.into_signed().min(position.size.width),
540+
available_space
541+
.width
542+
.fill_or_fit(position.size.width)
543+
.into_signed(),
535544
);
545+
context.set_child_layout(&mounted, position);
536546
WidgetLayout {
537547
size: size + double_padding,
538548
baseline: layout.baseline.map(|baseline| baseline + padding),
@@ -616,6 +626,8 @@ define_components! {
616626
/// The outline color of the button when the mouse cursor is hovering over
617627
/// it.
618628
ButtonDisabledOutline(Color, "disabled_outline_color", Color::CLEAR_BLACK)
629+
/// The horizontal alignment to apply to the label widget of the button.
630+
ButtonLabelAlignment(HorizontalAlign, "align", HorizontalAlign::Center)
619631
}
620632
}
621633

src/widgets/grid.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ pub(crate) struct GridLayout {
275275
fit_to_content: Vec<LotId>,
276276
premeasured: Vec<LotId>,
277277
measured_scale: Fraction,
278-
pub row_baselines: Vec<Baseline>,
278+
pub row_baselines: Vec<BaselineInfo>,
279279
pub orientation: Orientation,
280280
}
281281

@@ -285,6 +285,15 @@ pub(crate) struct BaselineInfo {
285285
pub height: UPx,
286286
}
287287

288+
impl BaselineInfo {
289+
fn max(self, other: Self) -> Self {
290+
Self {
291+
baseline: self.baseline.max(other.baseline),
292+
height: self.height.max(other.height),
293+
}
294+
}
295+
}
296+
288297
impl From<&WidgetLayout> for BaselineInfo {
289298
fn from(layout: &WidgetLayout) -> Self {
290299
Self {
@@ -575,7 +584,7 @@ impl GridLayout {
575584

576585
WidgetLayout {
577586
size: self.orientation.make_size(measured, total_other),
578-
baseline: self.row_baselines[0],
587+
baseline: self.row_baselines[0].baseline,
579588
}
580589
}
581590

@@ -647,17 +656,17 @@ impl GridLayout {
647656
.extend((0..self.elements_per_child).map(|row| {
648657
self.layouts
649658
.iter()
650-
.fold(Baseline::NONE, |max_baseline, layout| {
651-
max_baseline.max(layout.baselines[row].baseline)
659+
.fold(BaselineInfo::NONE, |max_baseline, layout| {
660+
max_baseline.max(layout.baselines[row])
652661
})
653662
}));
654663
} else {
655664
self.row_baselines.extend(self.layouts.iter().map(|layout| {
656665
layout
657666
.baselines
658667
.iter()
659-
.fold(Baseline::NONE, |max_baseline, info| {
660-
max_baseline.max(info.baseline)
668+
.fold(BaselineInfo::NONE, |max_baseline, info| {
669+
max_baseline.max(*info)
661670
})
662671
}));
663672
};
@@ -685,17 +694,17 @@ impl GridLayout {
685694
match vertical_alignment {
686695
VerticalAlign::Top => {}
687696
VerticalAlign::Baseline => {
688-
let row_baseline = if self.orientation == Orientation::Column {
697+
let row_info = if self.orientation == Orientation::Column {
689698
self.row_baselines[row_index]
690699
} else {
691700
self.row_baselines[cell_index]
692701
};
693702

694703
if let (Some(cell_baseline), Some(row_baseline)) =
695-
(cell_info.baseline.0, *row_baseline)
704+
(cell_info.baseline.0, *row_info.baseline)
696705
{
697706
let alignment_needed = row_baseline - cell_baseline;
698-
let available_space = other_size - cell_info.height;
707+
let available_space = row_info.height - cell_info.height;
699708
let adjustment = alignment_needed.min(available_space);
700709
position.origin.y += adjustment.into_signed();
701710
}

src/widgets/label.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::styles::components::{HorizontalAlignment, TextColor, VerticalAlignmen
1717
use crate::styles::{HorizontalAlign, VerticalAlign};
1818
use crate::widget::{MakeWidgetWithTag, Widget, WidgetInstance, WidgetLayout, WidgetTag};
1919
use crate::window::WindowLocal;
20-
use crate::{ConstraintLimit, FitMeasuredSize};
20+
use crate::ConstraintLimit;
2121

2222
/// A read-only text widget.
2323
#[derive(Debug)]
@@ -154,13 +154,8 @@ where
154154
let width = available_space.width.max().try_into().unwrap_or(Px::MAX);
155155
let prepared = self.prepared_text(context, color, width, align);
156156

157-
// TODO if vertical alignment isn't top and we are using Fill on the
158-
// height constraint limit, we should calculate the actual baseline. On
159-
// that topic, if the text is wrapped, is the baseline of bottom-aligned
160-
// text the bottom line's baseline or the top line's baseline? Probably
161-
// bottom...
162157
WidgetLayout {
163-
size: available_space.fit_measured(prepared.size.into_unsigned().ceil()),
158+
size: prepared.size.into_unsigned().ceil(),
164159
baseline: prepared.line_height.into(),
165160
}
166161
}

src/widgets/stack.rs

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -189,35 +189,6 @@ impl Widget for Stack {
189189
0,
190190
cell_align,
191191
);
192-
// let mut position = Rect::new(
193-
// self.layout
194-
// .orientation
195-
// .make_point(layout.offset, )
196-
// .into_signed(),
197-
// self.layout
198-
// .orientation
199-
// .make_size(layout.size, )
200-
// .into_signed(),
201-
// );
202-
203-
// let cell_info = layout.baselines[0];
204-
205-
// let (row_baseline, row_after_baseline) =
206-
// if self.layout.orientation == Orientation::Column {
207-
// self.layout.row_baselines[0]
208-
// } else {
209-
// self.layout.row_baselines[index]
210-
// };
211-
212-
// if let (Some(cell_baseline), Some(row_baseline)) =
213-
// (cell_info.baseline.0, row_baseline.0)
214-
// {
215-
// let alignment_needed = row_baseline - cell_baseline;
216-
// let row_height = row_baseline + row_after_baseline.expect("has baseline");
217-
// let available_space = row_height - cell_info.height;
218-
// let adjustment = alignment_needed.min(available_space);
219-
// position.origin.y += adjustment.into_signed();
220-
// }
221192

222193
context.set_child_layout(child, position);
223194
}

0 commit comments

Comments
 (0)