Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Baseline Vertical Alignment #227

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions examples/custom-widgets.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
//! This example shows two approaches to writing custom widgets: implementing
//! traits or using the [`Custom`] widget with callbacks.

use cushy::figures::units::{Lp, UPx};
use cushy::figures::units::Lp;
use cushy::figures::{ScreenScale, Size};
use cushy::kludgine::Color;
use cushy::value::{Destination, Dynamic, Source};
use cushy::widget::{MakeWidget, MakeWidgetWithTag, Widget, WidgetInstance, WidgetTag, HANDLED};
use cushy::widget::{
MakeWidget, MakeWidgetWithTag, Widget, WidgetInstance, WidgetLayout, WidgetTag, HANDLED,
};
use cushy::widgets::Custom;
use cushy::window::DeviceId;
use cushy::Run;
Expand Down Expand Up @@ -95,11 +97,12 @@ impl Widget for Toggle {
&mut self,
available_space: Size<cushy::ConstraintLimit>,
context: &mut cushy::context::LayoutContext<'_, '_, '_, '_>,
) -> Size<UPx> {
) -> WidgetLayout {
Size::new(
available_space.width.min(),
Lp::inches(1).into_upx(context.gfx.scale()),
)
.into()
}

fn hit_test(
Expand Down
5 changes: 5 additions & 0 deletions examples/wrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ fn main() -> cushy::Result {
.new_radio(VerticalAlign::Top)
.labelled_by("Top"),
)
.and(
vertical_align
.new_radio(VerticalAlign::Baseline)
.labelled_by("Baseline"),
)
.and(
vertical_align
.new_radio(VerticalAlign::Center)
Expand Down
17 changes: 10 additions & 7 deletions guide/guide-examples/examples/composition-widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use cushy::figures::{IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size, Z
use cushy::kludgine::text::{MeasuredText, TextOrigin};
use cushy::styles::components::IntrinsicPadding;
use cushy::value::{Dynamic, IntoValue, Value};
use cushy::widget::Widget;
use cushy::widget::{Widget, WidgetLayout};
use cushy::widgets::input::InputValue;
use cushy::ConstraintLimit;

Expand Down Expand Up @@ -51,34 +51,37 @@ fn composition_widget() -> impl cushy::widget::MakeWidget {
&mut self,
available_space: Size<ConstraintLimit>,
context: &mut LayoutContext<'_, '_, '_, '_>,
) -> Size<UPx> {
) -> WidgetLayout {
let label_and_padding = self.label_and_padding_size(context);
let field_available_space = Size::new(
available_space.width,
available_space.height - label_and_padding.height,
);
let field = self.field.mounted(context);
let field_size = context.for_other(&field).layout(field_available_space);
let field_layout = context.for_other(&field).layout(field_available_space);

let full_size = Size::new(
available_space
.width
.min()
.max(field_size.width)
.max(field_layout.size.width)
.max(label_and_padding.width),
field_size.height + label_and_padding.height,
field_layout.size.height + label_and_padding.height,
);

context.set_child_layout(
&field,
Rect::new(
Point::new(UPx::ZERO, label_and_padding.height),
Size::new(full_size.width, field_size.height),
Size::new(full_size.width, field_layout.size.height),
)
.into_signed(),
);

full_size
WidgetLayout {
size: full_size,
baseline: field_layout.baseline,
}
}

// ANCHOR_END: widget-a
Expand Down
11 changes: 6 additions & 5 deletions guide/guide-examples/examples/composition-wrapperwidget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use cushy::figures::{IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size, Z
use cushy::kludgine::text::{MeasuredText, TextOrigin};
use cushy::styles::components::IntrinsicPadding;
use cushy::value::{Dynamic, IntoValue, Value};
use cushy::widget::{WrappedLayout, WrapperWidget};
use cushy::widget::{WidgetLayout, WrappedLayout, WrapperWidget};
use cushy::widgets::input::InputValue;
use cushy::ConstraintLimit;

Expand Down Expand Up @@ -75,7 +75,7 @@ fn composition_wrapperwidget() -> impl cushy::widget::MakeWidget {
// ANCHOR: wrapperwidget-c
fn position_child(
&mut self,
child_size: Size<Px>,
child_layout: WidgetLayout,
available_space: Size<ConstraintLimit>,
context: &mut LayoutContext<'_, '_, '_, '_>,
) -> WrappedLayout {
Expand All @@ -84,17 +84,18 @@ fn composition_wrapperwidget() -> impl cushy::widget::MakeWidget {
available_space
.width
.min()
.max(child_layout.size.width)
.into_signed()
.max(child_size.width)
.max(label_and_padding.width),
child_size.height + label_and_padding.height,
child_layout.size.height.into_signed() + label_and_padding.height,
);
WrappedLayout {
child: Rect::new(
Point::new(Px::ZERO, label_and_padding.height),
Size::new(full_size.width, child_size.height),
Size::new(full_size.width, child_layout.size.height.into_signed()),
),
size: full_size.into_unsigned(),
baseline: child_layout.baseline,
}
}

Expand Down
8 changes: 5 additions & 3 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ use crate::styles::components::{
use crate::styles::{ComponentDefinition, FontFamilyList, Styles, Theme, ThemePair};
use crate::tree::Tree;
use crate::value::{IntoValue, Source, Value};
use crate::widget::{EventHandling, MountedWidget, RootBehavior, WidgetId, WidgetInstance};
use crate::widget::{
EventHandling, MountedWidget, RootBehavior, WidgetId, WidgetInstance, WidgetLayout,
};
use crate::window::{
CursorState, DeviceId, KeyEvent, PlatformWindow, ThemeMode, WidgetCursorState,
};
Expand Down Expand Up @@ -809,7 +811,7 @@ impl<'context, 'clip, 'gfx, 'pass> LayoutContext<'context, 'clip, 'gfx, 'pass> {

/// Invokes [`Widget::layout()`](crate::widget::Widget::layout) on this
/// context's widget and returns the result.
pub fn layout(&mut self, available_space: Size<ConstraintLimit>) -> Size<UPx> {
pub fn layout(&mut self, available_space: Size<ConstraintLimit>) -> WidgetLayout {
if self.persist_layout {
if let Some(cached) = self.graphics.current_node.begin_layout(available_space) {
return cached;
Expand All @@ -822,7 +824,7 @@ impl<'context, 'clip, 'gfx, 'pass> LayoutContext<'context, 'clip, 'gfx, 'pass> {
.lock()
.as_widget()
.layout(available_space, self)
.map(Round::ceil);
.ceil();
if self.persist_layout {
self.graphics
.current_node
Expand Down
14 changes: 9 additions & 5 deletions src/styles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2797,12 +2797,15 @@ impl HorizontalAlign {
/// within `available_space`.
pub fn alignment_offset<Unit>(self, measured: Unit, available_space: Unit) -> Unit
where
Unit: Sub<Output = Unit> + Mul<Output = Unit> + UnscaledUnit + Zero,
Unit::Representation: CastFrom<i32>,
Unit: Sub<Output = Unit> + Mul<Output = Unit> + UnscaledUnit + Zero + Round,
Unit::Representation: Div<Output = Unit::Representation> + From<u8>,
{
match self {
Self::Left => Unit::ZERO,
Self::Center => (available_space - measured) * Unit::from_unscaled(2.cast_into()),
Self::Center => Unit::from_unscaled(
(available_space - measured).into_unscaled() / <Unit::Representation>::from(2),
)
.round(),
Self::Right => available_space - measured,
}
}
Expand Down Expand Up @@ -2835,8 +2838,9 @@ impl RequireInvalidation for HorizontalAlign {
#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
pub enum VerticalAlign {
/// Align towards the top.
#[default] // TODO this should be baseline, not top.
Top,
#[default]
Baseline,
/// Align towards the center/middle.
Center,
/// Align towards the bottom.
Expand All @@ -2852,7 +2856,7 @@ impl VerticalAlign {
Unit::Representation: CastFrom<i32>,
{
match self {
Self::Top => Unit::ZERO,
Self::Top | Self::Baseline => Unit::ZERO,
Self::Center => (available_space - measured) * Unit::from_unscaled(2.cast_into()),
Self::Bottom => available_space - measured,
}
Expand Down
17 changes: 10 additions & 7 deletions src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ use std::sync::{Arc, Weak};

use ahash::AHashMap;
use alot::{LotId, Lots};
use figures::units::{Px, UPx};
use figures::units::Px;
use figures::{Point, Rect, Size};
use parking_lot::Mutex;

use crate::styles::{Styles, ThemePair, VisualOrder};
use crate::value::Value;
use crate::widget::{MountedWidget, WidgetId, WidgetInstance};
use crate::widget::{MountedWidget, WidgetId, WidgetInstance, WidgetLayout};
use crate::window::{ThemeMode, WindowHandle};
use crate::ConstraintLimit;

Expand Down Expand Up @@ -121,15 +121,15 @@ impl Tree {
&self,
parent: LotId,
constraints: Size<ConstraintLimit>,
) -> Option<Size<UPx>> {
) -> Option<WidgetLayout> {
let mut data = self.data.lock();

let node = &mut data.nodes[parent];
if let Some(cached_layout) = &node.last_layout_query {
if constraints.width.max() <= cached_layout.constraints.width.max()
&& constraints.height.max() <= cached_layout.constraints.height.max()
{
return Some(cached_layout.size);
return Some(cached_layout.layout);
}

node.last_layout_query = None;
Expand All @@ -147,10 +147,13 @@ impl Tree {
&self,
id: LotId,
constraints: Size<ConstraintLimit>,
size: Size<UPx>,
size: WidgetLayout,
) {
let mut data = self.data.lock();
data.nodes[id].last_layout_query = Some(CachedLayoutQuery { constraints, size });
data.nodes[id].last_layout_query = Some(CachedLayoutQuery {
constraints,
layout: size,
});
}

pub(crate) fn visually_ordered_children(
Expand Down Expand Up @@ -655,7 +658,7 @@ impl Node {

struct CachedLayoutQuery {
constraints: Size<ConstraintLimit>,
size: Size<UPx>,
layout: WidgetLayout,
}

#[derive(Clone, Debug)]
Expand Down
Loading
Loading