Implemented `tile_origin` for gradients.

Fixed checkerboard.
This commit is contained in:
Samuel Guerra 2024-01-12 01:40:30 -03:00
parent 6cabab4d5a
commit 2ec2db72b3
10 changed files with 252 additions and 68 deletions

View File

@ -1653,6 +1653,7 @@ impl FrameBuilder {
line: PxLine,
stops: &[RenderGradientStop],
extend_mode: RenderExtendMode,
tile_origin: PxPoint,
tile_size: PxSize,
tile_spacing: PxSize,
) {
@ -1675,6 +1676,7 @@ impl FrameBuilder {
extend_mode,
},
stops,
tile_origin,
tile_size,
tile_spacing,
);
@ -1703,6 +1705,7 @@ impl FrameBuilder {
radius: PxSize,
stops: &[RenderGradientStop],
extend_mode: RenderExtendMode,
tile_origin: PxPoint,
tile_size: PxSize,
tile_spacing: PxSize,
) {
@ -1727,6 +1730,7 @@ impl FrameBuilder {
extend_mode,
},
stops,
tile_origin,
tile_size,
tile_spacing,
);
@ -1752,6 +1756,7 @@ impl FrameBuilder {
angle: AngleRadian,
stops: &[RenderGradientStop],
extend_mode: RenderExtendMode,
tile_origin: PxPoint,
tile_size: PxSize,
tile_spacing: PxSize,
) {
@ -1776,6 +1781,7 @@ impl FrameBuilder {
extend_mode,
},
stops,
tile_origin,
tile_size,
tile_spacing,
);
@ -1876,8 +1882,14 @@ impl FrameBuilder {
let offset = offset - radius.to_vector();
self.display_list
.push_radial_gradient(PxRect::new(offset, bounds), gradient, &stops, bounds, PxSize::zero());
self.display_list.push_radial_gradient(
PxRect::new(offset, bounds),
gradient,
&stops,
PxPoint::zero(),
bounds,
PxSize::zero(),
);
}
/// Push a custom display extension context with custom encoding.

View File

@ -1271,6 +1271,21 @@ impl_from_and_into_var! {
light: light.into(),
}
}
/// From same color to both.
fn from(color: Rgba) -> ColorPair {
ColorPair { dark: color, light: color }
}
/// From same color to both.
fn from(color: Hsva) -> ColorPair {
Rgba::from(color).into()
}
/// From same color to both.
fn from(color: Hsla) -> ColorPair {
Rgba::from(color).into()
}
}
impl ColorPair {
/// Overlay white with `highlight` amount as alpha over the [`dark`] color.
@ -1286,6 +1301,14 @@ impl ColorPair {
pub fn highlight_light(self, hightlight: impl Into<Factor>) -> Rgba {
colors::BLACK.with_alpha(hightlight.into()).mix_normal(self.light)
}
/// Gets the color for the scheme.
pub fn color(self, scheme: ColorScheme) -> Rgba {
match scheme {
ColorScheme::Light => self.light,
ColorScheme::Dark => self.dark,
}
}
}
/// Defines the color space for color interpolation in a context.

View File

@ -213,6 +213,21 @@ macro_rules! __impl_from_and_into_var {
$($rest)+
}
};
// INPUT ARRAY:
(
=input=>
[$($config:tt)*]
([ $($destruct:tt)+ ] : $Input:ty) $($rest:tt)+
) => {
$crate::__impl_from_and_into_var! {
=output=>
[
input_type { $Input }
$($config)*
]
$($rest)+
}
};
// OUTPUT (without From):
(

View File

@ -363,6 +363,7 @@ impl DisplayListBuilder {
clip_rect: PxRect,
gradient: wr::Gradient,
stops: &[wr::GradientStop],
tile_origin: PxPoint,
tile_size: PxSize,
tile_spacing: PxSize,
) {
@ -370,6 +371,7 @@ impl DisplayListBuilder {
clip_rect,
gradient,
stops: stops.to_vec().into_boxed_slice(),
tile_origin,
tile_size,
tile_spacing,
})
@ -381,6 +383,7 @@ impl DisplayListBuilder {
clip_rect: PxRect,
gradient: wr::RadialGradient,
stops: &[wr::GradientStop],
tile_origin: PxPoint,
tile_size: PxSize,
tile_spacing: PxSize,
) {
@ -388,6 +391,7 @@ impl DisplayListBuilder {
clip_rect,
gradient,
stops: stops.to_vec().into_boxed_slice(),
tile_origin,
tile_size,
tile_spacing,
});
@ -399,6 +403,7 @@ impl DisplayListBuilder {
clip_rect: PxRect,
gradient: wr::ConicGradient,
stops: &[wr::GradientStop],
tile_origin: PxPoint,
tile_size: PxSize,
tile_spacing: PxSize,
) {
@ -406,6 +411,7 @@ impl DisplayListBuilder {
clip_rect,
gradient,
stops: stops.to_vec().into_boxed_slice(),
tile_origin,
tile_size,
tile_spacing,
});
@ -1147,6 +1153,7 @@ enum DisplayItem {
clip_rect: PxRect,
gradient: wr::Gradient,
stops: Box<[wr::GradientStop]>,
tile_origin: PxPoint,
tile_size: PxSize,
tile_spacing: PxSize,
},
@ -1154,6 +1161,7 @@ enum DisplayItem {
clip_rect: PxRect,
gradient: wr::RadialGradient,
stops: Box<[wr::GradientStop]>,
tile_origin: PxPoint,
tile_size: PxSize,
tile_spacing: PxSize,
},
@ -1161,6 +1169,7 @@ enum DisplayItem {
clip_rect: PxRect,
gradient: wr::ConicGradient,
stops: Box<[wr::GradientStop]>,
tile_origin: PxPoint,
tile_size: PxSize,
tile_spacing: PxSize,
},
@ -1494,17 +1503,21 @@ impl DisplayItem {
clip_rect,
gradient,
stops,
mut tile_origin,
tile_size,
tile_spacing,
} => {
tile_origin.x.0 = tile_origin.x.0.rem_euclid(tile_size.width.0);
tile_origin.y.0 = tile_origin.y.0.rem_euclid(tile_size.height.0);
let bounds = PxRect::new(-tile_origin, clip_rect.size + tile_origin.to_vector().to_size()).to_wr();
let clip = sc.clip_chain_id(wr_list);
let bounds = clip_rect.to_wr();
// stops needs to immediately followed by the gradient, if the clip-chain item
// is inserted in the between the stops are lost.
wr_list.push_stops(stops);
wr_list.push_gradient(
&wr::CommonItemProperties {
clip_rect: bounds,
clip_rect: clip_rect.to_wr(),
clip_chain_id: clip,
spatial_id: sc.spatial_id(),
flags: sc.primitive_flags(),
@ -1519,15 +1532,19 @@ impl DisplayItem {
clip_rect,
gradient,
stops,
mut tile_origin,
tile_size,
tile_spacing,
} => {
tile_origin.x.0 = tile_origin.x.0.rem_euclid(tile_size.width.0);
tile_origin.y.0 = tile_origin.y.0.rem_euclid(tile_size.height.0);
let bounds = PxRect::new(-tile_origin, clip_rect.size + tile_origin.to_vector().to_size()).to_wr();
let clip = sc.clip_chain_id(wr_list);
let bounds = clip_rect.to_wr();
wr_list.push_stops(stops);
wr_list.push_radial_gradient(
&wr::CommonItemProperties {
clip_rect: bounds,
clip_rect: clip_rect.to_wr(),
clip_chain_id: clip,
spatial_id: sc.spatial_id(),
flags: sc.primitive_flags(),
@ -1542,15 +1559,19 @@ impl DisplayItem {
clip_rect,
gradient,
stops,
mut tile_origin,
tile_size,
tile_spacing,
} => {
tile_origin.x.0 = tile_origin.x.0.rem_euclid(tile_size.width.0);
tile_origin.y.0 = tile_origin.y.0.rem_euclid(tile_size.height.0);
let bounds = PxRect::new(-tile_origin, clip_rect.size + tile_origin.to_vector().to_size()).to_wr();
let clip = sc.clip_chain_id(wr_list);
let bounds = clip_rect.to_wr();
wr_list.push_stops(stops);
wr_list.push_conic_gradient(
&wr::CommonItemProperties {
clip_rect: bounds,
clip_rect: clip_rect.to_wr(),
clip_chain_id: clip,
spatial_id: sc.spatial_id(),
flags: sc.primitive_flags(),

View File

@ -221,7 +221,7 @@ pub fn default_cmd_tooltip_fn(args: CmdTooltipArgs) -> impl UiNode {
/// When this is set the button widget sets these properties if they are not set:
///
/// * [`child`]: Set to an widget produced by [`cmd_child_fn`](fn@cmd_child_fn), by default is `Text!(cmd.name())`.
/// * [`tooltip_fn`]: Set to a widget function provided by [`cmd_tooltip_fn`](fn@cmd_tooltip_fn), by default it
/// * [`tooltip_fn`]: Set to a widget function provided by [`cmd_tooltip_fn`](fn@cmd_tooltip_fn), by default it
/// shows the command info and first shortcut.
/// * [`enabled`]: Set to `cmd.is_enabled()`.
/// * [`visibility`]: Set to `cmd.has_handlers().into()`.

View File

@ -6,4 +6,6 @@ edition = "2021"
license = "Apache-2.0"
[dependencies]
zero-ui-wgt = { path = "../zero-ui-wgt" }
zero-ui-wgt = { path = "../zero-ui-wgt" }
zero-ui-color = { path = "../zero-ui-color" }
serde = "1"

View File

@ -3,10 +3,14 @@
//! Checkerboard widget, properties and nodes.
use std::ops;
use zero_ui_color::COLOR_SCHEME_VAR;
use zero_ui_wgt::prelude::{
gradient::{RenderExtendMode, RenderGradientStop},
*,
};
/// A checkerboard visual.
///
/// This widget draws a checkerboard pattern, with configurable dimensions and colors.
@ -18,51 +22,72 @@ impl Checkerboard {
}
}
/// Checker board colors.
///
/// See [`colors`](fn@colors) for more details.
#[derive(Debug, Clone, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
pub struct Colors(pub [ColorPair; 2]);
impl ops::Deref for Colors {
type Target = [ColorPair; 2];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl_from_and_into_var! {
fn from<C: Into<ColorPair>>([c0, c1]: [C; 2]) -> Colors {
Colors([c0.into(), c1.into()])
}
fn from<C0: Into<ColorPair>, C1: Into<ColorPair>>((c0, c1): (C0, C1)) -> Colors {
Colors([c0.into(), c1.into()])
}
}
context_var! {
/// The checkerboard colors.
///
/// Default depends on the color scheme.
///
/// [`BLACK`]: colors::BLACK
/// [`WHITE`]: colors::WHITE
pub static COLORS_VAR: (Rgba, Rgba) = color_scheme_map(
(rgb(20, 20, 20), rgb(40, 40, 40)),
(rgb(202, 202, 204), rgb(253, 253, 253))
);
/// The size of one color rectangle in the checkerboard.
///
/// Default is `(20, 20)`.
pub static SIZE_VAR: Size = (20, 20);
pub static COLORS_VAR: Colors = [
ColorPair { dark: rgb(20, 20, 20), light: rgb(202, 202, 204) },
ColorPair { dark: rgb(40, 40, 40), light: rgb(253, 253, 253) },
];
/// Offset applied to the checkerboard pattern.
///
/// Default is no offset `(0, 0)`.
pub static OFFSET_VAR: Vector = Vector::zero();
pub static ORIGIN_VAR: Point = Point::zero();
/// The size of one color rectangle in the checkerboard.
///
/// Default is `(20, 20)`.
pub static SIZE_VAR: Size = 20;
}
/// Set both checkerboard colors.
///
/// The values are the interchanging colors for a given color scheme, for example in the dark
/// color scheme the `(colors.0.dark, colors.1.dark)` colors are used.
///
/// This property sets [`COLORS_VAR`] for all inner checkerboard widgets.
#[property(CONTEXT, default(COLORS_VAR))]
pub fn colors(child: impl UiNode, colors: impl IntoVar<(Rgba, Rgba)>) -> impl UiNode {
#[property(CONTEXT, default(COLORS_VAR), widget_impl(Checkerboard))]
pub fn colors(child: impl UiNode, colors: impl IntoVar<Colors>) -> impl UiNode {
with_context_var(child, COLORS_VAR, colors)
}
/// Set the size of a checkerboard color rectangle.
///
/// This property sets the [`SIZE_VAR`] for all inner checkerboard widgets.
#[property(CONTEXT, default(SIZE_VAR))]
#[property(CONTEXT, default(SIZE_VAR), widget_impl(Checkerboard))]
pub fn cb_size(child: impl UiNode, size: impl IntoVar<Size>) -> impl UiNode {
with_context_var(child, SIZE_VAR, size)
}
/// Sets the offset of the checkerboard pattern.
///
/// Relative values are resolved in the context of a [`cb_size`](fn@cb_size).
///
/// This property sets the [`OFFSET_VAR`] for all inner checkerboard widgets.
#[property(CONTEXT, default(OFFSET_VAR))]
pub fn cb_offset(child: impl UiNode, offset: impl IntoVar<Vector>) -> impl UiNode {
with_context_var(child, OFFSET_VAR, offset)
#[property(CONTEXT, default(ORIGIN_VAR), widget_impl(Checkerboard))]
pub fn cb_origin(child: impl UiNode, offset: impl IntoVar<Point>) -> impl UiNode {
with_context_var(child, ORIGIN_VAR, offset)
}
/// Checkerboard node.
@ -70,15 +95,16 @@ pub fn cb_offset(child: impl UiNode, offset: impl IntoVar<Vector>) -> impl UiNod
/// The node is configured by the contextual variables defined in the widget.
pub fn node() -> impl UiNode {
let mut render_size = PxSize::zero();
let mut tile_origin = PxPoint::zero();
let mut tile_size = PxSize::zero();
let mut center = PxPoint::zero();
match_node_leaf(move |op| match op {
UiNodeOp::Init => {
WIDGET
.sub_var_render(&COLORS_VAR)
.sub_var_render(&COLOR_SCHEME_VAR)
.sub_var_layout(&SIZE_VAR)
.sub_var_layout(&OFFSET_VAR);
.sub_var_layout(&ORIGIN_VAR);
}
UiNodeOp::Measure { desired_size, .. } => {
*desired_size = LAYOUT.constraints().fill_size();
@ -91,31 +117,23 @@ pub fn node() -> impl UiNode {
}
let ts = SIZE_VAR.layout_dft(PxSize::splat(Px(4)));
let to = LAYOUT.with_constraints(PxConstraints2d::new_exact_size(ts), || ORIGIN_VAR.layout());
let mut offset = OFFSET_VAR.layout();
if offset.x > ts.width {
offset.x /= ts.width;
}
if offset.y > ts.height {
offset.y /= ts.height;
}
let mut c = ts.to_vector().to_point() / 2.0.fct();
c += offset;
if tile_size != ts || center != c {
if tile_origin != to || tile_size != ts {
tile_origin = to;
tile_size = ts;
center = c;
WIDGET.render();
}
}
UiNodeOp::Render { frame } => {
let (c0, c1) = COLORS_VAR.get();
let colors = [c0.into(), c1.into()];
let [c0, c1] = COLORS_VAR.get().0;
let sch = COLOR_SCHEME_VAR.get();
let colors = [c0.color(sch).into(), c1.color(sch).into()];
frame.push_conic_gradient(
PxRect::from_size(render_size),
center,
tile_size.to_vector().to_point() / 2.fct(),
0.rad(),
&[
RenderGradientStop {
@ -152,6 +170,7 @@ pub fn node() -> impl UiNode {
},
],
RenderExtendMode::Repeat,
tile_origin,
tile_size,
PxSize::zero(),
);

View File

@ -155,7 +155,7 @@ where
}
/// Continue building a tiled linear gradient.
pub fn tile<T, TS>(self, tile_size: T, tile_spacing: TS) -> TiledLinearGradient<S, A, E, T::Var, TS::Var>
pub fn tile<T, TS>(self, tile_size: T, tile_spacing: TS) -> TiledLinearGradient<S, A, E, LocalVar<Point>, T::Var, TS::Var>
where
T: IntoVar<Size>,
TS: IntoVar<Size>,
@ -164,6 +164,7 @@ where
stops: self.stops,
axis: self.axis,
extend_mode: self.extend_mode,
tile_origin: LocalVar(Point::zero()),
tile_size: tile_size.into_var(),
tile_spacing: tile_spacing.into_var(),
data: self.data,
@ -175,7 +176,7 @@ where
///
/// Relative values are resolved on the full available size, so settings this to `100.pct()` is
/// the same as not tiling.
pub fn tile_size<T>(self, size: T) -> TiledLinearGradient<S, A, E, T::Var, LocalVar<Size>>
pub fn tile_size<T>(self, size: T) -> TiledLinearGradient<S, A, E, LocalVar<Point>, T::Var, LocalVar<Size>>
where
T: IntoVar<Size>,
{
@ -192,20 +193,22 @@ where
/// Use [`gradient`], [`linear_gradient`] to build.
///
/// [`gradient`]: fn@gradient
pub struct TiledLinearGradient<S, A, E, T, TS> {
pub struct TiledLinearGradient<S, A, E, O, T, TS> {
stops: S,
axis: A,
extend_mode: E,
tile_origin: O,
tile_size: T,
tile_spacing: TS,
data: LinearNodeData,
tile_data: TiledNodeData,
}
impl<S, A, E, T, TS> TiledLinearGradient<S, A, E, T, TS>
impl<S, A, E, O, T, TS> TiledLinearGradient<S, A, E, O, T, TS>
where
S: Var<GradientStops>,
A: Var<LinearGradientAxis>,
E: Var<ExtendMode>,
O: Var<Point>,
T: Var<Size>,
TS: Var<Size>,
{
@ -218,7 +221,7 @@ where
/// fully fit in the available space, so setting this to `1.lft()` will cause the *border* tiles
/// to always touch the full bounds and the middle filled with the maximum full tiles that fit or
/// empty space.
pub fn tile_spacing<TS2>(self, spacing: TS2) -> TiledLinearGradient<S, A, E, T::Var, TS2::Var>
pub fn tile_spacing<TS2>(self, spacing: TS2) -> TiledLinearGradient<S, A, E, O, T, TS2::Var>
where
TS2: IntoVar<Size>,
{
@ -226,12 +229,33 @@ where
stops: self.stops,
axis: self.axis,
extend_mode: self.extend_mode,
tile_origin: self.tile_origin,
tile_size: self.tile_size,
tile_spacing: spacing.into_var(),
data: self.data,
tile_data: self.tile_data,
}
}
/// Sets the tile offset.
///
/// Relative values are resolved on the tile size, so setting this to `100.pct()` will
/// offset a full *turn*.
pub fn tile_origin<O2>(self, origin: O2) -> TiledLinearGradient<S, A, E, O2::Var, T, TS>
where
O2: IntoVar<Point>,
{
TiledLinearGradient {
stops: self.stops,
axis: self.axis,
extend_mode: self.extend_mode,
tile_origin: origin.into_var(),
tile_size: self.tile_size,
tile_spacing: self.tile_spacing,
data: self.data,
tile_data: self.tile_data,
}
}
}
/// Radial gradient.
@ -281,7 +305,7 @@ where
}
/// Continue building a tiled radial gradient.
pub fn tile<T, TS>(self, tile_size: T, tile_spacing: TS) -> TiledRadialGradient<S, C, R, E, T::Var, TS::Var>
pub fn tile<T, TS>(self, tile_size: T, tile_spacing: TS) -> TiledRadialGradient<S, C, R, E, LocalVar<Point>, T::Var, TS::Var>
where
T: IntoVar<Size>,
TS: IntoVar<Size>,
@ -291,6 +315,7 @@ where
center: self.center,
radius: self.radius,
extend_mode: self.extend_mode,
tile_origin: LocalVar(Point::zero()),
tile_size: tile_size.into_var(),
tile_spacing: tile_spacing.into_var(),
data: self.data,
@ -299,7 +324,7 @@ where
}
/// Continue building a tiled radial gradient.
pub fn tile_size<T>(self, size: T) -> TiledRadialGradient<S, C, R, E, T::Var, LocalVar<Size>>
pub fn tile_size<T>(self, size: T) -> TiledRadialGradient<S, C, R, E, LocalVar<Point>, T::Var, LocalVar<Size>>
where
T: IntoVar<Size>,
{
@ -315,22 +340,24 @@ where
/// Use [`gradient`], [`radial_gradient`] to build.
///
/// [`gradient`]: fn@gradient
pub struct TiledRadialGradient<S, C, R, E, T, TS> {
pub struct TiledRadialGradient<S, C, R, E, O, T, TS> {
stops: S,
center: C,
radius: R,
extend_mode: E,
tile_origin: O,
tile_size: T,
tile_spacing: TS,
data: RadialNodeData,
tile_data: TiledNodeData,
}
impl<S, C, R, E, T, TS> TiledRadialGradient<S, C, R, E, T, TS>
impl<S, C, R, E, O, T, TS> TiledRadialGradient<S, C, R, E, O, T, TS>
where
S: Var<GradientStops>,
C: Var<Point>,
R: Var<GradientRadius>,
E: Var<ExtendMode>,
O: Var<Point>,
T: Var<Size>,
TS: Var<Size>,
{
@ -343,7 +370,7 @@ where
/// fully fit in the available space, so setting this to `1.lft()` will cause the *border* tiles
/// to always touch the full bounds and the middle filled with the maximum full tiles that fit or
/// empty space.
pub fn tile_spacing<TS2>(self, spacing: TS2) -> TiledRadialGradient<S, C, R, E, T::Var, TS2::Var>
pub fn tile_spacing<TS2>(self, spacing: TS2) -> TiledRadialGradient<S, C, R, E, O, T, TS2::Var>
where
TS2: IntoVar<Size>,
{
@ -352,12 +379,34 @@ where
center: self.center,
radius: self.radius,
extend_mode: self.extend_mode,
tile_origin: self.tile_origin,
tile_size: self.tile_size,
tile_spacing: spacing.into_var(),
data: self.data,
tile_data: self.tile_data,
}
}
/// Sets the tile offset.
///
/// Relative values are resolved on the tile size, so setting this to `100.pct()` will
/// offset a full *turn*.
pub fn tile_origin<O2>(self, origin: O2) -> TiledRadialGradient<S, C, R, E, O2::Var, T, TS>
where
O2: IntoVar<Point>,
{
TiledRadialGradient {
stops: self.stops,
center: self.center,
radius: self.radius,
extend_mode: self.extend_mode,
tile_origin: origin.into_var(),
tile_size: self.tile_size,
tile_spacing: self.tile_spacing,
data: self.data,
tile_data: self.tile_data,
}
}
}
/// Conic gradient.
@ -407,7 +456,7 @@ where
}
/// Continue building a tiled radial gradient.
pub fn tile<T, TS>(self, tile_size: T, tile_spacing: TS) -> TiledConicGradient<S, C, A, E, T::Var, TS::Var>
pub fn tile<T, TS>(self, tile_size: T, tile_spacing: TS) -> TiledConicGradient<S, C, A, E, LocalVar<Point>, T::Var, TS::Var>
where
T: IntoVar<Size>,
TS: IntoVar<Size>,
@ -417,6 +466,7 @@ where
center: self.center,
angle: self.angle,
extend_mode: self.extend_mode,
tile_origin: LocalVar(Point::zero()),
tile_size: tile_size.into_var(),
tile_spacing: tile_spacing.into_var(),
data: self.data,
@ -425,7 +475,7 @@ where
}
/// Continue building a tiled radial gradient.
pub fn tile_size<T>(self, size: T) -> TiledConicGradient<S, C, A, E, T::Var, LocalVar<Size>>
pub fn tile_size<T>(self, size: T) -> TiledConicGradient<S, C, A, E, LocalVar<Point>, T::Var, LocalVar<Size>>
where
T: IntoVar<Size>,
{
@ -440,22 +490,24 @@ where
/// Use [`gradient`], [`conic_gradient`] to build.
///
/// [`gradient`]: fn@gradient
pub struct TiledConicGradient<S, C, A, E, T, TS> {
pub struct TiledConicGradient<S, C, A, E, O, T, TS> {
stops: S,
center: C,
angle: A,
extend_mode: E,
tile_origin: O,
tile_size: T,
tile_spacing: TS,
data: ConicNodeData,
tile_data: TiledNodeData,
}
impl<S, C, A, E, T, TS> TiledConicGradient<S, C, A, E, T, TS>
impl<S, C, A, E, O, T, TS> TiledConicGradient<S, C, A, E, O, T, TS>
where
S: Var<GradientStops>,
C: Var<Point>,
A: Var<AngleRadian>,
E: Var<ExtendMode>,
O: Var<Point>,
T: Var<Size>,
TS: Var<Size>,
{
@ -468,7 +520,7 @@ where
/// fully fit in the available space, so setting this to `1.lft()` will cause the *border* tiles
/// to always touch the full bounds and the middle filled with the maximum full tiles that fit or
/// empty space.
pub fn tile_spacing<TS2>(self, spacing: TS2) -> TiledConicGradient<S, C, A, E, T::Var, TS2::Var>
pub fn tile_spacing<TS2>(self, spacing: TS2) -> TiledConicGradient<S, C, A, E, O, T, TS2::Var>
where
TS2: IntoVar<Size>,
{
@ -477,12 +529,34 @@ where
center: self.center,
angle: self.angle,
extend_mode: self.extend_mode,
tile_origin: self.tile_origin,
tile_size: self.tile_size,
tile_spacing: spacing.into_var(),
data: self.data,
tile_data: self.tile_data,
}
}
/// Sets the tile offset.
///
/// Relative values are resolved on the tile size, so setting this to `100.pct()` will
/// offset a full *turn*.
pub fn tile_origin<O2>(self, origin: O2) -> TiledConicGradient<S, C, A, E, O2::Var, T, TS>
where
O2: IntoVar<Point>,
{
TiledConicGradient {
stops: self.stops,
center: self.center,
angle: self.angle,
extend_mode: self.extend_mode,
tile_origin: origin.into_var(),
tile_size: self.tile_size,
tile_spacing: self.tile_spacing,
data: self.data,
tile_data: self.tile_data,
}
}
}
#[derive(Default)]
@ -533,6 +607,7 @@ where
self.data.line,
&self.data.stops,
self.extend_mode.get().into(),
PxPoint::zero(),
self.data.size,
PxSize::zero(),
);
@ -541,15 +616,17 @@ where
#[derive(Default)]
struct TiledNodeData {
origin: PxPoint,
size: PxSize,
spacing: PxSize,
}
#[ui_node(none)]
impl<S, A, E, T, TS> UiNode for TiledLinearGradient<S, A, E, T, TS>
impl<S, A, E, O, T, TS> UiNode for TiledLinearGradient<S, A, E, O, T, TS>
where
S: Var<GradientStops>,
A: Var<LinearGradientAxis>,
E: Var<ExtendMode>,
O: Var<Point>,
T: Var<Size>,
TS: Var<Size>,
{
@ -558,6 +635,7 @@ where
.sub_var_layout(&self.axis)
.sub_var_layout(&self.stops)
.sub_var_layout(&self.extend_mode)
.sub_var_layout(&self.tile_origin)
.sub_var_layout(&self.tile_size)
.sub_var_layout(&self.tile_spacing);
}
@ -579,6 +657,7 @@ where
self.tile_data.spacing = self.tile_spacing.layout();
});
self.data.line = self.axis.layout();
self.tile_data.origin = self.tile_origin.layout();
});
let length = self.data.line.length();
@ -598,6 +677,7 @@ where
self.data.line,
&self.data.stops,
self.extend_mode.get().into(),
self.tile_data.origin,
self.tile_data.size,
self.tile_data.spacing,
);
@ -663,6 +743,7 @@ where
self.data.radius,
&self.data.stops,
self.extend_mode.get().into(),
PxPoint::zero(),
self.data.size,
PxSize::zero(),
);
@ -670,12 +751,13 @@ where
}
#[ui_node(none)]
impl<S, C, R, E, T, TS> UiNode for TiledRadialGradient<S, C, R, E, T, TS>
impl<S, C, R, E, O, T, TS> UiNode for TiledRadialGradient<S, C, R, E, O, T, TS>
where
S: Var<GradientStops>,
C: Var<Point>,
R: Var<GradientRadius>,
E: Var<ExtendMode>,
O: Var<Point>,
T: Var<Size>,
TS: Var<Size>,
{
@ -685,6 +767,7 @@ where
.sub_var_layout(&self.radius)
.sub_var_layout(&self.stops)
.sub_var_layout(&self.extend_mode)
.sub_var_layout(&self.tile_origin)
.sub_var_layout(&self.tile_size)
.sub_var_layout(&self.tile_spacing);
}
@ -706,6 +789,7 @@ where
});
self.data.center = self.center.layout_dft(self.tile_data.size.to_vector().to_point() * 0.5.fct());
self.data.radius = self.radius.get().layout(self.data.center);
self.tile_data.origin = self.tile_origin.layout();
});
LAYOUT.with_constraints(
@ -730,6 +814,7 @@ where
self.data.radius,
&self.data.stops,
self.extend_mode.get().into(),
self.tile_data.origin,
self.tile_data.size,
self.tile_data.spacing,
);
@ -793,6 +878,7 @@ where
self.angle.get(),
&self.data.stops,
self.extend_mode.get().into(),
PxPoint::zero(),
self.data.size,
PxSize::zero(),
);
@ -800,12 +886,13 @@ where
}
#[ui_node(none)]
impl<S, C, A, E, T, TS> UiNode for TiledConicGradient<S, C, A, E, T, TS>
impl<S, C, A, E, O, T, TS> UiNode for TiledConicGradient<S, C, A, E, O, T, TS>
where
S: Var<GradientStops>,
C: Var<Point>,
A: Var<AngleRadian>,
E: Var<ExtendMode>,
O: Var<Point>,
T: Var<Size>,
TS: Var<Size>,
{
@ -815,6 +902,7 @@ where
.sub_var_layout(&self.angle)
.sub_var_layout(&self.stops)
.sub_var_layout(&self.extend_mode)
.sub_var_layout(&self.tile_origin)
.sub_var_layout(&self.tile_size)
.sub_var_layout(&self.tile_spacing);
}
@ -835,6 +923,7 @@ where
self.tile_data.spacing = self.tile_spacing.layout();
});
self.data.center = self.center.get().layout_dft(self.tile_data.size.to_vector().to_point() * 0.5.fct());
self.tile_data.origin = self.tile_origin.layout();
});
let perimeter = Px({
@ -859,6 +948,7 @@ where
self.angle.get(),
&self.data.stops,
self.extend_mode.get().into(),
self.tile_data.origin,
self.tile_data.size,
self.tile_data.spacing,
);

View File

@ -1237,6 +1237,7 @@ pub fn overscroll_node(child: impl UiNode) -> impl UiNode {
radius,
&stops,
ExtendMode::Clamp.into(),
PxPoint::zero(),
v_rect.size,
PxSize::zero(),
);
@ -1254,6 +1255,7 @@ pub fn overscroll_node(child: impl UiNode) -> impl UiNode {
radius,
&stops,
ExtendMode::Clamp.into(),
PxPoint::zero(),
h_rect.size,
PxSize::zero(),
);

View File

@ -4,4 +4,4 @@
//!
//! See [`zero_ui_wgt_checkerboard`] for the full widget API.
pub use zero_ui_wgt_checkerboard::{cb_offset, cb_size, colors, node, Checkerboard};
pub use zero_ui_wgt_checkerboard::{cb_origin, cb_size, colors, Checkerboard, Colors};