Fixed odd padding rounding issues

The Container code was causing small rounding errors when laying out
that would cause the layout to sometimes me larger by a pixel. I
searched for all locations we are applying padding and added rounding
calls.

Refs #92
This commit is contained in:
Jonathan Johnson 2023-12-19 15:08:26 -08:00
parent c117b1527e
commit 27d5594776
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
6 changed files with 65 additions and 38 deletions

View file

@ -5,7 +5,7 @@ use std::time::Duration;
use kludgine::app::winit::event::{DeviceId, ElementState, KeyEvent, MouseButton};
use kludgine::app::winit::window::CursorIcon;
use kludgine::figures::units::{Lp, Px, UPx};
use kludgine::figures::{IntoSigned, Point, Rect, ScreenScale, Size};
use kludgine::figures::{IntoSigned, Point, Rect, Round, ScreenScale, Size};
use kludgine::shapes::{Shape, StrokeOptions};
use kludgine::Color;
@ -467,7 +467,10 @@ impl Widget for Button {
available_space: Size<crate::ConstraintLimit>,
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
) -> Size<UPx> {
let padding = context.get(&IntrinsicPadding).into_upx(context.gfx.scale());
let padding = context
.get(&IntrinsicPadding)
.into_upx(context.gfx.scale())
.round();
let double_padding = padding * 2;
let mounted = self.content.mounted(&mut context.as_event_context());
let available_space = available_space.map(|space| space - double_padding);

View file

@ -4,7 +4,7 @@ use std::ops::Div;
use kludgine::figures::units::{Lp, Px, UPx};
use kludgine::figures::{
Abs, Angle, IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size, Zero,
Abs, Angle, IntoSigned, IntoUnsigned, Point, Rect, Round, ScreenScale, Size, Zero,
};
use kludgine::shapes::{CornerRadii, PathBuilder, Shape};
use kludgine::Color;
@ -165,7 +165,7 @@ impl Container {
Some(padding) => padding.get(),
None => Edges::from(context.get(&IntrinsicPadding)),
}
.map(|dim| dim.into_px(context.gfx.scale()))
.map(|dim| dim.into_px(context.gfx.scale()).round())
}
fn effective_background_color(&mut self, context: &WidgetContext<'_, '_>) -> kludgine::Color {

View file

@ -155,7 +155,10 @@ impl<const COLUMNS: usize> Widget for Grid<COLUMNS> {
let content_size = self.layout.update(
available_space,
context.get(&IntrinsicPadding).into_upx(context.gfx.scale()),
context
.get(&IntrinsicPadding)
.into_upx(context.gfx.scale())
.round(),
context.gfx.scale(),
|row, column, constraints, persist| {
let mut context = context.for_other(&self.live_rows[column][row]);

View file

@ -15,7 +15,7 @@ use kludgine::app::winit::keyboard::{Key, NamedKey};
use kludgine::app::winit::window::{CursorIcon, ImePurpose};
use kludgine::figures::units::{Lp, Px, UPx};
use kludgine::figures::{
Abs, FloatConversion, IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size,
Abs, FloatConversion, IntoSigned, IntoUnsigned, Point, Rect, Round, ScreenScale, Size,
};
use kludgine::shapes::{Shape, StrokeOptions};
use kludgine::text::{MeasuredText, Text, TextOrigin};
@ -340,7 +340,8 @@ where
Self::point_from_cursor(&cache.measured, self.selection.cursor, cache.bytes);
position.y += context
.get(&IntrinsicPadding)
.into_px(context.kludgine.scale());
.into_px(context.kludgine.scale())
.round();
match affinity {
Affinity::Before => position.x = Px::ZERO,
Affinity::After => {
@ -361,7 +362,8 @@ where
position += Point::squared(
context
.get(&IntrinsicPadding)
.into_px(context.kludgine.scale()),
.into_px(context.kludgine.scale())
.round(),
);
if let Some(target_x) = self.line_navigation_x_target {
position.x = target_x;
@ -819,7 +821,8 @@ where
let padding = context
.get(&IntrinsicPadding)
.into_px(context.kludgine.scale());
.into_px(context.kludgine.scale())
.round();
let mut location = location - padding;
if location.y < 0 {
location.y = Px::ZERO;
@ -1029,8 +1032,11 @@ where
let cursor_state = self.blink_state;
let size = context.gfx.size();
let padding = context.get(&IntrinsicPadding).into_px(context.gfx.scale());
let padding = Point::<Px>::new(padding, padding);
let padding = context
.get(&IntrinsicPadding)
.into_px(context.gfx.scale())
.round();
let padding = Point::squared(padding);
let cache = self.layout_text(Some(size.width.into_signed()), context);
@ -1147,7 +1153,10 @@ where
available_space: Size<ConstraintLimit>,
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
) -> Size<UPx> {
let padding = context.get(&IntrinsicPadding).into_upx(context.gfx.scale());
let padding = context
.get(&IntrinsicPadding)
.into_upx(context.gfx.scale())
.round();
let width = available_space.width.max().saturating_sub(padding * 2);

View file

@ -1,7 +1,7 @@
//! A widget that combines a collection of [`Children`] widgets into one.
use kludgine::figures::units::UPx;
use kludgine::figures::{IntoSigned, Rect, ScreenScale, Size};
use kludgine::figures::{IntoSigned, Rect, Round, ScreenScale, Size};
use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContext};
use crate::styles::components::IntrinsicPadding;
@ -142,7 +142,8 @@ impl Widget for Stack {
FlexibleDimension::Auto => context.get(&IntrinsicPadding),
FlexibleDimension::Dimension(dimension) => dimension,
}
.into_upx(context.gfx.scale());
.into_upx(context.gfx.scale())
.round();
let content_size = self.layout.update(
available_space,

View file

@ -3,7 +3,7 @@
use intentional::Cast;
use kludgine::figures::units::{Px, UPx};
use kludgine::figures::{IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size, Zero};
use kludgine::figures::{IntoSigned, IntoUnsigned, Point, Rect, Round, ScreenScale, Size, Zero};
use crate::context::{AsEventContext, GraphicsContext, LayoutContext};
use crate::styles::components::{IntrinsicPadding, LayoutOrder};
@ -64,6 +64,36 @@ impl Wrap {
self.vertical_align = align.into_value();
self
}
fn horizontal_alignment(
align: WrapAlign,
order: HorizontalOrder,
remaining: Px,
row_children_len: usize,
) -> (Px, Px) {
match (align, order) {
(WrapAlign::Start, HorizontalOrder::LeftToRight)
| (WrapAlign::End, HorizontalOrder::RightToLeft) => (Px::ZERO, Px::ZERO),
(WrapAlign::End, HorizontalOrder::LeftToRight)
| (WrapAlign::Start, HorizontalOrder::RightToLeft) => (remaining, Px::ZERO),
(WrapAlign::Center, _) => (remaining / 2, Px::ZERO),
(WrapAlign::SpaceBetween, _) => {
if row_children_len > 1 {
(Px::ZERO, remaining / (row_children_len - 1).cast::<i32>())
} else {
(Px::ZERO, Px::ZERO)
}
}
(WrapAlign::SpaceEvenly, _) => {
let spacing = remaining / row_children_len.cast::<i32>();
(spacing / 2, spacing)
}
(WrapAlign::SpaceAround, _) => {
let spacing = remaining / (row_children_len + 1).cast::<i32>();
(spacing, spacing)
}
}
}
}
impl Widget for Wrap {
@ -73,6 +103,7 @@ impl Widget for Wrap {
}
}
#[allow(clippy::too_many_lines)]
fn layout(
&mut self,
available_space: Size<ConstraintLimit>,
@ -96,7 +127,8 @@ impl Widget for Wrap {
FlexibleDimension::Auto => context.get(&IntrinsicPadding),
FlexibleDimension::Dimension(dimension) => dimension,
})
.into_px(context.gfx.scale());
.into_px(context.gfx.scale())
.round();
self.mounted
.synchronize_with(&self.children, &mut context.as_event_context());
@ -144,28 +176,7 @@ impl Widget for Wrap {
// Calculate the horizontal alignment.
let remaining = (width - x).max(Px::ZERO);
let (x, space_between) = if remaining > 0 {
match (align, order) {
(WrapAlign::Start, HorizontalOrder::LeftToRight)
| (WrapAlign::End, HorizontalOrder::RightToLeft) => (Px::ZERO, Px::ZERO),
(WrapAlign::End, HorizontalOrder::LeftToRight)
| (WrapAlign::Start, HorizontalOrder::RightToLeft) => (remaining, Px::ZERO),
(WrapAlign::Center, _) => (remaining / 2, Px::ZERO),
(WrapAlign::SpaceBetween, _) => {
if row_children.len() > 1 {
(Px::ZERO, remaining / (row_children.len() - 1).cast::<i32>())
} else {
(Px::ZERO, Px::ZERO)
}
}
(WrapAlign::SpaceEvenly, _) => {
let spacing = remaining / row_children.len().cast::<i32>();
(spacing / 2, spacing)
}
(WrapAlign::SpaceAround, _) => {
let spacing = remaining / (row_children.len() + 1).cast::<i32>();
(spacing, spacing)
}
}
Self::horizontal_alignment(align, order, remaining, row_children.len())
} else {
(Px::ZERO, Px::ZERO)
};