mirror of
https://github.com/danbulant/cushy
synced 2026-06-14 20:11:04 +00:00
parent
9c1c77f9b1
commit
bb66803653
14 changed files with 952 additions and 20 deletions
120
examples/custom-widgets.rs
Normal file
120
examples/custom-widgets.rs
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
//! This example shows two approaches to writing custom widgets: implementing
|
||||
//! traits or using the [`Custom`] widget with callbacks.
|
||||
|
||||
use gooey::value::Dynamic;
|
||||
use gooey::widget::{MakeWidget, Widget, HANDLED};
|
||||
use gooey::widgets::Custom;
|
||||
use gooey::Run;
|
||||
use kludgine::figures::units::{Lp, UPx};
|
||||
use kludgine::figures::{ScreenScale, Size};
|
||||
use kludgine::Color;
|
||||
|
||||
fn main() -> gooey::Result {
|
||||
"Inline Widgets"
|
||||
.and(callback_widget())
|
||||
.into_rows()
|
||||
.and(
|
||||
"impl MakeWidget"
|
||||
.and(ToggleMakeWidget::default())
|
||||
.into_rows(),
|
||||
)
|
||||
.and("impl Widget".and(impl_widget()).into_rows())
|
||||
.into_columns()
|
||||
.centered()
|
||||
.expand()
|
||||
.run()
|
||||
}
|
||||
|
||||
/// This function returns a [`Custom`] widget that implements its functionality
|
||||
/// using callbacks.
|
||||
///
|
||||
/// This approach was added to make it easy to create one-off widgets in a
|
||||
/// hierarchy to handle events or other purpose-built functions.
|
||||
fn callback_widget() -> impl MakeWidget {
|
||||
// This implementation and the impl `Widget` implementation both use the
|
||||
// same Dynamic value setup.
|
||||
let toggle = Toggle::default();
|
||||
|
||||
Custom::empty()
|
||||
.background_color(toggle.color)
|
||||
.on_hit_test(|_, _| true)
|
||||
.on_mouse_down(move |_, _, _, _| {
|
||||
toggle.value.toggle();
|
||||
HANDLED
|
||||
})
|
||||
.height(Lp::inches(1))
|
||||
}
|
||||
|
||||
/// A second approach is to implement [`MakeWidget`] for a type. This allows any
|
||||
/// type to be used when composing your UI that know how to create a widget.
|
||||
///
|
||||
/// This enables using callback-based widgets (or any other combination of
|
||||
/// widgets) in a reusable fashion.
|
||||
#[derive(Default)]
|
||||
struct ToggleMakeWidget(Toggle);
|
||||
|
||||
impl MakeWidget for ToggleMakeWidget {
|
||||
fn make_widget(self) -> gooey::widget::WidgetInstance {
|
||||
// In a real code base, the contents of callback_widget() would go here
|
||||
callback_widget().make_widget()
|
||||
}
|
||||
}
|
||||
|
||||
/// This function returns [`Toggle`] using its [`Widget`] implementation.
|
||||
///
|
||||
/// This is the lowest-level way to implement a Widget, but it also provides the
|
||||
/// most power and flexibility.
|
||||
fn impl_widget() -> impl MakeWidget {
|
||||
Toggle::default()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Toggle {
|
||||
value: Dynamic<bool>,
|
||||
color: Dynamic<Color>,
|
||||
}
|
||||
|
||||
impl Default for Toggle {
|
||||
fn default() -> Self {
|
||||
let value = Dynamic::default();
|
||||
let color = value.map_each(|on| if *on { Color::RED } else { Color::BLUE });
|
||||
Self { value, color }
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for Toggle {
|
||||
fn redraw(&mut self, context: &mut gooey::context::GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
context.fill(self.color.get_tracking_refresh(context));
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
available_space: Size<gooey::ConstraintLimit>,
|
||||
context: &mut gooey::context::LayoutContext<'_, '_, '_, '_, '_>,
|
||||
) -> Size<UPx> {
|
||||
Size::new(
|
||||
available_space.width.min(),
|
||||
Lp::inches(1).into_upx(context.gfx.scale()),
|
||||
)
|
||||
}
|
||||
|
||||
fn hit_test(
|
||||
&mut self,
|
||||
_location: kludgine::figures::Point<kludgine::figures::units::Px>,
|
||||
_context: &mut gooey::context::EventContext<'_, '_>,
|
||||
) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn mouse_down(
|
||||
&mut self,
|
||||
_location: kludgine::figures::Point<kludgine::figures::units::Px>,
|
||||
_device_id: kludgine::app::winit::event::DeviceId,
|
||||
_button: kludgine::app::winit::event::MouseButton,
|
||||
_context: &mut gooey::context::EventContext<'_, '_>,
|
||||
) -> gooey::widget::EventHandling {
|
||||
self.value.toggle();
|
||||
|
||||
HANDLED
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ use kludgine::app::winit::event::{
|
|||
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
||||
};
|
||||
use kludgine::figures::units::{Lp, Px, UPx};
|
||||
use kludgine::figures::{IntoSigned, Point, Px2D, Rect, ScreenScale, Size, Zero};
|
||||
use kludgine::figures::{IntoSigned, Point, Px2D, Rect, Round, ScreenScale, Size, Zero};
|
||||
use kludgine::shapes::{Shape, StrokeOptions};
|
||||
use kludgine::{Color, Kludgine};
|
||||
|
||||
|
|
@ -610,7 +610,7 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> GraphicsContext<'context, 'window, '
|
|||
);
|
||||
|
||||
let background = self.get(&WidgetBackground);
|
||||
self.gfx.fill(background);
|
||||
self.fill(background);
|
||||
|
||||
self.apply_current_font_settings();
|
||||
|
||||
|
|
@ -707,7 +707,8 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> LayoutContext<'context, 'window, 'cl
|
|||
.clone()
|
||||
.lock()
|
||||
.as_widget()
|
||||
.layout(available_space, self);
|
||||
.layout(available_space, self)
|
||||
.map(Round::ceil);
|
||||
if self.persist_layout {
|
||||
self.graphics
|
||||
.current_node
|
||||
|
|
|
|||
10
src/lib.rs
10
src/lib.rs
|
|
@ -42,6 +42,16 @@ pub enum ConstraintLimit {
|
|||
}
|
||||
|
||||
impl ConstraintLimit {
|
||||
/// Returns `UPx::ZERO` when sizing to fit, otherwise it returns the size
|
||||
/// being filled.
|
||||
#[must_use]
|
||||
pub fn min(self) -> UPx {
|
||||
match self {
|
||||
ConstraintLimit::Fill(v) => v,
|
||||
ConstraintLimit::SizeToFit(_) => UPx::ZERO,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the maximum measurement that will fit the constraint.
|
||||
#[must_use]
|
||||
pub fn max(self) -> UPx {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ use crate::styles::{Dimension, FocusableWidgets, FontFamilyList, VisualOrder};
|
|||
/// use gooey::styles::Dimension;
|
||||
/// use gooey::styles::components::{SurfaceColor, TextColor};
|
||||
/// use gooey::kludgine::Color;
|
||||
/// use gooey::kludgine::figures::Zero;
|
||||
///
|
||||
/// define_components! {
|
||||
/// GroupName {
|
||||
|
|
|
|||
|
|
@ -132,8 +132,8 @@ impl Tree {
|
|||
|
||||
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()
|
||||
if constraints.width.max() <= cached_layout.constraints.width.max()
|
||||
&& constraints.height.max() <= cached_layout.constraints.height.max()
|
||||
{
|
||||
return Some(cached_layout.size);
|
||||
}
|
||||
|
|
|
|||
15
src/value.rs
15
src/value.rs
|
|
@ -3,7 +3,7 @@
|
|||
use std::cell::Cell;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::future::Future;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ops::{Deref, DerefMut, Not};
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex, MutexGuard, TryLockError};
|
||||
use std::task::{Poll, Waker};
|
||||
|
|
@ -134,6 +134,19 @@ impl<T> Dynamic<T> {
|
|||
self.0.map_mut(|value, _| map(value)).expect("deadlocked")
|
||||
}
|
||||
|
||||
/// Updates the value to the result of invoking [`Not`] on the current
|
||||
/// value. This function returns the new value.
|
||||
#[allow(clippy::must_use_candidate)]
|
||||
pub fn toggle(&self) -> T
|
||||
where
|
||||
T: Not<Output = T> + Clone,
|
||||
{
|
||||
self.map_mut(|value| {
|
||||
*value = !value.clone();
|
||||
value.clone()
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a new dynamic that is updated using `U::from(T.clone())` each
|
||||
/// time `self` is updated.
|
||||
#[must_use]
|
||||
|
|
|
|||
|
|
@ -42,11 +42,14 @@ pub trait Widget: Send + UnwindSafe + Debug + 'static {
|
|||
|
||||
/// Layout this widget and returns the ideal size based on its contents and
|
||||
/// the `available_space`.
|
||||
#[allow(unused_variables)]
|
||||
fn layout(
|
||||
&mut self,
|
||||
available_space: Size<ConstraintLimit>,
|
||||
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
||||
) -> Size<UPx>;
|
||||
) -> Size<UPx> {
|
||||
available_space.map(ConstraintLimit::min)
|
||||
}
|
||||
|
||||
/// Return true if this widget should expand to fill the window when it is
|
||||
/// the root widget.
|
||||
|
|
@ -250,7 +253,7 @@ pub trait WrapperWidget: Debug + Send + UnwindSafe + 'static {
|
|||
available_space: Size<ConstraintLimit>,
|
||||
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
||||
) -> WrappedLayout {
|
||||
let adjusted_space = self.adjust_child_constraint(available_space, context);
|
||||
let adjusted_space = self.adjust_child_constraints(available_space, context);
|
||||
let child = self.child_mut().mounted(&mut context.as_event_context());
|
||||
let size = context
|
||||
.for_other(&child)
|
||||
|
|
@ -263,7 +266,7 @@ pub trait WrapperWidget: Debug + Send + UnwindSafe + 'static {
|
|||
/// Returns the adjusted contraints to use when laying out the child.
|
||||
#[allow(unused_variables)]
|
||||
#[must_use]
|
||||
fn adjust_child_constraint(
|
||||
fn adjust_child_constraints(
|
||||
&mut self,
|
||||
available_space: Size<ConstraintLimit>,
|
||||
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
||||
|
|
@ -430,7 +433,7 @@ where
|
|||
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
let background_color = self.background_color(context);
|
||||
if let Some(color) = background_color {
|
||||
context.gfx.fill(color);
|
||||
context.fill(color);
|
||||
}
|
||||
|
||||
self.redraw_background(context);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ pub mod button;
|
|||
mod canvas;
|
||||
pub mod checkbox;
|
||||
pub mod container;
|
||||
mod custom;
|
||||
mod expand;
|
||||
pub mod input;
|
||||
pub mod label;
|
||||
|
|
@ -24,6 +25,7 @@ pub use button::Button;
|
|||
pub use canvas::Canvas;
|
||||
pub use checkbox::Checkbox;
|
||||
pub use container::Container;
|
||||
pub use custom::Custom;
|
||||
pub use expand::Expand;
|
||||
pub use input::Input;
|
||||
pub use label::Label;
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ impl WrapperWidget for Container {
|
|||
})
|
||||
}
|
||||
|
||||
fn adjust_child_constraint(
|
||||
fn adjust_child_constraints(
|
||||
&mut self,
|
||||
available_space: Size<ConstraintLimit>,
|
||||
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
||||
|
|
|
|||
779
src/widgets/custom.rs
Normal file
779
src/widgets/custom.rs
Normal file
|
|
@ -0,0 +1,779 @@
|
|||
use std::fmt::Debug;
|
||||
use std::panic::UnwindSafe;
|
||||
|
||||
use kludgine::app::winit::event::{
|
||||
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
||||
};
|
||||
use kludgine::figures::units::Px;
|
||||
use kludgine::figures::{Point, Size};
|
||||
use kludgine::Color;
|
||||
|
||||
use crate::context::{EventContext, GraphicsContext, LayoutContext, WidgetContext};
|
||||
use crate::value::{IntoValue, Value};
|
||||
use crate::widget::{EventHandling, MakeWidget, WidgetRef, WrappedLayout, WrapperWidget, IGNORED};
|
||||
use crate::widgets::Space;
|
||||
use crate::ConstraintLimit;
|
||||
|
||||
/// A callback-based custom widget.
|
||||
///
|
||||
/// This type can be used to create inline widgets without defining a new type
|
||||
/// and implementing [`Widget`]/[`WrapperWidget`] for it.
|
||||
#[must_use]
|
||||
pub struct Custom {
|
||||
child: WidgetRef,
|
||||
redraw_foreground: Option<Box<dyn RedrawFunc>>,
|
||||
redraw_background: Option<Box<dyn RedrawFunc>>,
|
||||
mounted: Option<Box<dyn EventFunc>>,
|
||||
unmounted: Option<Box<dyn EventFunc>>,
|
||||
background: Option<Value<Color>>,
|
||||
unhover: Option<Box<dyn EventFunc>>,
|
||||
focus: Option<Box<dyn EventFunc>>,
|
||||
blur: Option<Box<dyn EventFunc>>,
|
||||
activate: Option<Box<dyn EventFunc>>,
|
||||
deactivate: Option<Box<dyn EventFunc>>,
|
||||
accept_focus: Option<Box<dyn EventFunc<bool>>>,
|
||||
adjust_child: Option<Box<dyn AdjustChildConstraintsFunc>>,
|
||||
position_child: Option<Box<dyn PositionChildFunc>>,
|
||||
hit_test: Option<Box<dyn OneParamEventFunc<Point<Px>, bool>>>,
|
||||
hover: Option<Box<dyn OneParamEventFunc<Point<Px>>>>,
|
||||
mouse_down:
|
||||
Option<Box<dyn ThreeParamEventFunc<Point<Px>, DeviceId, MouseButton, EventHandling>>>,
|
||||
mouse_drag: Option<Box<dyn ThreeParamEventFunc<Point<Px>, DeviceId, MouseButton>>>,
|
||||
mouse_up: Option<Box<MouseUpFunc>>,
|
||||
ime: Option<Box<dyn OneParamEventFunc<Ime, EventHandling>>>,
|
||||
keyboard_input: Option<Box<dyn ThreeParamEventFunc<DeviceId, KeyEvent, bool, EventHandling>>>,
|
||||
mouse_wheel:
|
||||
Option<Box<dyn ThreeParamEventFunc<DeviceId, MouseScrollDelta, TouchPhase, EventHandling>>>,
|
||||
}
|
||||
|
||||
impl Debug for Custom {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Custom")
|
||||
.field("child", &self.child)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Custom {
|
||||
fn default() -> Self {
|
||||
Self::empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl Custom {
|
||||
/// Returns a custom widget that has no child.
|
||||
pub fn empty() -> Self {
|
||||
Self::new(Space::clear())
|
||||
}
|
||||
|
||||
/// Returns a custom widget that contains `child`.
|
||||
pub fn new(child: impl MakeWidget) -> Self {
|
||||
Self {
|
||||
child: WidgetRef::new(child),
|
||||
redraw_background: None,
|
||||
redraw_foreground: None,
|
||||
background: None,
|
||||
mounted: None,
|
||||
unmounted: None,
|
||||
unhover: None,
|
||||
focus: None,
|
||||
blur: None,
|
||||
activate: None,
|
||||
deactivate: None,
|
||||
accept_focus: None,
|
||||
adjust_child: None,
|
||||
position_child: None,
|
||||
hit_test: None,
|
||||
hover: None,
|
||||
mouse_down: None,
|
||||
mouse_drag: None,
|
||||
mouse_up: None,
|
||||
ime: None,
|
||||
keyboard_input: None,
|
||||
mouse_wheel: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the background color of this widget to `color` and returns self.
|
||||
///
|
||||
/// If the color is set to a non-transparent value, it will be filled before
|
||||
/// any of the redraw callbacks are invoked.
|
||||
///
|
||||
/// This value coresponds to [`WrapperWidget::background_color`].
|
||||
pub fn background_color(mut self, color: impl IntoValue<Color>) -> Self {
|
||||
self.background = Some(color.into_value());
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets `redraw` as the callback to invoke when redrawing this control.
|
||||
///
|
||||
/// If this control contains a child, its redraw function will be invoked
|
||||
/// after `redraw` is invoked. Use [`Self::on_redraw_after_child()`] to draw
|
||||
/// after the child widget.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::redraw_background`].
|
||||
pub fn on_redraw<Redraw>(mut self, redraw: Redraw) -> Self
|
||||
where
|
||||
Redraw: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window, 'clip, 'gfx, 'pass> FnMut(
|
||||
&mut GraphicsContext<'context, 'window, 'clip, 'gfx, 'pass>,
|
||||
),
|
||||
{
|
||||
self.redraw_background = Some(Box::new(redraw));
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets `redraw` as the callback to invoke when redrawing this control,
|
||||
/// after the child control has been redrawn.
|
||||
///
|
||||
/// If this control contains a child, its redraw function will be invoked
|
||||
/// before `redraw` is invoked. Use [`Self::on_redraw()`] to draw before the
|
||||
/// child widget.
|
||||
///
|
||||
/// `redraw` will be invoked regardless of whether a child is present.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::redraw_foreground`].
|
||||
pub fn on_redraw_after_child<Redraw>(mut self, redraw: Redraw) -> Self
|
||||
where
|
||||
Redraw: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window, 'clip, 'gfx, 'pass> FnMut(
|
||||
&mut GraphicsContext<'context, 'window, 'clip, 'gfx, 'pass>,
|
||||
),
|
||||
{
|
||||
self.redraw_foreground = Some(Box::new(redraw));
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets `mounted` to be invoked when this widget is mounted into a parent.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::mounted`].
|
||||
pub fn on_mounted<Mounted>(mut self, mounted: Mounted) -> Self
|
||||
where
|
||||
Mounted: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(&mut EventContext<'context, 'window>),
|
||||
{
|
||||
self.mounted = Some(Box::new(mounted));
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets `unmounted` to be invoked when this widget is unmounted from its
|
||||
/// parent.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::unmounted`].
|
||||
pub fn on_unmounted<Mounted>(mut self, mounted: Mounted) -> Self
|
||||
where
|
||||
Mounted: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(&mut EventContext<'context, 'window>),
|
||||
{
|
||||
self.unmounted = Some(Box::new(mounted));
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `unhovered` when the mouse cursor leaves the widget's boundary.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::unhover`].
|
||||
pub fn on_unhover<Unhover>(mut self, unhovered: Unhover) -> Self
|
||||
where
|
||||
Unhover: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(&mut EventContext<'context, 'window>),
|
||||
{
|
||||
self.unhover = Some(Box::new(unhovered));
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `focus` when the widget receives input focus.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::focus`].
|
||||
pub fn on_focus<Focused>(mut self, focus: Focused) -> Self
|
||||
where
|
||||
Focused: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(&mut EventContext<'context, 'window>),
|
||||
{
|
||||
self.focus = Some(Box::new(focus));
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `blur` when the widget loses input focus.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::blur`].
|
||||
pub fn on_blur<Blur>(mut self, blur: Blur) -> Self
|
||||
where
|
||||
Blur: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(&mut EventContext<'context, 'window>),
|
||||
{
|
||||
self.blur = Some(Box::new(blur));
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `activated` when this widget becomes the active widget.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::activate`].
|
||||
pub fn on_activate<Activated>(mut self, activated: Activated) -> Self
|
||||
where
|
||||
Activated: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(&mut EventContext<'context, 'window>),
|
||||
{
|
||||
self.activate = Some(Box::new(activated));
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `deactivated` when this widget no longer is the active widget.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::deactivate`].
|
||||
pub fn on_deactivate<Deactivated>(mut self, deactivated: Deactivated) -> Self
|
||||
where
|
||||
Deactivated: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(&mut EventContext<'context, 'window>),
|
||||
{
|
||||
self.deactivate = Some(Box::new(deactivated));
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `accept` when this widget is set to receive input focus. If this
|
||||
/// function returns true, this widget will become the focused widget.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::accept_focus`].
|
||||
pub fn on_accept_focus<AcceptFocus>(mut self, accept: AcceptFocus) -> Self
|
||||
where
|
||||
AcceptFocus: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(&mut EventContext<'context, 'window>) -> bool,
|
||||
{
|
||||
self.accept_focus = Some(Box::new(accept));
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `adjust_child_constraints` before measuring the child widget.
|
||||
/// The returned constraints will be passed along to the child in its layout
|
||||
/// function.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::adjust_child_constraints`].
|
||||
pub fn on_adjust_child_constraints<AdjustChildConstraints>(
|
||||
mut self,
|
||||
adjust_child_constraints: AdjustChildConstraints,
|
||||
) -> Self
|
||||
where
|
||||
AdjustChildConstraints: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window, 'clip, 'gfx, 'pass> FnMut(
|
||||
Size<ConstraintLimit>,
|
||||
&mut LayoutContext<'context, 'window, 'clip, 'gfx, 'pass>,
|
||||
) -> Size<ConstraintLimit>,
|
||||
{
|
||||
self.adjust_child = Some(Box::new(adjust_child_constraints));
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `position_child` to determine the position of a measured child.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::position_child`].
|
||||
pub fn on_position_child<PositionChild>(mut self, position_child: PositionChild) -> Self
|
||||
where
|
||||
PositionChild: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window, 'clip, 'gfx, 'pass> FnMut(
|
||||
Size<Px>,
|
||||
Size<ConstraintLimit>,
|
||||
&mut LayoutContext<'context, 'window, 'clip, 'gfx, 'pass>,
|
||||
) -> WrappedLayout,
|
||||
{
|
||||
self.position_child = Some(Box::new(position_child));
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `hit_test` when determining if a location should be considered
|
||||
/// interacting with this widget.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::hit_test`].
|
||||
pub fn on_hit_test<HitTest>(mut self, hit_test: HitTest) -> Self
|
||||
where
|
||||
HitTest: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(Point<Px>, &mut EventContext<'context, 'window>) -> bool,
|
||||
{
|
||||
self.hit_test = Some(Box::new(hit_test));
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `hover` when a mouse cursor is above this widget.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::hover`].
|
||||
pub fn on_hover<Hover>(mut self, hover: Hover) -> Self
|
||||
where
|
||||
Hover: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(Point<Px>, &mut EventContext<'context, 'window>),
|
||||
{
|
||||
self.hover = Some(Box::new(hover));
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `mouse_down` when a mouse button is pushed on a location where
|
||||
/// [`Self::on_hit_test`] returned true.
|
||||
///
|
||||
/// Returning [`HANDLED`](crate::widget::HANDLED) will set this widget as
|
||||
/// the handler for the [`DeviceId`] and [`MouseButton`]. Future mouse
|
||||
/// events for the same device and button will be sent to this widget's
|
||||
/// [`Self::on_mouse_drag`] and [`Self::on_mouse_up`] callbacks.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::mouse_down`].
|
||||
pub fn on_mouse_down<MouseDown>(mut self, mouse_down: MouseDown) -> Self
|
||||
where
|
||||
MouseDown: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(
|
||||
Point<Px>,
|
||||
DeviceId,
|
||||
MouseButton,
|
||||
&mut EventContext<'context, 'window>,
|
||||
) -> EventHandling,
|
||||
{
|
||||
self.mouse_down = Some(Box::new(mouse_down));
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `mouse_drag` when the mouse cursor moves while a tracked button
|
||||
/// is presed.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::mouse_drag`].
|
||||
pub fn on_mouse_drag<MouseDrag>(mut self, mouse_drag: MouseDrag) -> Self
|
||||
where
|
||||
MouseDrag: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(
|
||||
Point<Px>,
|
||||
DeviceId,
|
||||
MouseButton,
|
||||
&mut EventContext<'context, 'window>,
|
||||
),
|
||||
{
|
||||
self.mouse_drag = Some(Box::new(mouse_drag));
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `mouse_up` when a tracked mouse button is released.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::mouse_up`].
|
||||
pub fn on_mouse_up<MouseUp>(mut self, mouse_up: MouseUp) -> Self
|
||||
where
|
||||
MouseUp: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(
|
||||
Option<Point<Px>>,
|
||||
DeviceId,
|
||||
MouseButton,
|
||||
&mut EventContext<'context, 'window>,
|
||||
),
|
||||
{
|
||||
self.mouse_up = Some(Box::new(mouse_up));
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `ime` when an input manager event occurs.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::ime`].
|
||||
pub fn on_ime<OnIme>(mut self, ime: OnIme) -> Self
|
||||
where
|
||||
OnIme: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(Ime, &mut EventContext<'context, 'window>) -> EventHandling,
|
||||
{
|
||||
self.ime = Some(Box::new(ime));
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `keyboard_input` when a keyboard event occurs.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::keyboard_input`].
|
||||
pub fn on_keyboard_input<KeyboardInput>(mut self, keyboard_input: KeyboardInput) -> Self
|
||||
where
|
||||
KeyboardInput: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(
|
||||
DeviceId,
|
||||
KeyEvent,
|
||||
bool,
|
||||
&mut EventContext<'context, 'window>,
|
||||
) -> EventHandling,
|
||||
{
|
||||
self.keyboard_input = Some(Box::new(keyboard_input));
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `mouse_wheel` when a mouse wheel event occurs.
|
||||
///
|
||||
/// This callback corresponds to [`WrapperWidget::mouse_wheel`].
|
||||
pub fn mouse_wheel<MouseWheel>(mut self, mouse_wheel: MouseWheel) -> Self
|
||||
where
|
||||
MouseWheel: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(
|
||||
DeviceId,
|
||||
MouseScrollDelta,
|
||||
TouchPhase,
|
||||
&mut EventContext<'context, 'window>,
|
||||
) -> EventHandling,
|
||||
{
|
||||
self.mouse_wheel = Some(Box::new(mouse_wheel));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl WrapperWidget for Custom {
|
||||
fn child_mut(&mut self) -> &mut WidgetRef {
|
||||
&mut self.child
|
||||
}
|
||||
|
||||
fn redraw_background(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
if let Some(redraw) = &mut self.redraw_background {
|
||||
redraw.invoke(context);
|
||||
}
|
||||
}
|
||||
|
||||
fn redraw_foreground(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
if let Some(redraw) = &mut self.redraw_foreground {
|
||||
redraw.invoke(context);
|
||||
}
|
||||
}
|
||||
|
||||
fn adjust_child_constraints(
|
||||
&mut self,
|
||||
available_space: Size<ConstraintLimit>,
|
||||
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
||||
) -> Size<ConstraintLimit> {
|
||||
if let Some(adjust_child) = &mut self.adjust_child {
|
||||
adjust_child.invoke(available_space, context)
|
||||
} else {
|
||||
available_space
|
||||
}
|
||||
}
|
||||
|
||||
fn position_child(
|
||||
&mut self,
|
||||
size: Size<Px>,
|
||||
available_space: Size<ConstraintLimit>,
|
||||
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
||||
) -> WrappedLayout {
|
||||
if let Some(position_child) = &mut self.position_child {
|
||||
position_child.invoke(size, available_space, context)
|
||||
} else {
|
||||
Size::new(
|
||||
available_space
|
||||
.width
|
||||
.fit_measured(size.width, context.gfx.scale()),
|
||||
available_space
|
||||
.height
|
||||
.fit_measured(size.height, context.gfx.scale()),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
fn background_color(&mut self, context: &WidgetContext<'_, '_>) -> Option<Color> {
|
||||
self.background.as_ref().map(|bg| bg.get_tracked(context))
|
||||
}
|
||||
|
||||
fn mounted(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
if let Some(mounted) = &mut self.mounted {
|
||||
mounted.invoke(context);
|
||||
}
|
||||
}
|
||||
|
||||
fn unmounted(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
if let Some(unmounted) = &mut self.unmounted {
|
||||
unmounted.invoke(context);
|
||||
}
|
||||
}
|
||||
|
||||
fn hit_test(&mut self, location: Point<Px>, context: &mut EventContext<'_, '_>) -> bool {
|
||||
if let Some(hit_test) = &mut self.hit_test {
|
||||
hit_test.invoke(location, context)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn hover(&mut self, location: Point<Px>, context: &mut EventContext<'_, '_>) {
|
||||
if let Some(hover) = &mut self.hover {
|
||||
hover.invoke(location, context);
|
||||
}
|
||||
}
|
||||
|
||||
fn unhover(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
if let Some(unhover) = &mut self.unhover {
|
||||
unhover.invoke(context);
|
||||
}
|
||||
}
|
||||
|
||||
fn accept_focus(&mut self, context: &mut EventContext<'_, '_>) -> bool {
|
||||
if let Some(accept_focus) = &mut self.accept_focus {
|
||||
accept_focus.invoke(context)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn focus(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
if let Some(focus) = &mut self.focus {
|
||||
focus.invoke(context);
|
||||
}
|
||||
}
|
||||
|
||||
fn blur(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
if let Some(blur) = &mut self.blur {
|
||||
blur.invoke(context);
|
||||
}
|
||||
}
|
||||
|
||||
fn activate(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
if let Some(activate) = &mut self.activate {
|
||||
activate.invoke(context);
|
||||
}
|
||||
}
|
||||
|
||||
fn deactivate(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
if let Some(deactivate) = &mut self.deactivate {
|
||||
deactivate.invoke(context);
|
||||
}
|
||||
}
|
||||
|
||||
fn mouse_down(
|
||||
&mut self,
|
||||
location: Point<Px>,
|
||||
device_id: DeviceId,
|
||||
button: MouseButton,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) -> EventHandling {
|
||||
if let Some(mouse_down) = &mut self.mouse_down {
|
||||
mouse_down.invoke(location, device_id, button, context)
|
||||
} else {
|
||||
IGNORED
|
||||
}
|
||||
}
|
||||
|
||||
fn mouse_drag(
|
||||
&mut self,
|
||||
location: Point<Px>,
|
||||
device_id: DeviceId,
|
||||
button: MouseButton,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) {
|
||||
if let Some(mouse_drag) = &mut self.mouse_drag {
|
||||
mouse_drag.invoke(location, device_id, button, context);
|
||||
}
|
||||
}
|
||||
|
||||
fn mouse_up(
|
||||
&mut self,
|
||||
location: Option<Point<Px>>,
|
||||
device_id: DeviceId,
|
||||
button: MouseButton,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) {
|
||||
if let Some(mouse_up) = &mut self.mouse_up {
|
||||
mouse_up.invoke(location, device_id, button, context);
|
||||
}
|
||||
}
|
||||
|
||||
fn keyboard_input(
|
||||
&mut self,
|
||||
device_id: DeviceId,
|
||||
input: KeyEvent,
|
||||
is_synthetic: bool,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) -> EventHandling {
|
||||
if let Some(keyboard_input) = &mut self.keyboard_input {
|
||||
keyboard_input.invoke(device_id, input, is_synthetic, context)
|
||||
} else {
|
||||
IGNORED
|
||||
}
|
||||
}
|
||||
|
||||
fn ime(&mut self, ime: Ime, context: &mut EventContext<'_, '_>) -> EventHandling {
|
||||
if let Some(f) = &mut self.ime {
|
||||
f.invoke(ime, context)
|
||||
} else {
|
||||
IGNORED
|
||||
}
|
||||
}
|
||||
|
||||
fn mouse_wheel(
|
||||
&mut self,
|
||||
device_id: DeviceId,
|
||||
delta: MouseScrollDelta,
|
||||
phase: TouchPhase,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) -> EventHandling {
|
||||
if let Some(mouse_wheel) = &mut self.mouse_wheel {
|
||||
mouse_wheel.invoke(device_id, delta, phase, context)
|
||||
} else {
|
||||
IGNORED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait RedrawFunc: Send + UnwindSafe {
|
||||
fn invoke(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>);
|
||||
}
|
||||
|
||||
impl<Func> RedrawFunc for Func
|
||||
where
|
||||
Func: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window, 'clip, 'gfx, 'pass> FnMut(
|
||||
&mut GraphicsContext<'context, 'window, 'clip, 'gfx, 'pass>,
|
||||
),
|
||||
{
|
||||
fn invoke(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
self(context);
|
||||
}
|
||||
}
|
||||
|
||||
trait AdjustChildConstraintsFunc: Send + UnwindSafe {
|
||||
fn invoke(
|
||||
&mut self,
|
||||
available_space: Size<ConstraintLimit>,
|
||||
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
||||
) -> Size<ConstraintLimit>;
|
||||
}
|
||||
|
||||
impl<Func> AdjustChildConstraintsFunc for Func
|
||||
where
|
||||
Func: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window, 'clip, 'gfx, 'pass> FnMut(
|
||||
Size<ConstraintLimit>,
|
||||
&mut LayoutContext<'context, 'window, 'clip, 'gfx, 'pass>,
|
||||
) -> Size<ConstraintLimit>,
|
||||
{
|
||||
fn invoke(
|
||||
&mut self,
|
||||
available_space: Size<ConstraintLimit>,
|
||||
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
||||
) -> Size<ConstraintLimit> {
|
||||
self(available_space, context)
|
||||
}
|
||||
}
|
||||
|
||||
trait PositionChildFunc: Send + UnwindSafe {
|
||||
fn invoke(
|
||||
&mut self,
|
||||
size: Size<Px>,
|
||||
available_space: Size<ConstraintLimit>,
|
||||
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
||||
) -> WrappedLayout;
|
||||
}
|
||||
|
||||
impl<Func> PositionChildFunc for Func
|
||||
where
|
||||
Func: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window, 'clip, 'gfx, 'pass> FnMut(
|
||||
Size<Px>,
|
||||
Size<ConstraintLimit>,
|
||||
&mut LayoutContext<'context, 'window, 'clip, 'gfx, 'pass>,
|
||||
) -> WrappedLayout,
|
||||
{
|
||||
fn invoke(
|
||||
&mut self,
|
||||
size: Size<Px>,
|
||||
available_space: Size<ConstraintLimit>,
|
||||
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
||||
) -> WrappedLayout {
|
||||
self(size, available_space, context)
|
||||
}
|
||||
}
|
||||
|
||||
trait EventFunc<R = ()>: Send + UnwindSafe {
|
||||
fn invoke(&mut self, context: &mut EventContext<'_, '_>) -> R;
|
||||
}
|
||||
|
||||
impl<R, Func> EventFunc<R> for Func
|
||||
where
|
||||
Func: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(&mut EventContext<'context, 'window>) -> R,
|
||||
{
|
||||
fn invoke(&mut self, context: &mut EventContext<'_, '_>) -> R {
|
||||
self(context)
|
||||
}
|
||||
}
|
||||
|
||||
trait OneParamEventFunc<P, R = ()>: Send + UnwindSafe {
|
||||
fn invoke(&mut self, param: P, context: &mut EventContext<'_, '_>) -> R;
|
||||
}
|
||||
|
||||
impl<P, R, Func> OneParamEventFunc<P, R> for Func
|
||||
where
|
||||
Func: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(P, &mut EventContext<'context, 'window>) -> R,
|
||||
{
|
||||
fn invoke(&mut self, location: P, context: &mut EventContext<'_, '_>) -> R {
|
||||
self(location, context)
|
||||
}
|
||||
}
|
||||
|
||||
trait ThreeParamEventFunc<P1, P2, P3, R = ()>: Send + UnwindSafe {
|
||||
fn invoke(
|
||||
&mut self,
|
||||
location: P1,
|
||||
device_id: P2,
|
||||
button: P3,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) -> R;
|
||||
}
|
||||
|
||||
type MouseUpFunc = dyn ThreeParamEventFunc<Option<Point<Px>>, DeviceId, MouseButton>;
|
||||
|
||||
impl<P1, P2, P3, R, Func> ThreeParamEventFunc<P1, P2, P3, R> for Func
|
||||
where
|
||||
Func: Send
|
||||
+ UnwindSafe
|
||||
+ 'static
|
||||
+ for<'context, 'window> FnMut(P1, P2, P3, &mut EventContext<'context, 'window>) -> R,
|
||||
{
|
||||
fn invoke(
|
||||
&mut self,
|
||||
location: P1,
|
||||
device_id: P2,
|
||||
button: P3,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) -> R {
|
||||
self(location, device_id, button, context)
|
||||
}
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ impl Label {
|
|||
if *prepared_generation == check_generation
|
||||
&& *prepared_color == color
|
||||
&& (*prepared_width == width
|
||||
|| (*prepared_width < width
|
||||
|| ((*prepared_width < width || prepared.size.width <= width)
|
||||
&& prepared.line_height == prepared.size.height)) => {}
|
||||
_ => {
|
||||
let measured = self.text.map(|text| {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ impl Widget for Space {
|
|||
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
self.color.redraw_when_changed(context);
|
||||
let color = self.color.get();
|
||||
context.gfx.fill(color);
|
||||
context.fill(color);
|
||||
}
|
||||
|
||||
fn layout(
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ use std::ops::{Bound, Deref};
|
|||
|
||||
use alot::{LotId, OrderedLots};
|
||||
use kludgine::figures::units::{Lp, UPx};
|
||||
use kludgine::figures::{Fraction, IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size};
|
||||
use kludgine::figures::{
|
||||
Fraction, IntoSigned, IntoUnsigned, Point, Rect, Round, ScreenScale, Size,
|
||||
};
|
||||
|
||||
use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContext};
|
||||
use crate::styles::Dimension;
|
||||
|
|
@ -343,7 +345,7 @@ impl Layout {
|
|||
self.premeasured.retain(|&measured| measured != id);
|
||||
match min {
|
||||
Dimension::Px(pixels) => {
|
||||
self.allocated_space.0 -= pixels.into_unsigned();
|
||||
self.allocated_space.0 -= pixels.into_unsigned().ceil();
|
||||
}
|
||||
Dimension::Lp(lp) => {
|
||||
self.allocated_space.1 -= lp;
|
||||
|
|
@ -403,7 +405,8 @@ impl Layout {
|
|||
) -> Size<UPx> {
|
||||
let (space_constraint, other_constraint) = self.orientation.split_size(available);
|
||||
let available_space = space_constraint.max();
|
||||
let allocated_space = self.allocated_space.0 + self.allocated_space.1.into_upx(scale);
|
||||
let allocated_space =
|
||||
self.allocated_space.0 + self.allocated_space.1.into_upx(scale).ceil();
|
||||
let mut remaining = available_space.saturating_sub(allocated_space);
|
||||
// If our `other_constraint` is not known, we will need to give child
|
||||
// widgets an opportunity to lay themselves out in the full area. This
|
||||
|
|
@ -442,8 +445,8 @@ impl Layout {
|
|||
|
||||
// Measure the weighted children within the remaining space
|
||||
if self.total_weights > 0 {
|
||||
let space_per_weight = remaining / self.total_weights;
|
||||
remaining %= self.total_weights;
|
||||
let space_per_weight = (remaining / self.total_weights).floor();
|
||||
remaining -= space_per_weight * self.total_weights;
|
||||
for (fractional_index, &(id, weight)) in self.fractional.iter().enumerate() {
|
||||
let index = self.children.index_of_id(id).expect("child not found");
|
||||
let mut size = space_per_weight * u32::from(weight);
|
||||
|
|
@ -453,7 +456,7 @@ impl Layout {
|
|||
let from_end = u32::try_from(self.fractional.len() - fractional_index)
|
||||
.expect("too many items");
|
||||
if remaining >= from_end {
|
||||
let amount = (remaining + from_end - 1) / from_end;
|
||||
let amount = (remaining / from_end).ceil().min(remaining);
|
||||
remaining -= amount;
|
||||
size += amount;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ impl WrapperWidget for Switcher {
|
|||
}
|
||||
|
||||
// TODO this should be moved to an invalidated() event once we have it.
|
||||
fn adjust_child_constraint(
|
||||
fn adjust_child_constraints(
|
||||
&mut self,
|
||||
available_space: Size<ConstraintLimit>,
|
||||
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
||||
|
|
|
|||
Loading…
Reference in a new issue