mirror of
https://github.com/danbulant/cushy
synced 2026-09-20 06:53:46 +00:00
Vertical sliders/progress bars
Also fixed checkbox layout after Label no longer pads itself.
This commit is contained in:
parent
eee336eab0
commit
46a0758d09
6 changed files with 109 additions and 121 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue