Skip to content

Commit

Permalink
feat(core): 🎸 added Foreground builtin widget
Browse files Browse the repository at this point in the history
  • Loading branch information
M-Adoo committed Sep 20, 2024
1 parent 6e9a232 commit 6fe4179
Show file tree
Hide file tree
Showing 16 changed files with 147 additions and 51 deletions.
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he
### Features

- **core**: Added `WrapRender` for a render widget that combines with its child as a single widget tree node. (#626 @M-Adoo)
- **core:: Added `StateWriter::into_render` to covert writer to reader if no other writer exist. (#626 @M-Adoo)
- **painter**: Distinguishes between fill and stroke brushes, allowing the painter to have two default brushes. (#pr, @M-Adoo)
- **core**: Added `StateWriter::into_render` to covert writer to reader if no other writer exist. (#626 @M-Adoo)
- **core**: Added the built-in widget `Foreground`, enabling any widget to directly utilize `foreground` for configuring the painter brush. (#628, @M-Adoo)
- **painter**: Distinguishes between fill and stroke brushes, allowing the painter to have two default brushes. (#628, @M-Adoo)

### Changed

Expand All @@ -43,7 +44,7 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he

### Breaking

- **painter**: Removed `Painter::get_brush` and `Painter::set_brush`, now using `get_fill_brush`, `get_stroke_brush`, `set_fill_brush`, and `set_stroke_brush` methods instead. (#pr @M-Adoo)
- **painter**: Removed `Painter::get_brush` and `Painter::set_brush`, now using `get_fill_brush`, `get_stroke_brush`, `set_fill_brush`, and `set_stroke_brush` methods instead. (#628 @M-Adoo)


## [0.4.0-alpha.9] - 2024-09-18
Expand Down
48 changes: 33 additions & 15 deletions core/src/builtin_widgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ pub use cursor::*;
pub use winit::window::CursorIcon;
mod margin;
pub use margin::*;
mod foreground;
mod padding;
pub use foreground::*;
pub use padding::*;
mod box_decoration;
pub use box_decoration::*;
Expand Down Expand Up @@ -106,6 +108,7 @@ pub struct FatObj<T> {
request_focus: Option<State<RequestFocus>>,
fitted_box: Option<State<FittedBox>>,
box_decoration: Option<State<BoxDecoration>>,
foreground: Option<State<Foreground>>,
padding: Option<State<Padding>>,
layout_box: Option<State<LayoutBox>>,
cursor: Option<State<Cursor>>,
Expand Down Expand Up @@ -169,6 +172,7 @@ impl<T> FatObj<T> {
request_focus: self.request_focus,
fitted_box: self.fitted_box,
box_decoration: self.box_decoration,
foreground: self.foreground,
padding: self.padding,
layout_box: self.layout_box,
cursor: self.cursor,
Expand Down Expand Up @@ -247,15 +251,15 @@ impl<T> FatObj<T> {
}

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

/// Return the `State<MixFlags>` from the `MixBuiltin`. If the `MixBuiltin`
/// does not exist in the `FatObj`, a new one is created.
/// does not exist in the `FatObj`, a new one will be created..
pub fn get_mix_flags_widget(&mut self) -> &State<MixFlags> {
self.get_mix_builtin_widget().mix_flags()
}
Expand All @@ -281,31 +285,39 @@ impl<T> FatObj<T> {
}

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

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

/// Returns the `State<Foreground>` widget from the FatObj. If it does not
/// exist, a new one will be created.
pub fn get_foreground_widget(&mut self) -> &State<Foreground> {
self
.foreground
.get_or_insert_with(|| State::value(<_>::default()))
}

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

/// Returns the `State<LayoutBox>` widget from the FatObj. If it doesn't
/// exist, a new one is created.
/// exist, a new one will be created.
pub fn get_layout_box_widget(&mut self) -> &State<LayoutBox> {
self
.layout_box
Expand Down Expand Up @@ -335,71 +347,71 @@ impl<T> FatObj<T> {
}

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

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

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

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

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

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

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

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

/// Returns the `State<KeepAlive>` widget from the FatObj. If it doesn't
/// exist, a new one is created.
/// exist, a new one will be created.
pub fn get_keep_alive_widget(&mut self) -> &State<KeepAlive> {
self
.keep_alive
Expand Down Expand Up @@ -732,6 +744,11 @@ impl<T> FatObj<T> {
self.declare_builtin_init(v, Self::get_box_decoration_widget, |m, v| m.background = v)
}

/// Initializes the foreground of the widget.
pub fn foreground<const M: u8>(self, v: impl DeclareInto<Brush, M>) -> Self {
self.declare_builtin_init(v, Self::get_foreground_widget, |m, v| m.foreground = v)
}

/// Initializes the border of the widget.
pub fn border<const M: u8>(self, v: impl DeclareInto<Option<Border>, M>) -> Self {
self.declare_builtin_init(v, Self::get_box_decoration_widget, |m, v| m.border = v)
Expand Down Expand Up @@ -876,6 +893,7 @@ impl<'a> FatObj<Widget<'a>> {
fitted_box,
constrained_box,
box_decoration,
foreground,
scrollable,
layout_box,
mix_builtin,
Expand Down
14 changes: 13 additions & 1 deletion core/src/builtin_widgets/box_decoration.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use crate::{prelude::*, wrap_render::WrapRender};

/// The BoxDecoration provides a variety of ways to draw a box.
/// The BoxDecoration provides configuration options to draw the background and
/// border of a box.
///
/// If a background color is specified, a derived foreground calculation from
/// the background will be applied to its children.
#[derive(Default, Clone)]
pub struct BoxDecoration {
/// The background of the box.
Expand Down Expand Up @@ -66,6 +70,14 @@ impl WrapRender for BoxDecoration {
painter.fill();
}
self.paint_border(painter, &rect);

if let Some(Brush::Color(ref background)) = self.background {
let foreground = Palette::of(&ctx).on_container_of(background);
ctx
.painter()
.set_fill_brush(foreground)
.set_stroke_brush(foreground);
}
host.paint(ctx)
}
}
Expand Down
38 changes: 38 additions & 0 deletions core/src/builtin_widgets/foreground.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use crate::{prelude::*, wrap_render::WrapRender};

/// A widget that sets the brush for foreground elements. It's can be inherited
/// by its descendants. When meet a color of `background`, the foreground will
/// be overwrite by it.

#[derive(Default)]
pub struct Foreground {
pub foreground: Brush,
}

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

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

fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> Widget<'c> {
WrapRender::combine_child(this, child)
}
}

impl WrapRender for Foreground {
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_fill_brush(self.foreground.clone())
.set_stroke_brush(self.foreground.clone());
host.paint(ctx)
}
}
6 changes: 6 additions & 0 deletions macros/src/declare_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,12 @@ pub(crate) fn declare_derive(input: &mut syn::DeriveInput) -> syn::Result<TokenS
self
}

#[doc="Initializes the foreground of the widget."]
#vis fn foreground<const _M: u8>(mut self, v: impl DeclareInto<Brush, _M>) -> Self {
self.fat_obj = self.fat_obj.foreground(v);
self
}

#[doc="Initializes the extra space within the widget."]
#vis fn padding<const _M: u8>(mut self, v: impl DeclareInto<EdgeInsets, _M>) -> Self
{
Expand Down
2 changes: 2 additions & 0 deletions macros/src/variable_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ pub static BUILTIN_INFOS: phf::Map<&'static str, BuiltinMember> = phf_map! {
"background" => builtin_member!{"BoxDecoration", Field, "box_decoration"},
"border" => builtin_member!{"BoxDecoration", Field, "box_decoration"},
"border_radius" => builtin_member!{"BoxDecoration", Field, "box_decoration"},
// Foreground
"foreground" => builtin_member! { "Foreground", Field, "foreground"},
// Padding
"padding" => builtin_member!{"Padding", Field, "padding"},
// LayoutBox
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 6 additions & 11 deletions text/src/text_render.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{cell::RefCell, rc::Rc};

use ribir_geom::{Rect, Size};
use ribir_painter::{Brush, Painter, Path, PathStyle};
use ribir_painter::{Painter, Path, PathStyle};

use crate::{font_db::FontDB, Em, FontFace, FontSize, GlyphBound, Pixel, VisualGlyphs};

Expand Down Expand Up @@ -34,7 +34,7 @@ impl Default for TextStyle {
/// draw the text glyphs within the box_rect, with the given brush font_size and
/// path style
pub fn draw_glyphs_in_rect(
painter: &mut Painter, visual_glyphs: VisualGlyphs, box_rect: Rect, brush: Brush, font_size: f32,
painter: &mut Painter, visual_glyphs: VisualGlyphs, box_rect: Rect, font_size: f32,
path_style: &PathStyle, font_db: Rc<RefCell<FontDB>>,
) {
let visual_rect = visual_glyphs.visual_rect();
Expand All @@ -48,7 +48,6 @@ pub fn draw_glyphs_in_rect(
draw_glyphs(
painter,
visual_glyphs.glyph_bounds_in_rect(&paint_rect),
brush,
font_size,
path_style,
font_db,
Expand All @@ -57,7 +56,7 @@ pub fn draw_glyphs_in_rect(

/// draw the glyphs with the given brush, font_size and path style
pub fn draw_glyphs(
painter: &mut Painter, glyphs: impl Iterator<Item = GlyphBound>, brush: Brush, font_size: f32,
painter: &mut Painter, glyphs: impl Iterator<Item = GlyphBound>, font_size: f32,
path_style: &PathStyle, font_db: Rc<RefCell<FontDB>>,
) {
glyphs.for_each(|g| {
Expand All @@ -67,19 +66,15 @@ pub fn draw_glyphs(
if let Some(face) = face {
let unit = face.units_per_em() as f32;
let scale = font_size / unit;
let mut painter = painter.save_guard();
if let Some(path) = face.outline_glyph(g.glyph_id, path_style) {
let mut painter = painter.save_guard();
painter
.translate(g.bound.min_x(), g.bound.min_y())
.scale(scale, -scale)
.translate(0., -unit);

painter
.set_fill_brush(brush.clone())
.fill_path(path.into());
painter.fill_path(path.into());
} else if let Some(svg) = face.glyph_svg_image(g.glyph_id) {
let mut painter = painter.save_guard();

let grid_scale = face
.vertical_height()
.map(|h| h as f32 / face.units_per_em() as f32)
Expand All @@ -100,7 +95,7 @@ pub fn draw_glyphs(

let x_offset = g.bound.min_x() + (g.bound.width() - (m_width * scale)) / 2.;
let y_offset = g.bound.min_y() + (g.bound.height() - (m_height * scale)) / 2.;
let mut painter = painter.save_guard();

painter
.translate(x_offset, y_offset)
.scale(scale, scale)
Expand Down
2 changes: 1 addition & 1 deletion themes/material/src/ripple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl<'c> ComposeChild<'c> for Ripple {
});

let mut ripple = @PathPaintKit {
brush: pipe!(StateRole::pressed().calc_color($this.color)),
foreground: pipe!(StateRole::pressed().calc_color($this.color)),
path: Path::circle(launch_at, radius),
};

Expand Down
2 changes: 1 addition & 1 deletion themes/material/src/state_layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl Compose for StateLayer {
fn_widget! {
@PathPaintKit {
path: pipe!($this.path.clone()),
brush: pipe!($this.role.calc_color($this.color)),
foreground: pipe!($this.role.calc_color($this.color)),
}
}
.into_widget()
Expand Down
Loading

0 comments on commit 6fe4179

Please sign in to comment.