mirror of
https://github.com/danbulant/cushy
synced 2026-07-05 03:00:43 +00:00
Subpixels + Feathering + figures refactor
Much curves
This commit is contained in:
parent
aea9def07d
commit
d5bde44e27
20 changed files with 144 additions and 155 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
|
@ -623,7 +623,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "figures"
|
name = "figures"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/khonsulabs/figures#4712514fbed861ad530bd48d4e62f8efcaa4df1f"
|
source = "git+https://github.com/khonsulabs/figures#0745fc0ff95e94ce2181aa1528a30bda3d6152f2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"euclid",
|
"euclid",
|
||||||
|
|
@ -1089,7 +1089,7 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kludgine"
|
name = "kludgine"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/khonsulabs/kludgine#ca138e79a4b8ebc3bdd463006b1dadd3269183f3"
|
source = "git+https://github.com/khonsulabs/kludgine#0530299bbe79431b5fa398182991c63e06d94b90"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"alot",
|
"alot",
|
||||||
|
|
@ -1974,9 +1974,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.24"
|
version = "0.38.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9ad981d6c340a49cdc40a1028d9c6084ec7e9fa33fcb839cab656a267071e234"
|
checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.1",
|
"bitflags 2.4.1",
|
||||||
"errno",
|
"errno",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use gooey::widgets::Canvas;
|
use gooey::widgets::Canvas;
|
||||||
use gooey::{Run, Tick};
|
use gooey::{Run, Tick};
|
||||||
use kludgine::figures::units::Px;
|
use kludgine::figures::{Angle, IntoSigned, Point, Px2D, Rect, Size};
|
||||||
use kludgine::figures::{Angle, IntoSigned, Point, Rect, Size};
|
|
||||||
use kludgine::shapes::Shape;
|
use kludgine::shapes::Shape;
|
||||||
use kludgine::text::{Text, TextOrigin};
|
use kludgine::text::{Text, TextOrigin};
|
||||||
use kludgine::{Color, DrawableExt};
|
use kludgine::{Color, DrawableExt};
|
||||||
|
|
@ -15,11 +14,11 @@ fn main() -> gooey::Result<()> {
|
||||||
context.gfx.draw_text(
|
context.gfx.draw_text(
|
||||||
Text::new("Canvas exposes the full power of Kludgine", Color::WHITE)
|
Text::new("Canvas exposes the full power of Kludgine", Color::WHITE)
|
||||||
.origin(TextOrigin::Center)
|
.origin(TextOrigin::Center)
|
||||||
.translate_by(center - Point::new(Px(0), Px(100))),
|
.translate_by(center - Point::px(0, 100)),
|
||||||
);
|
);
|
||||||
context.gfx.draw_shape(
|
context.gfx.draw_shape(
|
||||||
Shape::filled_rect(
|
Shape::filled_rect(
|
||||||
Rect::new(Point::new(Px(-50), Px(-50)), Size::new(Px(100), Px(100))),
|
Rect::new(Point::px(-50, -50), Size::px(100, 100)),
|
||||||
Color::RED,
|
Color::RED,
|
||||||
)
|
)
|
||||||
.translate_by(center)
|
.translate_by(center)
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ fn main() -> gooey::Result {
|
||||||
.and("Masked Input Field:")
|
.and("Masked Input Field:")
|
||||||
.and(password.into_input())
|
.and(password.into_input())
|
||||||
.into_rows()
|
.into_rows()
|
||||||
.width(Px(100)..Px(800))
|
.width(Px::new(100)..Px::new(800))
|
||||||
.scroll()
|
.scroll()
|
||||||
.centered()
|
.centered()
|
||||||
.expand()
|
.expand()
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,10 @@ use gooey::kludgine::Color;
|
||||||
use gooey::value::Dynamic;
|
use gooey::value::Dynamic;
|
||||||
use gooey::widgets::TileMap;
|
use gooey::widgets::TileMap;
|
||||||
use gooey::{Run, Tick};
|
use gooey::{Run, Tick};
|
||||||
|
use kludgine::figures::FloatConversion;
|
||||||
use kludgine::DrawableExt;
|
use kludgine::DrawableExt;
|
||||||
|
|
||||||
const PLAYER_SIZE: Px = Px(16);
|
const PLAYER_SIZE: Px = Px::new(16);
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
const TILES: [TileKind; 64] = {
|
const TILES: [TileKind; 64] = {
|
||||||
|
|
@ -33,7 +34,7 @@ fn main() -> gooey::Result {
|
||||||
|
|
||||||
let myself = characters.push(Player {
|
let myself = characters.push(Player {
|
||||||
color: Color::RED,
|
color: Color::RED,
|
||||||
position: Point::new(TILE_SIZE.0 as f32, TILE_SIZE.0 as f32),
|
position: Point::new(TILE_SIZE.into_float(), TILE_SIZE.into_float()),
|
||||||
});
|
});
|
||||||
|
|
||||||
let layers = Dynamic::new((Tiles::new(8, 8, TILES), characters));
|
let layers = Dynamic::new((Tiles::new(8, 8, TILES), characters));
|
||||||
|
|
@ -58,10 +59,11 @@ fn main() -> gooey::Result {
|
||||||
direction.x -= 1.0;
|
direction.x -= 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let one_second_movement = direction * TILE_SIZE.0 as f32;
|
let one_second_movement = direction * TILE_SIZE.into_float();
|
||||||
|
|
||||||
layers.map_mut(|layers| {
|
layers.map_mut(|layers| {
|
||||||
layers.1[myself].position += Point::new(
|
layers.1[myself].position += Point::new(
|
||||||
|
// TODO fix this in figures
|
||||||
one_second_movement.x * elapsed.as_secs_f32(),
|
one_second_movement.x * elapsed.as_secs_f32(),
|
||||||
one_second_movement.y * elapsed.as_secs_f32(),
|
one_second_movement.y * elapsed.as_secs_f32(),
|
||||||
)
|
)
|
||||||
|
|
@ -85,10 +87,7 @@ impl Object for Player {
|
||||||
let zoomed_size = PLAYER_SIZE * zoom;
|
let zoomed_size = PLAYER_SIZE * zoom;
|
||||||
context.draw_shape(
|
context.draw_shape(
|
||||||
Shape::filled_rect(
|
Shape::filled_rect(
|
||||||
Rect::new(
|
Rect::new(Point::squared(-zoomed_size / 2), Size::squared(zoomed_size)),
|
||||||
Point::new(-zoomed_size / 2, -zoomed_size / 2),
|
|
||||||
Size::squared(zoomed_size),
|
|
||||||
),
|
|
||||||
self.color,
|
self.color,
|
||||||
)
|
)
|
||||||
.translate_by(center),
|
.translate_by(center),
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use kludgine::app::winit::event::{
|
||||||
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
||||||
};
|
};
|
||||||
use kludgine::figures::units::{Lp, Px, UPx};
|
use kludgine::figures::units::{Lp, Px, UPx};
|
||||||
use kludgine::figures::{IntoSigned, IsZero, Point, Rect, ScreenScale, Size};
|
use kludgine::figures::{IntoSigned, Point, Px2D, Rect, ScreenScale, Size, Zero};
|
||||||
use kludgine::shapes::{Shape, StrokeOptions};
|
use kludgine::shapes::{Shape, StrokeOptions};
|
||||||
use kludgine::{Color, Kludgine};
|
use kludgine::{Color, Kludgine};
|
||||||
|
|
||||||
|
|
@ -525,7 +525,7 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> GraphicsContext<'context, 'window, '
|
||||||
/// If the alpha channel of `color` is 0, this function does nothing.
|
/// If the alpha channel of `color` is 0, this function does nothing.
|
||||||
pub fn fill(&mut self, color: Color) {
|
pub fn fill(&mut self, color: Color) {
|
||||||
if color.alpha() > 0 {
|
if color.alpha() > 0 {
|
||||||
let visible_rect = Rect::from(self.gfx.region().size - (Px(1), Px(1)));
|
let visible_rect = Rect::from(self.gfx.region().size - Size::px(1, 1));
|
||||||
|
|
||||||
let radii = self.get(&CornerRadius);
|
let radii = self.get(&CornerRadius);
|
||||||
let radii = radii.map(|r| r.into_px(self.gfx.scale()));
|
let radii = radii.map(|r| r.into_px(self.gfx.scale()));
|
||||||
|
|
@ -542,23 +542,23 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> GraphicsContext<'context, 'window, '
|
||||||
/// Strokes an outline around this widget's contents.
|
/// Strokes an outline around this widget's contents.
|
||||||
pub fn stroke_outline<Unit>(&mut self, color: Color, options: StrokeOptions<Unit>)
|
pub fn stroke_outline<Unit>(&mut self, color: Color, options: StrokeOptions<Unit>)
|
||||||
where
|
where
|
||||||
Unit: ScreenScale<Px = Px, Lp = Lp, UPx = UPx> + IsZero,
|
Unit: ScreenScale<Px = Px, Lp = Lp, UPx = UPx> + Zero,
|
||||||
{
|
{
|
||||||
if color.alpha() > 0 {
|
if color.alpha() > 0 {
|
||||||
let visible_rect = Rect::from(self.gfx.region().size - (Px(1), Px(1)));
|
let options = options.colored(color).into_px(self.gfx.scale());
|
||||||
|
let inset = options.line_width;
|
||||||
|
let visible_rect = Rect::new(
|
||||||
|
Point::squared(inset),
|
||||||
|
self.gfx.region().size - Point::new(inset * 2, inset * 2),
|
||||||
|
);
|
||||||
|
|
||||||
let radii = self.get(&CornerRadius);
|
let radii = self.get(&CornerRadius);
|
||||||
let radii = radii.map(|r| r.into_px(self.gfx.scale()));
|
let radii = radii.map(|r| r.into_px(self.gfx.scale()));
|
||||||
|
|
||||||
let focus_ring = if radii.is_zero() {
|
let focus_ring = if radii.is_zero() {
|
||||||
Shape::stroked_rect(visible_rect, color, options.into_px(self.gfx.scale()))
|
Shape::stroked_rect(visible_rect, options.into_px(self.gfx.scale()))
|
||||||
} else {
|
} else {
|
||||||
Shape::stroked_round_rect(
|
Shape::stroked_round_rect(visible_rect, radii, options)
|
||||||
visible_rect,
|
|
||||||
radii,
|
|
||||||
color,
|
|
||||||
options.into_px(self.gfx.scale()),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
self.gfx.draw_shape(&focus_ring);
|
self.gfx.draw_shape(&focus_ring);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use kludgine::figures::units::{Px, UPx};
|
use kludgine::figures::units::{Px, UPx};
|
||||||
use kludgine::figures::{
|
use kludgine::figures::{
|
||||||
self, Fraction, IntoSigned, IntoUnsigned, IsZero, Point, Rect, ScreenScale, ScreenUnit, Size,
|
self, Fraction, IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, ScreenUnit, Size, Zero,
|
||||||
};
|
};
|
||||||
use kludgine::render::Renderer;
|
use kludgine::render::Renderer;
|
||||||
use kludgine::shapes::Shape;
|
use kludgine::shapes::Shape;
|
||||||
|
|
@ -45,12 +45,12 @@ impl<'clip, 'gfx, 'pass> Graphics<'clip, 'gfx, 'pass> {
|
||||||
let clip_origin = self.renderer.clip_rect().origin.into_signed();
|
let clip_origin = self.renderer.clip_rect().origin.into_signed();
|
||||||
-Point::new(
|
-Point::new(
|
||||||
if clip_origin.x <= self.region.origin.x {
|
if clip_origin.x <= self.region.origin.x {
|
||||||
Px(0)
|
Px::ZERO
|
||||||
} else {
|
} else {
|
||||||
clip_origin.x - self.region.origin.x
|
clip_origin.x - self.region.origin.x
|
||||||
},
|
},
|
||||||
if clip_origin.y <= self.region.origin.y {
|
if clip_origin.y <= self.region.origin.y {
|
||||||
Px(0)
|
Px::ZERO
|
||||||
} else {
|
} else {
|
||||||
clip_origin.y - self.region.origin.y
|
clip_origin.y - self.region.origin.y
|
||||||
},
|
},
|
||||||
|
|
@ -147,7 +147,7 @@ impl<'clip, 'gfx, 'pass> Graphics<'clip, 'gfx, 'pass> {
|
||||||
/// Draws a shape at the origin, rotating and scaling as needed.
|
/// Draws a shape at the origin, rotating and scaling as needed.
|
||||||
pub fn draw_shape<'a, Unit>(&mut self, shape: impl Into<Drawable<&'a Shape<Unit, false>, Unit>>)
|
pub fn draw_shape<'a, Unit>(&mut self, shape: impl Into<Drawable<&'a Shape<Unit, false>, Unit>>)
|
||||||
where
|
where
|
||||||
Unit: IsZero + ShaderScalable + figures::ScreenUnit + Copy,
|
Unit: Zero + ShaderScalable + figures::ScreenUnit + Copy,
|
||||||
{
|
{
|
||||||
let mut shape = shape.into();
|
let mut shape = shape.into();
|
||||||
shape.translation += Point::<Unit>::from_px(self.translation(), self.scale());
|
shape.translation += Point::<Unit>::from_px(self.translation(), self.scale());
|
||||||
|
|
@ -171,7 +171,7 @@ impl<'clip, 'gfx, 'pass> Graphics<'clip, 'gfx, 'pass> {
|
||||||
shape: impl Into<Drawable<&'shape Shape, Unit>>,
|
shape: impl Into<Drawable<&'shape Shape, Unit>>,
|
||||||
texture: &impl TextureSource,
|
texture: &impl TextureSource,
|
||||||
) where
|
) where
|
||||||
Unit: IsZero + ShaderScalable + figures::ScreenUnit + Copy,
|
Unit: Zero + ShaderScalable + figures::ScreenUnit + Copy,
|
||||||
i32: From<<Unit as IntoSigned>::Signed>,
|
i32: From<<Unit as IntoSigned>::Signed>,
|
||||||
Shape: ShapeSource<Unit, true> + 'shape,
|
Shape: ShapeSource<Unit, true> + 'shape,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
23
src/lib.rs
23
src/lib.rs
|
|
@ -25,7 +25,7 @@ use std::ops::Sub;
|
||||||
pub use kludgine;
|
pub use kludgine;
|
||||||
use kludgine::app::winit::error::EventLoopError;
|
use kludgine::app::winit::error::EventLoopError;
|
||||||
use kludgine::figures::units::UPx;
|
use kludgine::figures::units::UPx;
|
||||||
use kludgine::figures::{Fraction, ScreenUnit};
|
use kludgine::figures::{Fraction, ScreenUnit, Size};
|
||||||
pub use names::Name;
|
pub use names::Name;
|
||||||
pub use utils::{Lazy, WithClone};
|
pub use utils::{Lazy, WithClone};
|
||||||
|
|
||||||
|
|
@ -68,6 +68,27 @@ impl ConstraintLimit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An extension trait for `Size<ConstraintLimit>`.
|
||||||
|
pub trait FitMeasuredSize {
|
||||||
|
/// Returns the result of calling [`ConstraintLimit::fit_measured`] for each
|
||||||
|
/// matching component in `self` and `measured`.
|
||||||
|
fn fit_measured<Unit>(self, measured: Size<Unit>, scale: Fraction) -> Size<UPx>
|
||||||
|
where
|
||||||
|
Unit: ScreenUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FitMeasuredSize for Size<ConstraintLimit> {
|
||||||
|
fn fit_measured<Unit>(self, measured: Size<Unit>, scale: Fraction) -> Size<UPx>
|
||||||
|
where
|
||||||
|
Unit: ScreenUnit,
|
||||||
|
{
|
||||||
|
Size::new(
|
||||||
|
self.width.fit_measured(measured.width, scale),
|
||||||
|
self.height.fit_measured(measured.height, scale),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Sub<UPx> for ConstraintLimit {
|
impl Sub<UPx> for ConstraintLimit {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use ahash::AHashMap;
|
use ahash::AHashMap;
|
||||||
use kludgine::figures::units::{Lp, Px, UPx};
|
use kludgine::figures::units::{Lp, Px, UPx};
|
||||||
use kludgine::figures::{Fraction, IntoSigned, IntoUnsigned, IsZero, Rect, ScreenScale, Size};
|
use kludgine::figures::{Fraction, IntoSigned, IntoUnsigned, Rect, ScreenScale, Size, Zero};
|
||||||
use kludgine::shapes::CornerRadii;
|
use kludgine::shapes::CornerRadii;
|
||||||
use kludgine::Color;
|
use kludgine::Color;
|
||||||
use palette::{IntoColor, Okhsl, OklabHue, Srgb};
|
use palette::{IntoColor, Okhsl, OklabHue, Srgb};
|
||||||
|
|
@ -399,11 +399,6 @@ pub enum Dimension {
|
||||||
Lp(Lp),
|
Lp(Lp),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dimension {
|
|
||||||
/// A dimension of 0 pixels.
|
|
||||||
pub const ZERO: Self = Self::Px(Px(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Dimension {
|
impl Default for Dimension {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::ZERO
|
Self::ZERO
|
||||||
|
|
@ -422,7 +417,9 @@ impl From<Lp> for Dimension {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IsZero for Dimension {
|
impl Zero for Dimension {
|
||||||
|
const ZERO: Self = Dimension::Px(Px::ZERO);
|
||||||
|
|
||||||
fn is_zero(&self) -> bool {
|
fn is_zero(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Dimension::Px(x) => x.is_zero(),
|
Dimension::Px(x) => x.is_zero(),
|
||||||
|
|
|
||||||
|
|
@ -759,7 +759,7 @@ pub trait MakeWidget: Sized {
|
||||||
|
|
||||||
/// Returns a new widget that renders `color` behind `self`.
|
/// Returns a new widget that renders `color` behind `self`.
|
||||||
fn background_color(self, color: impl IntoValue<Color>) -> Container {
|
fn background_color(self, color: impl IntoValue<Color>) -> Container {
|
||||||
self.contain().pad_by(Px(0)).background_color(color)
|
self.contain().pad_by(Px::ZERO).background_color(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps `self` with the default padding.
|
/// Wraps `self` with the default padding.
|
||||||
|
|
|
||||||
|
|
@ -186,10 +186,7 @@ impl WrapperWidget for Align {
|
||||||
let layout = self.measure(available_space, context);
|
let layout = self.measure(available_space, context);
|
||||||
|
|
||||||
Rect::new(
|
Rect::new(
|
||||||
Point::new(
|
Point::new(layout.margin.left, layout.margin.top).into_signed(),
|
||||||
layout.margin.left.into_signed(),
|
|
||||||
layout.margin.top.into_signed(),
|
|
||||||
),
|
|
||||||
layout.content.into_signed(),
|
layout.content.into_signed(),
|
||||||
)
|
)
|
||||||
.into()
|
.into()
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ use crate::styles::{ColorExt, Styles};
|
||||||
use crate::utils::ModifiersExt;
|
use crate::utils::ModifiersExt;
|
||||||
use crate::value::{Dynamic, IntoValue, Value};
|
use crate::value::{Dynamic, IntoValue, Value};
|
||||||
use crate::widget::{Callback, EventHandling, MakeWidget, Widget, WidgetRef, HANDLED, IGNORED};
|
use crate::widget::{Callback, EventHandling, MakeWidget, Widget, WidgetRef, HANDLED, IGNORED};
|
||||||
|
use crate::FitMeasuredSize;
|
||||||
|
|
||||||
/// A clickable button.
|
/// A clickable button.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -362,12 +363,8 @@ impl Widget for Button {
|
||||||
let inset = context.get(&IntrinsicPadding).into_px(context.gfx.scale());
|
let inset = context.get(&IntrinsicPadding).into_px(context.gfx.scale());
|
||||||
|
|
||||||
let focus_ring = Shape::stroked_rect(
|
let focus_ring = Shape::stroked_rect(
|
||||||
Rect::new(
|
Rect::new(Point::squared(inset), context.gfx.region().size - inset * 2),
|
||||||
Point::new(inset, inset),
|
two_lp_stroke.colored(color),
|
||||||
context.gfx.region().size - inset * 2,
|
|
||||||
),
|
|
||||||
color,
|
|
||||||
two_lp_stroke,
|
|
||||||
);
|
);
|
||||||
context.gfx.draw_shape(&focus_ring);
|
context.gfx.draw_shape(&focus_ring);
|
||||||
} else if context.is_default() {
|
} else if context.is_default() {
|
||||||
|
|
@ -452,22 +449,12 @@ impl Widget for Button {
|
||||||
let padding = context.get(&IntrinsicPadding).into_upx(context.gfx.scale());
|
let padding = context.get(&IntrinsicPadding).into_upx(context.gfx.scale());
|
||||||
let double_padding = padding * 2;
|
let double_padding = padding * 2;
|
||||||
let mounted = self.content.mounted(&mut context.as_event_context());
|
let mounted = self.content.mounted(&mut context.as_event_context());
|
||||||
let available_space = Size::new(
|
let available_space = available_space.map(|space| space - double_padding);
|
||||||
available_space.width - double_padding,
|
|
||||||
available_space.height - double_padding,
|
|
||||||
);
|
|
||||||
let size = context.for_other(&mounted).layout(available_space);
|
let size = context.for_other(&mounted).layout(available_space);
|
||||||
let size = Size::new(
|
let size = available_space.fit_measured(size, context.gfx.scale());
|
||||||
available_space
|
|
||||||
.width
|
|
||||||
.fit_measured(size.width, context.gfx.scale()),
|
|
||||||
available_space
|
|
||||||
.height
|
|
||||||
.fit_measured(size.height, context.gfx.scale()),
|
|
||||||
);
|
|
||||||
context.set_child_layout(
|
context.set_child_layout(
|
||||||
&mounted,
|
&mounted,
|
||||||
Rect::new(Point::new(padding, padding), size).into_signed(),
|
Rect::new(Point::squared(padding), size).into_signed(),
|
||||||
);
|
);
|
||||||
size + double_padding
|
size + double_padding
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use kludgine::figures::Size;
|
||||||
use crate::context::{GraphicsContext, LayoutContext};
|
use crate::context::{GraphicsContext, LayoutContext};
|
||||||
use crate::value::Dynamic;
|
use crate::value::Dynamic;
|
||||||
use crate::widget::Widget;
|
use crate::widget::Widget;
|
||||||
use crate::Tick;
|
use crate::{ConstraintLimit, Tick};
|
||||||
|
|
||||||
/// A 2d drawable surface.
|
/// A 2d drawable surface.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
@ -55,7 +55,7 @@ impl Widget for Canvas {
|
||||||
available_space: Size<crate::ConstraintLimit>,
|
available_space: Size<crate::ConstraintLimit>,
|
||||||
_context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
_context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
||||||
) -> Size<UPx> {
|
) -> Size<UPx> {
|
||||||
Size::new(available_space.width.max(), available_space.height.max())
|
available_space.map(ConstraintLimit::max)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ impl WrapperWidget for CheckboxLabel {
|
||||||
let label_inset = checkbox_size + padding;
|
let label_inset = checkbox_size + padding;
|
||||||
let size_with_checkbox = Size::new(size.width + label_inset, size.height).into_unsigned();
|
let size_with_checkbox = Size::new(size.width + label_inset, size.height).into_unsigned();
|
||||||
WrappedLayout {
|
WrappedLayout {
|
||||||
child: Rect::new(Point::new(label_inset, Px(0)), size),
|
child: Rect::new(Point::new(label_inset, Px::ZERO), size),
|
||||||
size: size_with_checkbox,
|
size: size_with_checkbox,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -170,10 +170,7 @@ impl WrapperWidget for CheckboxLabel {
|
||||||
fn redraw_background(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
fn redraw_background(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||||
let checkbox_size = context.get(&LineHeight).into_px(context.gfx.scale());
|
let checkbox_size = context.get(&LineHeight).into_px(context.gfx.scale());
|
||||||
let padding = context.get(&IntrinsicPadding).into_px(context.gfx.scale());
|
let padding = context.get(&IntrinsicPadding).into_px(context.gfx.scale());
|
||||||
let checkbox_rect = Rect::new(
|
let checkbox_rect = Rect::new(Point::squared(padding), Size::squared(checkbox_size));
|
||||||
Point::new(padding, padding),
|
|
||||||
Size::new(checkbox_size, checkbox_size),
|
|
||||||
);
|
|
||||||
let stroke_options = StrokeOptions::lp_wide(Lp::points(2)).into_px(context.gfx.scale());
|
let stroke_options = StrokeOptions::lp_wide(Lp::points(2)).into_px(context.gfx.scale());
|
||||||
match self.value.get_tracking_refresh(context) {
|
match self.value.get_tracking_refresh(context) {
|
||||||
state @ (CheckboxState::Checked | CheckboxState::Indeterminant) => {
|
state @ (CheckboxState::Checked | CheckboxState::Indeterminant) => {
|
||||||
|
|
@ -196,7 +193,7 @@ impl WrapperWidget for CheckboxLabel {
|
||||||
icon_area.origin.y,
|
icon_area.origin.y,
|
||||||
))
|
))
|
||||||
.build()
|
.build()
|
||||||
.stroke(text_color, stroke_options),
|
.stroke(stroke_options.colored(text_color)),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
context.gfx.draw_shape(
|
context.gfx.draw_shape(
|
||||||
|
|
@ -206,15 +203,16 @@ impl WrapperWidget for CheckboxLabel {
|
||||||
center.y,
|
center.y,
|
||||||
))
|
))
|
||||||
.build()
|
.build()
|
||||||
.stroke(text_color, stroke_options),
|
.stroke(stroke_options.colored(text_color)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CheckboxState::Unchecked => {
|
CheckboxState::Unchecked => {
|
||||||
let color = context.get(&OutlineColor);
|
let color = context.get(&OutlineColor);
|
||||||
context
|
context.gfx.draw_shape(&Shape::stroked_rect(
|
||||||
.gfx
|
checkbox_rect,
|
||||||
.draw_shape(&Shape::stroked_rect(checkbox_rect, color, stroke_options));
|
stroke_options.colored(color),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,10 +102,7 @@ impl WrapperWidget for Expand {
|
||||||
available_space: Size<ConstraintLimit>,
|
available_space: Size<ConstraintLimit>,
|
||||||
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
||||||
) -> WrappedLayout {
|
) -> WrappedLayout {
|
||||||
let available_space = Size::new(
|
let available_space = available_space.map(|lim| ConstraintLimit::Fill(lim.max()));
|
||||||
ConstraintLimit::Fill(available_space.width.max()),
|
|
||||||
ConstraintLimit::Fill(available_space.height.max()),
|
|
||||||
);
|
|
||||||
let child = self.child.mounted(&mut context.as_event_context());
|
let child = self.child.mounted(&mut context.as_event_context());
|
||||||
let size = context.for_other(&child).layout(available_space);
|
let size = context.for_other(&child).layout(available_space);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -522,7 +522,7 @@ where
|
||||||
) -> (Point<Px>, Px) {
|
) -> (Point<Px>, Px) {
|
||||||
if measured.glyphs.is_empty() || (cursor.offset == 0 && cursor.affinity == Affinity::Before)
|
if measured.glyphs.is_empty() || (cursor.offset == 0 && cursor.affinity == Affinity::Before)
|
||||||
{
|
{
|
||||||
return (Point::default(), Px(0));
|
return (Point::default(), Px::ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Space between glyphs isn't represented in the glyphs. If the cursor rests
|
// Space between glyphs isn't represented in the glyphs. If the cursor rests
|
||||||
|
|
@ -553,7 +553,7 @@ where
|
||||||
) {
|
) {
|
||||||
(Ordering::Less | Ordering::Equal, Ordering::Less) => {
|
(Ordering::Less | Ordering::Equal, Ordering::Less) => {
|
||||||
// cosmic text may have grouped multiple graphemes into a single glyph.
|
// cosmic text may have grouped multiple graphemes into a single glyph.
|
||||||
let mut grapheme_offset = Px(0);
|
let mut grapheme_offset = Px::ZERO;
|
||||||
if glyph.info.start < cursor.offset {
|
if glyph.info.start < cursor.offset {
|
||||||
let clustered_bytes = glyph.info.end - glyph.info.start;
|
let clustered_bytes = glyph.info.end - glyph.info.start;
|
||||||
if clustered_bytes > 1 {
|
if clustered_bytes > 1 {
|
||||||
|
|
@ -567,8 +567,8 @@ where
|
||||||
return (
|
return (
|
||||||
Point::new(
|
Point::new(
|
||||||
rect.origin.x + grapheme_offset,
|
rect.origin.x + grapheme_offset,
|
||||||
measured.line_height.saturating_mul(Px(
|
measured.line_height.saturating_mul(Px::new(
|
||||||
i32::try_from(glyph.info.line).unwrap_or(i32::MAX)
|
i32::try_from(glyph.info.line).unwrap_or(i32::MAX),
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
rect.size.width,
|
rect.size.width,
|
||||||
|
|
@ -586,9 +586,9 @@ where
|
||||||
|
|
||||||
if closest_after_index == usize::MAX {
|
if closest_after_index == usize::MAX {
|
||||||
let bottom_right = &measured.glyphs[bottom_right_index];
|
let bottom_right = &measured.glyphs[bottom_right_index];
|
||||||
let bottom_y = measured
|
let bottom_y = measured.line_height.saturating_mul(Px::new(
|
||||||
.line_height
|
i32::try_from(bottom_right.info.line).unwrap_or(i32::MAX),
|
||||||
.saturating_mul(Px(i32::try_from(bottom_right.info.line).unwrap_or(i32::MAX)));
|
));
|
||||||
// No glyph could be found that started/contained the cursors offset.
|
// No glyph could be found that started/contained the cursors offset.
|
||||||
let mut bottom_right_cursor = Point::new(
|
let mut bottom_right_cursor = Point::new(
|
||||||
bottom_right_rect.origin.x + bottom_right_rect.size.width,
|
bottom_right_rect.origin.x + bottom_right_rect.size.width,
|
||||||
|
|
@ -609,7 +609,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// The cursor should be placed after the bottom_right glyph
|
// The cursor should be placed after the bottom_right glyph
|
||||||
(bottom_right_cursor, Px(0))
|
(bottom_right_cursor, Px::ZERO)
|
||||||
} else {
|
} else {
|
||||||
let before = &measured.glyphs[closest_before_index];
|
let before = &measured.glyphs[closest_before_index];
|
||||||
let after = &measured.glyphs[closest_after_index];
|
let after = &measured.glyphs[closest_after_index];
|
||||||
|
|
@ -617,7 +617,7 @@ where
|
||||||
let after_rect = after.rect();
|
let after_rect = after.rect();
|
||||||
let before_y = measured
|
let before_y = measured
|
||||||
.line_height
|
.line_height
|
||||||
.saturating_mul(Px(i32::try_from(before.info.line).unwrap_or(i32::MAX)));
|
.saturating_mul(Px::new(i32::try_from(before.info.line).unwrap_or(i32::MAX)));
|
||||||
|
|
||||||
if before.info.line == after.info.line {
|
if before.info.line == after.info.line {
|
||||||
let before_right = before_rect.origin.x + before_rect.size.width;
|
let before_right = before_rect.origin.x + before_rect.size.width;
|
||||||
|
|
@ -639,7 +639,10 @@ where
|
||||||
origin.x += before_rect.size.width;
|
origin.x += before_rect.size.width;
|
||||||
(origin, before_y)
|
(origin, before_y)
|
||||||
}
|
}
|
||||||
Affinity::After => (Point::new(Px(0), before_y + measured.line_height), Px(0)),
|
Affinity::After => (
|
||||||
|
Point::new(Px::ZERO, before_y + measured.line_height),
|
||||||
|
Px::ZERO,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -665,7 +668,7 @@ where
|
||||||
|
|
||||||
let mut closest: Option<(Cursor, i32)> = None;
|
let mut closest: Option<(Cursor, i32)> = None;
|
||||||
let mut current_line = usize::MAX;
|
let mut current_line = usize::MAX;
|
||||||
let mut current_line_y = Px(0);
|
let mut current_line_y = Px::ZERO;
|
||||||
for glyph in &cache.measured.glyphs {
|
for glyph in &cache.measured.glyphs {
|
||||||
if current_line != glyph.info.line {
|
if current_line != glyph.info.line {
|
||||||
current_line = glyph.info.line;
|
current_line = glyph.info.line;
|
||||||
|
|
@ -673,7 +676,7 @@ where
|
||||||
current_line_y = cache
|
current_line_y = cache
|
||||||
.measured
|
.measured
|
||||||
.line_height
|
.line_height
|
||||||
.saturating_mul(Px(i32::try_from(current_line).unwrap_or(i32::MAX)));
|
.saturating_mul(Px::new(i32::try_from(current_line).unwrap_or(i32::MAX)));
|
||||||
}
|
}
|
||||||
let rect = glyph.rect();
|
let rect = glyph.rect();
|
||||||
let relative = location - Point::new(rect.origin.x, current_line_y);
|
let relative = location - Point::new(rect.origin.x, current_line_y);
|
||||||
|
|
@ -704,7 +707,7 @@ where
|
||||||
|
|
||||||
// Make relative be relative to the center of the glyph for a nearest search.
|
// Make relative be relative to the center of the glyph for a nearest search.
|
||||||
let relative = relative + rect.size / 2;
|
let relative = relative + rect.size / 2;
|
||||||
let xy = (relative.x.0.saturating_mul(relative.y.0)).saturating_abs();
|
let xy = (relative.x.get().saturating_mul(relative.y.get())).saturating_abs();
|
||||||
match closest {
|
match closest {
|
||||||
Some((_, closest_xy)) if xy < closest_xy => {
|
Some((_, closest_xy)) if xy < closest_xy => {
|
||||||
closest = Some((
|
closest = Some((
|
||||||
|
|
@ -872,7 +875,7 @@ where
|
||||||
context.gfx.draw_shape(
|
context.gfx.draw_shape(
|
||||||
Shape::filled_rect(
|
Shape::filled_rect(
|
||||||
Rect::new(
|
Rect::new(
|
||||||
Point::new(Px(0), bottom_of_first_line),
|
Point::new(Px::ZERO, bottom_of_first_line),
|
||||||
Size::new(size.width.into_signed(), distance_between),
|
Size::new(size.width.into_signed(), distance_between),
|
||||||
),
|
),
|
||||||
highlight,
|
highlight,
|
||||||
|
|
@ -884,7 +887,7 @@ where
|
||||||
context.gfx.draw_shape(
|
context.gfx.draw_shape(
|
||||||
Shape::filled_rect(
|
Shape::filled_rect(
|
||||||
Rect::new(
|
Rect::new(
|
||||||
Point::new(Px(0), end_position.y),
|
Point::new(Px::ZERO, end_position.y),
|
||||||
Size::new(end_position.x + end_width, cache.measured.line_height),
|
Size::new(end_position.x + end_width, cache.measured.line_height),
|
||||||
),
|
),
|
||||||
highlight,
|
highlight,
|
||||||
|
|
@ -939,7 +942,7 @@ where
|
||||||
|
|
||||||
let cache = self.layout_text(Some(width.into_signed()), &mut context.graphics);
|
let cache = self.layout_text(Some(width.into_signed()), &mut context.graphics);
|
||||||
|
|
||||||
cache.measured.size.into_unsigned() + Size::new(padding * 2, padding * 2)
|
cache.measured.size.into_unsigned() + Size::squared(padding * 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keyboard_input(
|
fn keyboard_input(
|
||||||
|
|
|
||||||
|
|
@ -98,10 +98,7 @@ impl WrapperWidget for Resize {
|
||||||
let size = if let (Some(width), Some(height)) =
|
let size = if let (Some(width), Some(height)) =
|
||||||
(self.width.exact_dimension(), self.height.exact_dimension())
|
(self.width.exact_dimension(), self.height.exact_dimension())
|
||||||
{
|
{
|
||||||
Size::new(
|
Size::new(width, height).map(|i| i.into_upx(context.gfx.scale()))
|
||||||
width.into_upx(context.gfx.scale()),
|
|
||||||
height.into_upx(context.gfx.scale()),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
let available_space = Size::new(
|
let available_space = Size::new(
|
||||||
override_constraint(available_space.width, self.width, context.gfx.scale()),
|
override_constraint(available_space.width, self.width, context.gfx.scale()),
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ impl Widget for Scroll {
|
||||||
let max_scroll_x = if self.enabled.x {
|
let max_scroll_x = if self.enabled.x {
|
||||||
-self.horizontal_bar.amount_hidden
|
-self.horizontal_bar.amount_hidden
|
||||||
} else {
|
} else {
|
||||||
Px(0)
|
Px::ZERO
|
||||||
};
|
};
|
||||||
|
|
||||||
self.vertical_bar =
|
self.vertical_bar =
|
||||||
|
|
@ -194,7 +194,7 @@ impl Widget for Scroll {
|
||||||
let max_scroll_y = if self.enabled.y {
|
let max_scroll_y = if self.enabled.y {
|
||||||
-self.vertical_bar.amount_hidden
|
-self.vertical_bar.amount_hidden
|
||||||
} else {
|
} else {
|
||||||
Px(0)
|
Px::ZERO
|
||||||
};
|
};
|
||||||
let new_max_scroll = Point::new(max_scroll_x, max_scroll_y);
|
let new_max_scroll = Point::new(max_scroll_x, max_scroll_y);
|
||||||
if current_max_scroll != new_max_scroll {
|
if current_max_scroll != new_max_scroll {
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,9 @@ impl<T> Slider<T> {
|
||||||
value: value.into_dynamic(),
|
value: value.into_dynamic(),
|
||||||
minimum: min.into_value(),
|
minimum: min.into_value(),
|
||||||
maximum: max.into_value(),
|
maximum: max.into_value(),
|
||||||
knob_size: UPx(0),
|
knob_size: UPx::ZERO,
|
||||||
horizontal: true,
|
horizontal: true,
|
||||||
rendered_size: Px(0),
|
rendered_size: Px::ZERO,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -135,7 +135,7 @@ where
|
||||||
} else {
|
} else {
|
||||||
position.y
|
position.y
|
||||||
};
|
};
|
||||||
let position = position.clamp(Px(0), self.rendered_size);
|
let position = position.clamp(Px::ZERO, self.rendered_size);
|
||||||
let percent = position.into_float() / self.rendered_size.into_float();
|
let percent = position.into_float() / self.rendered_size.into_float();
|
||||||
let min = self.minimum.get();
|
let min = self.minimum.get();
|
||||||
let max = self.maximum.get();
|
let max = self.maximum.get();
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ impl Widget for Stack {
|
||||||
Rect::new(
|
Rect::new(
|
||||||
self.layout
|
self.layout
|
||||||
.orientation
|
.orientation
|
||||||
.make_point(layout.offset, UPx(0))
|
.make_point(layout.offset, UPx::ZERO)
|
||||||
.into_signed(),
|
.into_signed(),
|
||||||
self.layout
|
self.layout
|
||||||
.orientation
|
.orientation
|
||||||
|
|
@ -313,9 +313,9 @@ impl Layout {
|
||||||
orientation,
|
orientation,
|
||||||
children: OrderedLots::new(),
|
children: OrderedLots::new(),
|
||||||
layouts: Vec::new(),
|
layouts: Vec::new(),
|
||||||
other: UPx(0),
|
other: UPx::ZERO,
|
||||||
total_weights: 0,
|
total_weights: 0,
|
||||||
allocated_space: (UPx(0), Lp(0)),
|
allocated_space: (UPx::ZERO, Lp::ZERO),
|
||||||
fractional: Vec::new(),
|
fractional: Vec::new(),
|
||||||
fit_to_content: Vec::new(),
|
fit_to_content: Vec::new(),
|
||||||
premeasured: Vec::new(),
|
premeasured: Vec::new(),
|
||||||
|
|
@ -370,12 +370,12 @@ impl Layout {
|
||||||
let layout = match child {
|
let layout = match child {
|
||||||
StackDimension::FitContent => {
|
StackDimension::FitContent => {
|
||||||
self.fit_to_content.push(id);
|
self.fit_to_content.push(id);
|
||||||
UPx(0)
|
UPx::ZERO
|
||||||
}
|
}
|
||||||
StackDimension::Fractional { weight } => {
|
StackDimension::Fractional { weight } => {
|
||||||
self.total_weights += u32::from(weight);
|
self.total_weights += u32::from(weight);
|
||||||
self.fractional.push((id, weight));
|
self.fractional.push((id, weight));
|
||||||
UPx(0)
|
UPx::ZERO
|
||||||
}
|
}
|
||||||
StackDimension::Measured { min, .. } => {
|
StackDimension::Measured { min, .. } => {
|
||||||
self.premeasured.push(id);
|
self.premeasured.push(id);
|
||||||
|
|
@ -389,7 +389,7 @@ impl Layout {
|
||||||
self.layouts.insert(
|
self.layouts.insert(
|
||||||
index,
|
index,
|
||||||
StackLayout {
|
StackLayout {
|
||||||
offset: UPx(0),
|
offset: UPx::ZERO,
|
||||||
size: layout,
|
size: layout,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -412,7 +412,7 @@ impl Layout {
|
||||||
let needs_final_layout = !matches!(other_constraint, ConstraintLimit::Fill(_));
|
let needs_final_layout = !matches!(other_constraint, ConstraintLimit::Fill(_));
|
||||||
|
|
||||||
// Measure the children that fit their content
|
// Measure the children that fit their content
|
||||||
self.other = UPx(0);
|
self.other = UPx::ZERO;
|
||||||
for &id in &self.fit_to_content {
|
for &id in &self.fit_to_content {
|
||||||
let index = self.children.index_of_id(id).expect("child not found");
|
let index = self.children.index_of_id(id).expect("child not found");
|
||||||
let (measured, other) = self.orientation.split_size(measure(
|
let (measured, other) = self.orientation.split_size(measure(
|
||||||
|
|
@ -484,7 +484,7 @@ impl Layout {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Finally, compute the offsets of all of the widgets.
|
// Finally, compute the offsets of all of the widgets.
|
||||||
let mut offset = UPx(0);
|
let mut offset = UPx::ZERO;
|
||||||
for index in 0..self.children.len() {
|
for index in 0..self.children.len() {
|
||||||
self.layouts[index].offset = offset;
|
self.layouts[index].offset = offset;
|
||||||
offset += self.layouts[index].size;
|
offset += self.layouts[index].size;
|
||||||
|
|
@ -593,7 +593,7 @@ mod tests {
|
||||||
orientation.make_size(measured, other)
|
orientation.make_size(measured, other)
|
||||||
});
|
});
|
||||||
assert_eq!(computed_size, expected_size);
|
assert_eq!(computed_size, expected_size);
|
||||||
let mut offset = UPx(0);
|
let mut offset = UPx::ZERO;
|
||||||
for ((index, &child), &expected) in flex.iter().enumerate().zip(expected) {
|
for ((index, &child), &expected) in flex.iter().enumerate().zip(expected) {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
child.size,
|
child.size,
|
||||||
|
|
@ -635,11 +635,11 @@ mod tests {
|
||||||
fn size_to_fit() {
|
fn size_to_fit() {
|
||||||
assert_measured_children(
|
assert_measured_children(
|
||||||
&[Child::new(3, 1), Child::new(3, 1), Child::new(3, 1)],
|
&[Child::new(3, 1), Child::new(3, 1), Child::new(3, 1)],
|
||||||
ConstraintLimit::SizeToFit(UPx(10)),
|
ConstraintLimit::SizeToFit(UPx::new(10)),
|
||||||
ConstraintLimit::SizeToFit(UPx(10)),
|
ConstraintLimit::SizeToFit(UPx::new(10)),
|
||||||
&[UPx(3), UPx(3), UPx(3)],
|
&[UPx::new(3), UPx::new(3), UPx::new(3)],
|
||||||
UPx(9),
|
UPx::new(9),
|
||||||
UPx(1),
|
UPx::new(1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -660,11 +660,11 @@ mod tests {
|
||||||
Child::new(3, 1).weighted(1),
|
Child::new(3, 1).weighted(1),
|
||||||
Child::new(3, 1).weighted(1),
|
Child::new(3, 1).weighted(1),
|
||||||
],
|
],
|
||||||
ConstraintLimit::Fill(UPx(10)),
|
ConstraintLimit::Fill(UPx::new(10)),
|
||||||
ConstraintLimit::SizeToFit(UPx(10)),
|
ConstraintLimit::SizeToFit(UPx::new(10)),
|
||||||
&[UPx(4), UPx(3), UPx(3)],
|
&[UPx::new(4), UPx::new(3), UPx::new(3)],
|
||||||
UPx(10),
|
UPx::new(10),
|
||||||
UPx(7), // 20 / 3 = 6.666, rounded up is 7
|
UPx::new(7), // 20 / 3 = 6.666, rounded up is 7
|
||||||
);
|
);
|
||||||
// Same as above, but with an 11px box. This creates a leftover of 3 px
|
// Same as above, but with an 11px box. This creates a leftover of 3 px
|
||||||
// (11 % 4), adding 1px to all three children.
|
// (11 % 4), adding 1px to all three children.
|
||||||
|
|
@ -674,11 +674,11 @@ mod tests {
|
||||||
Child::new(3, 1).weighted(1),
|
Child::new(3, 1).weighted(1),
|
||||||
Child::new(3, 1).weighted(1),
|
Child::new(3, 1).weighted(1),
|
||||||
],
|
],
|
||||||
ConstraintLimit::Fill(UPx(11)),
|
ConstraintLimit::Fill(UPx::new(11)),
|
||||||
ConstraintLimit::SizeToFit(UPx(11)),
|
ConstraintLimit::SizeToFit(UPx::new(11)),
|
||||||
&[UPx(5), UPx(3), UPx(3)],
|
&[UPx::new(5), UPx::new(3), UPx::new(3)],
|
||||||
UPx(11),
|
UPx::new(11),
|
||||||
UPx(7), // 20 / 3 = 6.666, rounded up is 7
|
UPx::new(7), // 20 / 3 = 6.666, rounded up is 7
|
||||||
);
|
);
|
||||||
// 12px box. This creates no leftover.
|
// 12px box. This creates no leftover.
|
||||||
assert_measured_children(
|
assert_measured_children(
|
||||||
|
|
@ -687,11 +687,11 @@ mod tests {
|
||||||
Child::new(3, 1).weighted(1),
|
Child::new(3, 1).weighted(1),
|
||||||
Child::new(3, 1).weighted(1),
|
Child::new(3, 1).weighted(1),
|
||||||
],
|
],
|
||||||
ConstraintLimit::Fill(UPx(12)),
|
ConstraintLimit::Fill(UPx::new(12)),
|
||||||
ConstraintLimit::SizeToFit(UPx(12)),
|
ConstraintLimit::SizeToFit(UPx::new(12)),
|
||||||
&[UPx(6), UPx(3), UPx(3)],
|
&[UPx::new(6), UPx::new(3), UPx::new(3)],
|
||||||
UPx(12),
|
UPx::new(12),
|
||||||
UPx(4), // 20 / 6 = 3.666, rounded up is 4
|
UPx::new(4), // 20 / 6 = 3.666, rounded up is 4
|
||||||
);
|
);
|
||||||
// 13px box. This creates a leftover of 1 px (13 % 4), adding 1px only
|
// 13px box. This creates a leftover of 1 px (13 % 4), adding 1px only
|
||||||
// to the final child
|
// to the final child
|
||||||
|
|
@ -701,11 +701,11 @@ mod tests {
|
||||||
Child::new(3, 1).weighted(1),
|
Child::new(3, 1).weighted(1),
|
||||||
Child::new(3, 1).weighted(1),
|
Child::new(3, 1).weighted(1),
|
||||||
],
|
],
|
||||||
ConstraintLimit::Fill(UPx(13)),
|
ConstraintLimit::Fill(UPx::new(13)),
|
||||||
ConstraintLimit::SizeToFit(UPx(13)),
|
ConstraintLimit::SizeToFit(UPx::new(13)),
|
||||||
&[UPx(6), UPx(3), UPx(4)],
|
&[UPx::new(6), UPx::new(3), UPx::new(4)],
|
||||||
UPx(13),
|
UPx::new(13),
|
||||||
UPx(4), // 20 / 6 = 3.666, rounded up is 4
|
UPx::new(4), // 20 / 6 = 3.666, rounded up is 4
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -713,15 +713,15 @@ mod tests {
|
||||||
fn fixed_size() {
|
fn fixed_size() {
|
||||||
assert_measured_children(
|
assert_measured_children(
|
||||||
&[
|
&[
|
||||||
Child::new(3, 1).fixed_size(UPx(7)),
|
Child::new(3, 1).fixed_size(UPx::new(7)),
|
||||||
Child::new(3, 1).weighted(1),
|
Child::new(3, 1).weighted(1),
|
||||||
Child::new(3, 1).weighted(1),
|
Child::new(3, 1).weighted(1),
|
||||||
],
|
],
|
||||||
ConstraintLimit::Fill(UPx(15)),
|
ConstraintLimit::Fill(UPx::new(15)),
|
||||||
ConstraintLimit::SizeToFit(UPx(15)),
|
ConstraintLimit::SizeToFit(UPx::new(15)),
|
||||||
&[UPx(7), UPx(4), UPx(4)],
|
&[UPx::new(7), UPx::new(4), UPx::new(4)],
|
||||||
UPx(15),
|
UPx::new(15),
|
||||||
UPx(1),
|
UPx::new(1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -396,7 +396,7 @@ where
|
||||||
let min_width = resize
|
let min_width = resize
|
||||||
.width
|
.width
|
||||||
.minimum()
|
.minimum()
|
||||||
.map_or(Px(0), |width| width.into_px(graphics.scale()));
|
.map_or(Px::ZERO, |width| width.into_px(graphics.scale()));
|
||||||
let max_width = resize
|
let max_width = resize
|
||||||
.width
|
.width
|
||||||
.maximum()
|
.maximum()
|
||||||
|
|
@ -404,7 +404,7 @@ where
|
||||||
let min_height = resize
|
let min_height = resize
|
||||||
.height
|
.height
|
||||||
.minimum()
|
.minimum()
|
||||||
.map_or(Px(0), |height| height.into_px(graphics.scale()));
|
.map_or(Px::ZERO, |height| height.into_px(graphics.scale()));
|
||||||
let max_height = resize
|
let max_height = resize
|
||||||
.height
|
.height
|
||||||
.maximum()
|
.maximum()
|
||||||
|
|
@ -566,15 +566,9 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
let actual_size = layout_context.layout(if is_expanded {
|
let actual_size = layout_context.layout(if is_expanded {
|
||||||
Size::new(
|
window_size.map(ConstraintLimit::Fill)
|
||||||
ConstraintLimit::Fill(window_size.width),
|
|
||||||
ConstraintLimit::Fill(window_size.height),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
Size::new(
|
window_size.map(ConstraintLimit::SizeToFit)
|
||||||
ConstraintLimit::SizeToFit(window_size.width),
|
|
||||||
ConstraintLimit::SizeToFit(window_size.height),
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
let render_size = actual_size.min(window_size);
|
let render_size = actual_size.min(window_size);
|
||||||
if actual_size != window_size && !resizable {
|
if actual_size != window_size && !resizable {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue