From 1d02abf528a3ef44835d21ac0c579d9f40c4163e Mon Sep 17 00:00:00 2001 From: Colin Rofls Date: Wed, 9 Sep 2020 11:28:42 -0400 Subject: [PATCH] Add TextAlignment support to TextLayout and Label This also updates the 'text' example to demonstrate this feature. --- CHANGELOG.md | 2 ++ druid/examples/text.rs | 30 ++++++++++++++++++++++++++---- druid/src/data.rs | 6 ++++++ druid/src/lib.rs | 2 +- druid/src/text/layout.rs | 13 ++++++++++++- druid/src/widget/label.rs | 19 ++++++++++++++++++- 6 files changed, 65 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c50d4cdb1..00c7ed2c52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ You can find its changes [documented below](#060---2020-06-01). - `TextLayout` type simplifies drawing text ([#1182] by [@cmyr]) - Implementation of `Data` trait for `i128` and `u128` primitive data types. ([#1214] by [@koutoftimer]) - `LineBreaking` enum allows configuration of label line-breaking ([#1195] by [@cmyr]) +- `TextAlignment` support in `TextLayout` and `Label` ([#1210] by [@cmyr])` ### Changed @@ -442,6 +443,7 @@ Last release without a changelog :( [#1195]: https://github.com/linebender/druid/pull/1195 [#1204]: https://github.com/linebender/druid/pull/1204 [#1205]: https://github.com/linebender/druid/pull/1205 +[#1210]: https://github.com/linebender/druid/pull/1210 [#1214]: https://github.com/linebender/druid/pull/1214 [Unreleased]: https://github.com/linebender/druid/compare/v0.6.0...master diff --git a/druid/examples/text.rs b/druid/examples/text.rs index 46d051f757..a11548325e 100644 --- a/druid/examples/text.rs +++ b/druid/examples/text.rs @@ -16,7 +16,8 @@ use druid::widget::{Controller, Flex, Label, LineBreaking, RadioGroup, Scroll}; use druid::{ - AppLauncher, Color, Data, Env, Lens, LocalizedString, UpdateCtx, Widget, WidgetExt, WindowDesc, + AppLauncher, Color, Data, Env, Lens, LocalizedString, TextAlignment, UpdateCtx, Widget, + WidgetExt, WindowDesc, }; const WINDOW_TITLE: LocalizedString = LocalizedString::new("Text Options"); @@ -28,8 +29,8 @@ const SPACER_SIZE: f64 = 8.0; #[derive(Clone, Data, Lens)] struct AppState { - /// the width at which to wrap lines. line_break_mode: LineBreaking, + alignment: TextAlignment, } /// A controller that sets properties on a label. @@ -49,6 +50,9 @@ impl Controller> for LabelController { child.set_line_break_mode(data.line_break_mode); ctx.request_layout(); } + if old_data.alignment != data.alignment { + child.set_text_alignment(data.alignment); + } child.update(ctx, old_data, data, env); } } @@ -62,6 +66,7 @@ pub fn main() { // create the initial app state let initial_state = AppState { line_break_mode: LineBreaking::Clip, + alignment: Default::default(), }; // start the application @@ -93,9 +98,26 @@ fn build_root_widget() -> impl Widget { ])) .lens(AppState::line_break_mode); - Flex::column() + let alignment_picker = Flex::column() + .with_child(Label::new("Justification")) .with_spacer(SPACER_SIZE) - .with_child(line_break_chooser) + .with_child(RadioGroup::new(vec![ + ("Start", TextAlignment::Start), + ("End", TextAlignment::End), + ("Center", TextAlignment::Center), + ("Justified", TextAlignment::Justified), + ])) + .lens(AppState::alignment); + + let controls = Flex::row() + .cross_axis_alignment(druid::widget::CrossAxisAlignment::Start) + .with_child(alignment_picker) .with_spacer(SPACER_SIZE) + .with_child(line_break_chooser) + .padding(SPACER_SIZE); + + Flex::column() + .cross_axis_alignment(druid::widget::CrossAxisAlignment::Start) + .with_child(controls) .with_flex_child(label, 1.0) } diff --git a/druid/src/data.rs b/druid/src/data.rs index 912b39d3d0..be1a8fda22 100644 --- a/druid/src/data.rs +++ b/druid/src/data.rs @@ -415,6 +415,12 @@ impl Data for piet::FontStyle { } } +impl Data for piet::TextAlignment { + fn same(&self, other: &Self) -> bool { + self == other + } +} + #[cfg(feature = "im")] impl Data for im::Vector { fn same(&self, other: &Self) -> bool { diff --git a/druid/src/lib.rs b/druid/src/lib.rs index c9d4bb2006..f2e51908da 100644 --- a/druid/src/lib.rs +++ b/druid/src/lib.rs @@ -172,7 +172,7 @@ mod window; pub use kurbo::{Affine, Insets, Point, Rect, Size, Vec2}; pub use piet::{ Color, FontFamily, FontStyle, FontWeight, LinearGradient, RadialGradient, RenderContext, - UnitPoint, + TextAlignment, UnitPoint, }; // these are the types from shell that we expose; others we only use internally. pub use shell::keyboard_types; diff --git a/druid/src/text/layout.rs b/druid/src/text/layout.rs index abe2d5abb4..53d240e0f4 100644 --- a/druid/src/text/layout.rs +++ b/druid/src/text/layout.rs @@ -18,7 +18,7 @@ use std::ops::Range; use crate::kurbo::{Line, Point, Rect, Size}; use crate::piet::{ - Color, PietText, PietTextLayout, Text as _, TextAttribute, TextLayout as _, + Color, PietText, PietTextLayout, Text as _, TextAlignment, TextAttribute, TextLayout as _, TextLayoutBuilder as _, }; use crate::{ArcStr, Data, Env, FontDescriptor, KeyOrValue, PaintCtx, RenderContext}; @@ -55,6 +55,7 @@ pub struct TextLayout { // the underlying layout object. This is constructed lazily. layout: Option, wrap_width: f64, + alignment: TextAlignment, } impl TextLayout { @@ -75,6 +76,7 @@ impl TextLayout { cached_text_size: None, layout: None, wrap_width: f64::INFINITY, + alignment: Default::default(), } } @@ -136,6 +138,14 @@ impl TextLayout { } } + /// Set the [`TextAlignment`] for this layout. + /// + /// [`TextAlignment`]: enum.TextAlignment.html + pub fn set_text_alignment(&mut self, alignment: TextAlignment) { + self.alignment = alignment; + self.layout = None; + } + /// The size of the laid-out text. /// /// This is not meaningful until [`rebuild_if_needed`] has been called. @@ -239,6 +249,7 @@ impl TextLayout { factory .new_text_layout(self.text.clone()) .max_width(self.wrap_width) + .alignment(self.alignment) .font(descriptor.family.clone(), descriptor.size) .default_attribute(descriptor.weight) .default_attribute(descriptor.style) diff --git a/druid/src/widget/label.rs b/druid/src/widget/label.rs index 71cc8f996c..61c4bfbb58 100644 --- a/druid/src/widget/label.rs +++ b/druid/src/widget/label.rs @@ -17,7 +17,8 @@ use crate::piet::{Color, PietText}; use crate::widget::prelude::*; use crate::{ - BoxConstraints, Data, FontDescriptor, KeyOrValue, LocalizedString, Point, Size, TextLayout, + BoxConstraints, Data, FontDescriptor, KeyOrValue, LocalizedString, Point, Size, TextAlignment, + TextLayout, }; // added padding between the edges of the widget and the text. @@ -162,6 +163,14 @@ impl Label { self } + /// Builder-style method to set the [`TextAlignment`]. + /// + /// [`TextAlignment`]: enum.TextAlignment.html + pub fn with_text_alignment(mut self, alignment: TextAlignment) -> Self { + self.set_text_alignment(alignment); + self + } + /// Set the label's text. /// /// If you change this property, you are responsible for calling @@ -234,6 +243,14 @@ impl Label { self.line_break_mode = mode; } + /// Set the [`TextAlignment`] for this layout. + /// + /// [`TextAlignment`]: enum.TextAlignment.html + pub fn set_text_alignment(&mut self, alignment: TextAlignment) { + self.layout.set_text_alignment(alignment); + self.needs_rebuild = true; + } + fn rebuild_if_needed(&mut self, factory: &mut PietText, data: &T, env: &Env) { if self.needs_rebuild { self.text.resolve(data, env);