Vertical sliders/progress bars

Also fixed checkbox layout after Label no longer pads itself.
This commit is contained in:
Jonathan Johnson 2023-11-21 20:41:56 -08:00
parent eee336eab0
commit 46a0758d09
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
6 changed files with 109 additions and 121 deletions

2
Cargo.lock generated
View file

@ -643,7 +643,7 @@ dependencies = [
[[package]]
name = "figures"
version = "0.1.0"
source = "git+https://github.com/khonsulabs/figures#40045fa1940f6212bc4876a4ef9ae2cd0bd89808"
source = "git+https://github.com/khonsulabs/figures#4de8f5965bc7f9fc12369b2af93068e9da7a2446"
dependencies = [
"bytemuck",
"euclid",

View file

@ -4,6 +4,8 @@ use gooey::widgets::progress::Progressable;
use gooey::widgets::slider::Slidable;
use gooey::widgets::Checkbox;
use gooey::Run;
use kludgine::figures::units::Lp;
use kludgine::figures::Size;
fn main() -> gooey::Result {
let indeterminant = Dynamic::new(false);
@ -12,10 +14,18 @@ fn main() -> gooey::Result {
.map_each(|(&indeterminant, &value)| (!indeterminant).then_some(value));
value
.clone()
.slider()
.and(progress.progress_bar())
.and(progress.clone().progress_bar())
.and(Checkbox::new(indeterminant.clone(), "Indeterminant"))
.into_rows()
.fit_horizontally()
.expand()
.and(value.slider())
.and(progress.progress_bar())
.into_columns()
.pad()
.size(Size::squared(Lp::inches(3)))
.centered()
.expand()
.run()

View file

@ -708,6 +708,15 @@ pub trait MakeWidget: Sized {
Expand::horizontal(self)
}
/// Resizes `self` to `size`.
#[must_use]
fn size<T>(self, size: Size<T>) -> Resize
where
T: Into<DimensionRange>,
{
Resize::to(size, self)
}
/// Resizes `self` to `width`.
///
/// `width` can be an any of:

View file

@ -159,10 +159,15 @@ impl WrapperWidget for CheckboxLabel {
) -> WrappedLayout {
let checkbox_size = context.get(&LineHeight).into_px(context.gfx.scale()); // TODO create a component?
let padding = context.get(&IntrinsicPadding).into_px(context.gfx.scale());
let label_inset = checkbox_size + padding;
let size_with_checkbox = Size::new(size.width + label_inset, size.height).into_unsigned();
let label_inset = checkbox_size + padding * 2;
let effective_height = size.height.max(label_inset);
let size_with_checkbox =
Size::new(size.width + label_inset + padding, effective_height).into_unsigned();
WrappedLayout {
child: Rect::new(Point::new(label_inset, Px::ZERO), size),
child: Rect::new(
Point::new(label_inset, Px::ZERO),
Size::new(size.width, effective_height),
),
size: size_with_checkbox,
}
}

View file

@ -5,7 +5,7 @@ use std::time::Duration;
use kludgine::figures::Ranged;
use crate::animation::easings::EaseInOutSine;
use crate::animation::easings::EaseInOutQuadradic;
use crate::animation::{
AnimationHandle, AnimationTarget, IntoAnimate, PercentBetween, Spawn, ZeroToOne,
};
@ -82,37 +82,39 @@ fn update_progress_bar(
) {
match progress {
Progress::Indeterminant => {
*indeterminant_animation = Some(
end.transition_to(ZeroToOne::new(0.66))
.over(Duration::from_millis(500))
.with_easing(EaseInOutSine)
.and_then(
start
.transition_to(ZeroToOne::new(0.33))
.over(Duration::from_millis(500))
.with_easing(EaseInOutSine),
if indeterminant_animation.is_none() {
*indeterminant_animation = Some(
(
start.transition_to(ZeroToOne::ZERO),
end.transition_to(ZeroToOne::ZERO),
)
.and_then(
end.transition_to(ZeroToOne::ONE)
.over(Duration::from_millis(500))
.with_easing(EaseInOutSine),
)
.and_then(
start
.transition_to(ZeroToOne::ONE)
.over(Duration::from_millis(500))
.with_easing(EaseInOutSine),
)
.and_then(
(
start.transition_to(ZeroToOne::ZERO),
end.transition_to(ZeroToOne::ZERO),
.over(Duration::ZERO)
.and_then(
end.transition_to(ZeroToOne::new(0.66))
.over(Duration::from_millis(500))
.with_easing(EaseInOutQuadradic),
)
.over(Duration::ZERO),
)
.cycle()
.spawn(),
);
.and_then(
start
.transition_to(ZeroToOne::new(0.33))
.over(Duration::from_millis(500))
.with_easing(EaseInOutQuadradic),
)
.and_then(
end.transition_to(ZeroToOne::ONE)
.over(Duration::from_millis(500))
.with_easing(EaseInOutQuadradic),
)
.and_then(
start
.transition_to(ZeroToOne::ONE)
.over(Duration::from_millis(500))
.with_easing(EaseInOutQuadradic),
)
.cycle()
.spawn(),
);
}
}
Progress::Percent(value) => {
let _stopped_animation = indeterminant_animation.take();

View file

@ -9,8 +9,7 @@ use kludgine::app::winit::event::{DeviceId, MouseButton, MouseScrollDelta, Touch
use kludgine::app::winit::keyboard::{Key, NamedKey};
use kludgine::figures::units::{Lp, Px, UPx};
use kludgine::figures::{
FloatConversion, FromComponents, IntoComponents, IntoSigned, Point, Ranged, Rect, Round,
ScreenScale, Size,
FloatConversion, IntoSigned, Point, Ranged, Rect, Round, ScreenScale, Size,
};
use kludgine::shapes::{Shape, StrokeOptions};
use kludgine::{Color, DrawableExt, Origin};
@ -155,7 +154,7 @@ where
let half_focus_ring =
spec.if_knobbed(|| (Lp::points(2).into_px(context.gfx.scale()) / 2).ceil());
let focus_ring = half_focus_ring * 2;
let track_length = self.rendered_size - spec.if_knobbed(|| spec.knob_size - focus_ring);
let track_length = self.rendered_size - spec.if_knobbed(|| spec.knob_size + focus_ring);
let (start, end) = if let Some(end) = spec.end {
(track_length * spec.start, track_length * end)
} else {
@ -169,10 +168,10 @@ where
if start > 0 {
context.gfx.draw_shape(
Shape::filled_round_rect(
Rect::new(
flipped(!self.horizontal, Point::new(start_inset, start_inset)),
flipped(!self.horizontal, Size::new(start, spec.track_size)),
),
self.orient_rectangle(Rect::new(
Point::new(start_inset, start_inset),
Size::new(start, spec.track_size),
)),
half_track,
spec.inactive_track_color,
)
@ -182,19 +181,13 @@ where
if end < track_length {
context.gfx.draw_shape(
Shape::filled_round_rect(
Rect::new(
flipped(
!self.horizontal,
Point::new(end + spec.if_knobbed(|| spec.half_knob), start_inset),
self.orient_rectangle(Rect::new(
Point::new(end + spec.if_knobbed(|| spec.half_knob), start_inset),
Size::new(
track_length - end + spec.if_knobbed(|| half_track),
spec.track_size,
),
flipped(
!self.horizontal,
Size::new(
track_length - end + spec.if_knobbed(|| half_track),
spec.track_size,
),
),
),
)),
half_track,
spec.inactive_track_color,
)
@ -205,22 +198,16 @@ where
if start != end {
context.gfx.draw_shape(
Shape::filled_round_rect(
Rect::new(
flipped(
!self.horizontal,
Point::new(
start + spec.if_knobbed(|| spec.half_knob - half_track),
start_inset,
),
self.orient_rectangle(Rect::new(
Point::new(
start + spec.if_knobbed(|| spec.half_knob - half_track),
start_inset,
),
flipped(
!self.horizontal,
Size::new(
end - start + spec.if_knobbed(|| spec.track_size),
spec.track_size,
),
Size::new(
end - start + spec.if_knobbed(|| spec.track_size),
spec.track_size,
),
),
)),
half_track,
spec.track_color,
)
@ -231,14 +218,10 @@ where
// Draw the knob
if spec.knob_size > 0 {
let focus = context.focused().then_some(self.focused_knob).flatten();
self.draw_knobs(
flipped(
!self.horizontal,
Point::new(end + spec.half_knob, spec.half_knob) + inset,
),
Self::draw_knobs(
self.flip_pt_if_vertical(Point::new(end + spec.half_knob, spec.half_knob) + inset),
spec.end.map(|_| {
flipped(
!self.horizontal,
self.flip_pt_if_vertical(
Point::new(start + spec.half_knob, spec.half_knob) + inset,
)
}),
@ -247,39 +230,10 @@ where
spec,
context,
);
// let this_knob_role = if spec.end.is_some() {
// Knob::End
// } else {
// Knob::Start
// };
// self.draw_knob(
// flipped(
// !self.horizontal,
// Point::new(end + spec.half_knob, spec.half_knob) + inset,
// ),
// focused && self.focused_knob == Some(this_knob_role),
// focus_ring,
// spec,
// context,
// );
// if spec.end.is_some() {
// self.draw_knob(
// flipped(
// !self.horizontal,
// Point::new(start + spec.half_knob, spec.half_knob) + inset,
// ),
// focused && matches!(self.focused_knob, Some(Knob::Start)),
// focus_ring,
// spec,
// context,
// );
// }
}
}
fn draw_knobs(
&mut self,
end_knob: Point<Px>,
start_knob: Option<Point<Px>>,
focus: Option<Knob>,
@ -293,14 +247,13 @@ where
(None, focus) => (end_knob, focus.is_some(), None),
};
self.draw_knob(a, a_is_focused, focus_ring_width, spec, context);
Self::draw_knob(a, a_is_focused, focus_ring_width, spec, context);
if let Some((b, b_is_focused)) = b {
self.draw_knob(b, b_is_focused, focus_ring_width, spec, context);
Self::draw_knob(b, b_is_focused, focus_ring_width, spec, context);
}
}
fn draw_knob(
&mut self,
knob_center: Point<Px>,
is_focused: bool,
focus_ring_width: Px,
@ -309,7 +262,7 @@ where
) {
context.gfx.draw_shape(
Shape::filled_circle(spec.half_knob, spec.knob_color, Origin::Center)
.translate_by(flipped(!self.horizontal, knob_center)),
.translate_by(knob_center),
);
if is_focused {
@ -336,7 +289,7 @@ where
let position = if self.horizontal {
position.x - knob_size / 2
} else {
position.y - knob_size / 2
self.rendered_size - position.y - knob_size / 2
};
let track_width = self.rendered_size - knob_size;
let position = position.clamp(Px::ZERO, track_width);
@ -439,6 +392,27 @@ where
self.value.update(T::from_parts(start, end));
}
}
fn orient_rectangle(&self, rect: Rect<Px>) -> Rect<Px> {
if self.horizontal {
rect
} else {
let (tl, br) = rect.extents();
Rect::from_extents(
Point::new(tl.y, self.rendered_size - tl.x),
Point::new(br.y, self.rendered_size - br.x),
)
}
}
fn flip_pt_if_vertical(&self, pt: Point<Px>) -> Point<Px> {
if self.horizontal {
pt
} else {
Point::new(pt.y, self.rendered_size - pt.x)
}
}
}
impl<T> Widget for Slider<T>
@ -742,18 +716,6 @@ impl TrackSpec {
}
}
fn flipped<T, Unit>(flip: bool, value: T) -> T
where
T: IntoComponents<Unit> + FromComponents<Unit>,
{
if flip {
let (a, b) = value.into_components();
T::from_components((b, a))
} else {
value
}
}
define_components! {
Slider {
/// The size of the track that the knob of a [`Slider`] traversesq.