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]] [[package]]
name = "figures" name = "figures"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/khonsulabs/figures#40045fa1940f6212bc4876a4ef9ae2cd0bd89808" source = "git+https://github.com/khonsulabs/figures#4de8f5965bc7f9fc12369b2af93068e9da7a2446"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"euclid", "euclid",

View file

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

View file

@ -708,6 +708,15 @@ pub trait MakeWidget: Sized {
Expand::horizontal(self) 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`. /// Resizes `self` to `width`.
/// ///
/// `width` can be an any of: /// `width` can be an any of:

View file

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

View file

@ -5,7 +5,7 @@ use std::time::Duration;
use kludgine::figures::Ranged; use kludgine::figures::Ranged;
use crate::animation::easings::EaseInOutSine; use crate::animation::easings::EaseInOutQuadradic;
use crate::animation::{ use crate::animation::{
AnimationHandle, AnimationTarget, IntoAnimate, PercentBetween, Spawn, ZeroToOne, AnimationHandle, AnimationTarget, IntoAnimate, PercentBetween, Spawn, ZeroToOne,
}; };
@ -82,37 +82,39 @@ fn update_progress_bar(
) { ) {
match progress { match progress {
Progress::Indeterminant => { Progress::Indeterminant => {
*indeterminant_animation = Some( if indeterminant_animation.is_none() {
end.transition_to(ZeroToOne::new(0.66)) *indeterminant_animation = Some(
.over(Duration::from_millis(500)) (
.with_easing(EaseInOutSine) start.transition_to(ZeroToOne::ZERO),
.and_then( end.transition_to(ZeroToOne::ZERO),
start
.transition_to(ZeroToOne::new(0.33))
.over(Duration::from_millis(500))
.with_easing(EaseInOutSine),
) )
.and_then( .over(Duration::ZERO)
end.transition_to(ZeroToOne::ONE) .and_then(
.over(Duration::from_millis(500)) end.transition_to(ZeroToOne::new(0.66))
.with_easing(EaseInOutSine), .over(Duration::from_millis(500))
) .with_easing(EaseInOutQuadradic),
.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(
) start
.cycle() .transition_to(ZeroToOne::new(0.33))
.spawn(), .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) => { Progress::Percent(value) => {
let _stopped_animation = indeterminant_animation.take(); 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::app::winit::keyboard::{Key, NamedKey};
use kludgine::figures::units::{Lp, Px, UPx}; use kludgine::figures::units::{Lp, Px, UPx};
use kludgine::figures::{ use kludgine::figures::{
FloatConversion, FromComponents, IntoComponents, IntoSigned, Point, Ranged, Rect, Round, FloatConversion, IntoSigned, Point, Ranged, Rect, Round, ScreenScale, Size,
ScreenScale, Size,
}; };
use kludgine::shapes::{Shape, StrokeOptions}; use kludgine::shapes::{Shape, StrokeOptions};
use kludgine::{Color, DrawableExt, Origin}; use kludgine::{Color, DrawableExt, Origin};
@ -155,7 +154,7 @@ where
let half_focus_ring = let half_focus_ring =
spec.if_knobbed(|| (Lp::points(2).into_px(context.gfx.scale()) / 2).ceil()); spec.if_knobbed(|| (Lp::points(2).into_px(context.gfx.scale()) / 2).ceil());
let focus_ring = half_focus_ring * 2; 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 { let (start, end) = if let Some(end) = spec.end {
(track_length * spec.start, track_length * end) (track_length * spec.start, track_length * end)
} else { } else {
@ -169,10 +168,10 @@ where
if start > 0 { if start > 0 {
context.gfx.draw_shape( context.gfx.draw_shape(
Shape::filled_round_rect( Shape::filled_round_rect(
Rect::new( self.orient_rectangle(Rect::new(
flipped(!self.horizontal, Point::new(start_inset, start_inset)), Point::new(start_inset, start_inset),
flipped(!self.horizontal, Size::new(start, spec.track_size)), Size::new(start, spec.track_size),
), )),
half_track, half_track,
spec.inactive_track_color, spec.inactive_track_color,
) )
@ -182,19 +181,13 @@ where
if end < track_length { if end < track_length {
context.gfx.draw_shape( context.gfx.draw_shape(
Shape::filled_round_rect( Shape::filled_round_rect(
Rect::new( self.orient_rectangle(Rect::new(
flipped( Point::new(end + spec.if_knobbed(|| spec.half_knob), start_inset),
!self.horizontal, Size::new(
Point::new(end + spec.if_knobbed(|| spec.half_knob), start_inset), 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, half_track,
spec.inactive_track_color, spec.inactive_track_color,
) )
@ -205,22 +198,16 @@ where
if start != end { if start != end {
context.gfx.draw_shape( context.gfx.draw_shape(
Shape::filled_round_rect( Shape::filled_round_rect(
Rect::new( self.orient_rectangle(Rect::new(
flipped( Point::new(
!self.horizontal, start + spec.if_knobbed(|| spec.half_knob - half_track),
Point::new( start_inset,
start + spec.if_knobbed(|| spec.half_knob - half_track),
start_inset,
),
), ),
flipped( Size::new(
!self.horizontal, end - start + spec.if_knobbed(|| spec.track_size),
Size::new( spec.track_size,
end - start + spec.if_knobbed(|| spec.track_size),
spec.track_size,
),
), ),
), )),
half_track, half_track,
spec.track_color, spec.track_color,
) )
@ -231,14 +218,10 @@ where
// Draw the knob // Draw the knob
if spec.knob_size > 0 { if spec.knob_size > 0 {
let focus = context.focused().then_some(self.focused_knob).flatten(); let focus = context.focused().then_some(self.focused_knob).flatten();
self.draw_knobs( Self::draw_knobs(
flipped( self.flip_pt_if_vertical(Point::new(end + spec.half_knob, spec.half_knob) + inset),
!self.horizontal,
Point::new(end + spec.half_knob, spec.half_knob) + inset,
),
spec.end.map(|_| { spec.end.map(|_| {
flipped( self.flip_pt_if_vertical(
!self.horizontal,
Point::new(start + spec.half_knob, spec.half_knob) + inset, Point::new(start + spec.half_knob, spec.half_knob) + inset,
) )
}), }),
@ -247,39 +230,10 @@ where
spec, spec,
context, 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( fn draw_knobs(
&mut self,
end_knob: Point<Px>, end_knob: Point<Px>,
start_knob: Option<Point<Px>>, start_knob: Option<Point<Px>>,
focus: Option<Knob>, focus: Option<Knob>,
@ -293,14 +247,13 @@ where
(None, focus) => (end_knob, focus.is_some(), None), (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 { 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( fn draw_knob(
&mut self,
knob_center: Point<Px>, knob_center: Point<Px>,
is_focused: bool, is_focused: bool,
focus_ring_width: Px, focus_ring_width: Px,
@ -309,7 +262,7 @@ where
) { ) {
context.gfx.draw_shape( context.gfx.draw_shape(
Shape::filled_circle(spec.half_knob, spec.knob_color, Origin::Center) 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 { if is_focused {
@ -336,7 +289,7 @@ where
let position = if self.horizontal { let position = if self.horizontal {
position.x - knob_size / 2 position.x - knob_size / 2
} else { } else {
position.y - knob_size / 2 self.rendered_size - position.y - knob_size / 2
}; };
let track_width = self.rendered_size - knob_size; let track_width = self.rendered_size - knob_size;
let position = position.clamp(Px::ZERO, track_width); let position = position.clamp(Px::ZERO, track_width);
@ -439,6 +392,27 @@ where
self.value.update(T::from_parts(start, end)); 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> 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! { define_components! {
Slider { Slider {
/// The size of the track that the knob of a [`Slider`] traversesq. /// The size of the track that the knob of a [`Slider`] traversesq.