Skip to content

Commit

Permalink
feat(core): 🎸 Added TextStyleWidget
Browse files Browse the repository at this point in the history
  • Loading branch information
M-Adoo committed Oct 3, 2024
1 parent f6661e2 commit ff26638
Show file tree
Hide file tree
Showing 42 changed files with 465 additions and 427 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ jobs:
- name: compile to wasm
run: cargo build --workspace --target wasm32-unknown-unknown --exclude ribir_dev_helper
wasm-test:
needs: lint
name: wasm test
runs-on: ubuntu-latest
steps:
Expand Down
11 changes: 9 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,19 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he

## [@Unreleased] - @ReleaseDate

### Features

- **core**: Added the built-in widget `TextStyleWidgetWidget`, allowing any widget to easily configure the text style within it using `text_style`. (#635, @M-Adoo)

### Breaking

- **text**: Removed the `ribir_text` crate and integrated it into the `ribir_painter` crate. (#635 @M-Adoo)

## [0.4.0-alpha.11] - 2024-10-02

### Features

- **core**: Added the `PaintingStyle` built-in widget, enabling any widget to utilize `painting_style` to specify how shapes and paths should be painted within its descendants. (#633 @M-Adoo)
- **core**: Added the `PaintingStyleWidget` built-in widget, enabling any widget to utilize `painting_style` to specify how shapes and paths should be painted within its descendants. (#633 @M-Adoo)

### Changed

Expand All @@ -38,7 +46,6 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he
### Breaking

- **text**: Enhance the typography APIs by eliminating `FontSize`, `Pixel`, and `Em`, and directly utilize only logical pixels represented by `f32`. (#629 @M-Adoo)
- **text**: Removed the `ribir_text` crate and integrated it into the `ribir_painter` crate. (#pr @M-Adoo)

## [0.4.0-alpha.10] - 2024-09-25

Expand Down
1 change: 0 additions & 1 deletion changelog.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ module.exports = {
"painter",
"macros",
"gpu",
"text",
"algo",
"widgets",
"ribir",
Expand Down
22 changes: 22 additions & 0 deletions core/src/builtin_widgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ mod class;
pub use class::*;
mod constrained_box;
pub use constrained_box::*;
mod text_style;
pub use text_style::*;

use crate::prelude::*;

Expand Down Expand Up @@ -125,6 +127,7 @@ pub struct FatObj<T> {
opacity: Option<State<Opacity>>,
class: Option<State<Class>>,
painting_style: Option<State<PaintingStyleWidget>>,
text_style: Option<State<TextStyleWidget>>,
keep_alive: Option<State<KeepAlive>>,
keep_alive_unsubscribe_handle: Option<Box<dyn Any>>,
}
Expand Down Expand Up @@ -188,6 +191,7 @@ impl<T> FatObj<T> {
global_anchor: self.global_anchor,
class: self.class,
painting_style: self.painting_style,
text_style: self.text_style,
visibility: self.visibility,
opacity: self.opacity,
keep_alive: self.keep_alive,
Expand All @@ -203,6 +207,7 @@ impl<T> FatObj<T> {
&& self.request_focus.is_none()
&& self.fitted_box.is_none()
&& self.box_decoration.is_none()
&& self.foreground.is_none()
&& self.padding.is_none()
&& self.layout_box.is_none()
&& self.cursor.is_none()
Expand All @@ -213,6 +218,9 @@ impl<T> FatObj<T> {
&& self.v_align.is_none()
&& self.relative_anchor.is_none()
&& self.global_anchor.is_none()
&& self.class.is_none()
&& self.painting_style.is_none()
&& self.text_style.is_none()
&& self.visibility.is_none()
&& self.opacity.is_none()
&& self.keep_alive.is_none()
Expand Down Expand Up @@ -405,6 +413,14 @@ impl<T> FatObj<T> {
.get_or_insert_with(|| State::value(<_>::default()))
}

/// Returns the `State<TextStyleWidget>` widget from the FatObj. If it
/// doesn't exist, a new one will be created.
pub fn get_text_style_widget(&mut self) -> &State<TextStyleWidget> {
self
.text_style
.get_or_insert_with(|| State::value(<_>::default()))
}

/// Returns the `State<Visibility>` widget from the FatObj. If it doesn't
/// exist, a new one will be created.
pub fn get_visibility_widget(&mut self) -> &State<Visibility> {
Expand Down Expand Up @@ -755,6 +771,11 @@ impl<T> FatObj<T> {
self.declare_builtin_init(v, Self::get_painting_style_widget, |m, v| m.painting_style = v)
}

/// Initializes the text style of this widget.
pub fn text_style<const M: u8>(self, v: impl DeclareInto<TextStyle, M>) -> Self {
self.declare_builtin_init(v, Self::get_text_style_widget, |m, v| m.text_style = v)
}

/// Initializes the background of the widget.
pub fn background<const M: u8>(self, v: impl DeclareInto<Option<Brush>, M>) -> Self {
self.declare_builtin_init(v, Self::get_box_decoration_widget, |m, v| m.background = v)
Expand Down Expand Up @@ -925,6 +946,7 @@ impl<'a> FatObj<Widget<'a>> {
relative_anchor,
global_anchor,
painting_style,
text_style,
keep_alive
]
);
Expand Down
46 changes: 46 additions & 0 deletions core/src/builtin_widgets/text_style.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use crate::{prelude::*, wrap_render::WrapRender};

/// This widget establishes the text style for painting the text within its
/// descendants.
#[derive(Default)]
pub struct TextStyleWidget {
pub text_style: TextStyle,
}

impl Declare for TextStyleWidget {
type Builder = FatObj<()>;
#[inline]
fn declarer() -> Self::Builder { FatObj::new(()) }
}

impl<'c> ComposeChild<'c> for TextStyleWidget {
type Child = Widget<'c>;

fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> Widget<'c> {
// We need to provide the text style for the children to access.
match this.try_into_value() {
Ok(this) => {
let style = this.text_style.clone();
WrapRender::combine_child(State::value(this), child).attach_data(Box::new(Queryable(style)))
}
Err(this) => {
let style = this.map_reader(|w| PartData::from_ref(&w.text_style));
WrapRender::combine_child(this, child).attach_data(Box::new(style))
}
}
}
}

impl WrapRender for TextStyleWidget {
fn perform_layout(&self, clamp: BoxClamp, host: &dyn Render, ctx: &mut LayoutCtx) -> Size {
host.perform_layout(clamp, ctx)
}

fn paint(&self, host: &dyn Render, ctx: &mut PaintingCtx) {
ctx
.painter()
.set_text_style(self.text_style.clone());

host.paint(ctx)
}
}
62 changes: 32 additions & 30 deletions core/src/builtin_widgets/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ impl<T: StateWriter<Value = Theme>> Query for ThemeQuerier<T> {
Some(&v.palette)
} else if TypeId::of::<TypographyTheme>() == type_id {
Some(&v.typography_theme)
} else if TypeId::of::<TextStyle>() == type_id {
Some(&v.typography_theme.body_medium.text)
} else if TypeId::of::<Classes>() == type_id {
Some(&v.classes)
} else if TypeId::of::<IconTheme>() == type_id {
Expand Down Expand Up @@ -279,153 +281,153 @@ fn typography_theme(

TypographyTheme {
display_large: TextTheme {
text: CowArc::owned(TextStyle {
text: TextStyle {
line_height: 64.,
font_size: 57.,
letter_space: 0.,
font_face: regular_face.clone(),
overflow: Overflow::Clip,
}),
},
decoration: decoration.clone(),
},
display_medium: TextTheme {
text: CowArc::owned(TextStyle {
text: TextStyle {
line_height: 52.,
font_size: 45.,
letter_space: 0.,
font_face: regular_face.clone(),
overflow: Overflow::Clip,
}),
},
decoration: decoration.clone(),
},
display_small: TextTheme {
text: CowArc::owned(TextStyle {
text: TextStyle {
line_height: 44.,
font_size: 36.,
letter_space: 0.0,
font_face: regular_face.clone(),
overflow: Overflow::Clip,
}),
},
decoration: decoration.clone(),
},
headline_large: TextTheme {
text: CowArc::owned(TextStyle {
text: TextStyle {
line_height: 40.,
font_size: 32.,
letter_space: 0.0,
font_face: regular_face.clone(),
overflow: Overflow::Clip,
}),
},
decoration: decoration.clone(),
},
headline_medium: TextTheme {
text: CowArc::owned(TextStyle {
text: TextStyle {
line_height: 36.,
font_size: 28.,
letter_space: 0.,
font_face: regular_face.clone(),
overflow: Overflow::Clip,
}),
},
decoration: decoration.clone(),
},
headline_small: TextTheme {
text: CowArc::owned(TextStyle {
text: TextStyle {
line_height: 32.,
font_size: 24.,
letter_space: 0.0,
font_face: regular_face.clone(),
overflow: Overflow::Clip,
}),
},
decoration: decoration.clone(),
},
title_large: TextTheme {
text: CowArc::owned(TextStyle {
text: TextStyle {
line_height: 28.,
font_size: 22.,
letter_space: 0.0,
font_face: medium_face.clone(),
overflow: Overflow::Clip,
}),
},
decoration: decoration.clone(),
},
title_medium: TextTheme {
text: CowArc::owned(TextStyle {
text: TextStyle {
line_height: 24.,
font_size: 16.,
letter_space: 0.15,
font_face: medium_face.clone(),
overflow: Overflow::Clip,
}),
},
decoration: decoration.clone(),
},
title_small: TextTheme {
text: CowArc::owned(TextStyle {
text: TextStyle {
line_height: 20.,
font_size: 14.,
letter_space: 0.1,
font_face: medium_face.clone(),
overflow: Overflow::Clip,
}),
},
decoration: decoration.clone(),
},
label_large: TextTheme {
text: CowArc::owned(TextStyle {
text: TextStyle {
line_height: 20.0,
font_size: 14.0,
letter_space: 0.1,
font_face: medium_face.clone(),
overflow: Overflow::Clip,
}),
},
decoration: decoration.clone(),
},
label_medium: TextTheme {
text: CowArc::owned(TextStyle {
text: TextStyle {
line_height: 16.,
font_size: 12.,
letter_space: 0.5,
font_face: medium_face.clone(),
overflow: Overflow::Clip,
}),
},
decoration: decoration.clone(),
},
label_small: TextTheme {
text: CowArc::owned(TextStyle {
text: TextStyle {
line_height: 16.0,
font_size: 11.,
letter_space: 0.5,
font_face: medium_face,
overflow: Overflow::Clip,
}),
},
decoration: decoration.clone(),
},
body_large: TextTheme {
text: CowArc::owned(TextStyle {
text: TextStyle {
line_height: 24.0,
font_size: 16.0,
letter_space: 0.5,
font_face: regular_face.clone(),
overflow: Overflow::Clip,
}),
},
decoration: decoration.clone(),
},
body_medium: TextTheme {
text: CowArc::owned(TextStyle {
text: TextStyle {
line_height: 20.0,
font_size: 14.,
letter_space: 0.25,
font_face: regular_face.clone(),
overflow: Overflow::Clip,
}),
},
decoration: decoration.clone(),
},
body_small: TextTheme {
text: CowArc::owned(TextStyle {
text: TextStyle {
line_height: 16.,
font_size: 12.,
letter_space: 0.4,
font_face: regular_face,
overflow: Overflow::Clip,
}),
},
decoration,
},
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/builtin_widgets/theme/typography_theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub struct TypographyTheme {

#[derive(Clone, Debug, PartialEq)]
pub struct TextTheme {
pub text: CowArc<ribir_painter::TextStyle>,
pub text: ribir_painter::TextStyle,
pub decoration: TextDecorationStyle,
}

Expand Down
4 changes: 2 additions & 2 deletions core/src/context/build_ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ pub struct BuildCtx {
/// A node ID has already been allocated for the current building node.
pub(crate) pre_alloc: Option<WidgetId>,
pub(crate) tree: NonNull<WidgetTree>,
// Todo: Since `Theme`, `Palette`, and `TypographyTheme` are frequently queried during the
// building process, we should cache the closest one.
// Todo: Since `Theme`, `Palette`, `TypographyTheme` and `TextStyle` are frequently queried
// during the building process, layout and paint. we should cache the closest one.
}

/// A handle of `BuildCtx` that you can store it and access the `BuildCtx` later
Expand Down
1 change: 0 additions & 1 deletion core/src/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,4 +340,3 @@ impl<F: FnMut(&mut BuildCtx) -> Widget<'static> + 'static> From<F> for GenWidget
#[inline]
fn from(f: F) -> Self { Self::new(f) }
}

Loading

0 comments on commit ff26638

Please sign in to comment.