mirror of
https://github.com/danbulant/cushy
synced 2026-06-18 05:51:20 +00:00
ButtonClick + Overlays at locations
The overlay example now supports right-clicking to open overlays at the clicked location, showing how a context menu widget can begin being built.
This commit is contained in:
parent
ecf0d45bfa
commit
1c8d4e0176
20 changed files with 165 additions and 76 deletions
|
|
@ -68,6 +68,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- `PlatformWindowImplementation::set_cursor_icon` and
|
||||
`PlatformWindow::set_cursor_icon` have been renamed to `set_cursor` and accept
|
||||
`winit` 0.30's new `Cursor` type.
|
||||
- `Button::on_click` now takes a `Option<ButtonClick>` structure. When this
|
||||
value is provided, information about the mouse click that caused the event is
|
||||
provided.
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use std::time::Duration;
|
|||
use cushy::animation::{AnimationHandle, AnimationTarget, IntoAnimate, Spawn};
|
||||
use cushy::value::{Destination, Dynamic};
|
||||
use cushy::widget::MakeWidget;
|
||||
use cushy::widgets::button::ButtonClick;
|
||||
use cushy::widgets::progress::Progressable;
|
||||
use cushy::{Run, WithClone};
|
||||
use figures::units::Lp;
|
||||
|
|
@ -41,7 +42,7 @@ fn animate_to(
|
|||
animation: &Dynamic<AnimationHandle>,
|
||||
value: &Dynamic<u8>,
|
||||
target: u8,
|
||||
) -> impl FnMut(()) {
|
||||
) -> impl FnMut(Option<ButtonClick>) {
|
||||
(animation, value).with_clone(|(animation, value)| {
|
||||
move |_| {
|
||||
// Here we use spawn to schedule the animation, which returns an
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ fn main() -> cushy::Result {
|
|||
.into_button()
|
||||
.on_click({
|
||||
let task = dynamic.clone();
|
||||
move |()| {
|
||||
move |_| {
|
||||
let background_task = Task::default();
|
||||
spawn_background_thread(&background_task.progress, &task);
|
||||
task.set(Some(background_task));
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ fn main() -> cushy::Result {
|
|||
.into_button()
|
||||
.on_click({
|
||||
let clicked_button = clicked_button.clone();
|
||||
move |()| clicked_button.set("inner button clicked")
|
||||
move |_| clicked_button.set("inner button clicked")
|
||||
})
|
||||
.with(&ButtonHoverBackground, Color::RED)
|
||||
.with(&ButtonHoverForeground, Color::WHITE);
|
||||
|
|
@ -40,7 +40,7 @@ fn main() -> cushy::Result {
|
|||
.into_button()
|
||||
.on_click({
|
||||
let clicked_button = clicked_button.clone();
|
||||
move |()| clicked_button.set("middle button clicked")
|
||||
move |_| clicked_button.set("middle button clicked")
|
||||
});
|
||||
|
||||
let outer_button = "Yo dawg!"
|
||||
|
|
@ -49,7 +49,7 @@ fn main() -> cushy::Result {
|
|||
.into_button()
|
||||
.on_click({
|
||||
let clicked_button = clicked_button.clone();
|
||||
move |()| clicked_button.set("outer button clicked")
|
||||
move |_| clicked_button.set("outer button clicked")
|
||||
});
|
||||
|
||||
outer_button
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ fn main() -> cushy::Result {
|
|||
checkbox_state
|
||||
.clone()
|
||||
.to_checkbox(label)
|
||||
.and("Maybe".into_button().on_click(move |()| {
|
||||
.and("Maybe".into_button().on_click(move |_| {
|
||||
checkbox_state.set(CheckboxState::Indeterminant);
|
||||
}))
|
||||
.into_columns()
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ fn edit_contact_form(contact: &Contact, db: &Dynamic<HashMap<u64, Contact>>) ->
|
|||
.on_click({
|
||||
let contact_id = contact.id;
|
||||
let db = db.clone();
|
||||
move |()| {
|
||||
move |_| {
|
||||
let mut db = db.lock();
|
||||
let contact = db.get_mut(&contact_id).expect("missing contact");
|
||||
contact.first_name = first.get();
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ fn main() -> cushy::Result {
|
|||
let info = info.clone();
|
||||
let window_count = window_count.clone();
|
||||
let total_windows = total_windows.clone();
|
||||
move |()| open_a_window(&window_count, &total_windows, &info, &mut app)
|
||||
move |_| open_a_window(&window_count, &total_windows, &info, &mut app)
|
||||
})
|
||||
.make_widget();
|
||||
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ fn main() -> cushy::Result {
|
|||
.and(
|
||||
"Log In"
|
||||
.into_button()
|
||||
.on_click(validations.when_valid(move |()| {
|
||||
.on_click(validations.when_valid(move |_| {
|
||||
println!("Welcome, {}", username.get());
|
||||
exit(0);
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ fn open_window_button(
|
|||
let open_windows = open_windows.clone();
|
||||
let counter = counter.clone();
|
||||
let texture = texture.clone();
|
||||
"Open Another Window".into_button().on_click(move |()| {
|
||||
"Open Another Window".into_button().on_click(move |_| {
|
||||
open_another_window(&mut app, &open_windows, &counter, &texture);
|
||||
})
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ fn open_another_window(
|
|||
.and(
|
||||
"Close"
|
||||
.into_button()
|
||||
.on_click(move |()| handle.request_close()),
|
||||
.on_click(move |_| handle.request_close()),
|
||||
)
|
||||
.into_rows()
|
||||
.centered(),
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use cushy::widgets::layers::{OverlayBuilder, OverlayLayer};
|
|||
use cushy::Run;
|
||||
use figures::units::Lp;
|
||||
use figures::{Point, Zero};
|
||||
use kludgine::app::winit::event::MouseButton;
|
||||
use kludgine::Color;
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
|
|
@ -55,10 +56,20 @@ fn show_overlay_button(
|
|||
direction_func: impl for<'a> Fn(OverlayBuilder<'a>) -> OverlayBuilder<'a> + Send + 'static,
|
||||
) -> impl MakeWidget {
|
||||
let overlay = overlay.clone();
|
||||
label.into_button().on_click(move |()| {
|
||||
direction_func(overlay.build_overlay(test_widget(&overlay, false)))
|
||||
.hide_on_unhover()
|
||||
.show()
|
||||
.forget();
|
||||
})
|
||||
let button_tag = WidgetTag::unique();
|
||||
let button_id = button_tag.id();
|
||||
label
|
||||
.into_button()
|
||||
.on_click(move |click| {
|
||||
let overlay = overlay.build_overlay(test_widget(&overlay, false));
|
||||
let overlay = match click {
|
||||
Some(click) if click.mouse_button == MouseButton::Right => {
|
||||
overlay.above(button_id).at(click.window_location)
|
||||
}
|
||||
_ => direction_func(overlay),
|
||||
};
|
||||
|
||||
overlay.hide_on_unhover().show().forget();
|
||||
})
|
||||
.make_with_tag(button_tag)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ fn main() -> cushy::Result {
|
|||
.and(editors.neutral_variant.1)
|
||||
.and("Copy to Clipboard".into_button().on_click({
|
||||
let cushy = app.cushy().clone();
|
||||
move |()| {
|
||||
move |_| {
|
||||
if let Some(mut clipboard) = cushy.clipboard_guard() {
|
||||
let builder = color_scheme_builder.get();
|
||||
let mut source = String::default();
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@ fn main() -> cushy::Result {
|
|||
.and(
|
||||
"Submit"
|
||||
.into_button()
|
||||
.on_click(validations.clone().when_valid(move |()| {
|
||||
.on_click(validations.clone().when_valid(move |_| {
|
||||
println!(
|
||||
"Success! This callback only happens when all associated validations are valid"
|
||||
);
|
||||
})),
|
||||
)
|
||||
.and("Reset".into_button().on_click(move |()| {
|
||||
.and("Reset".into_button().on_click(move |_| {
|
||||
let _value = text.take();
|
||||
validations.reset();
|
||||
}))
|
||||
|
|
|
|||
12
src/debug.rs
12
src/debug.rs
|
|
@ -52,7 +52,7 @@ impl DebugContext {
|
|||
let id = self.section.map_ref(|section| {
|
||||
section.values.lock().push(Box::new(RegisteredValue {
|
||||
label: label.into(),
|
||||
value: reader.clone(),
|
||||
_value: reader.clone(),
|
||||
widget: make_observer(value.weak_clone()).make_widget(),
|
||||
}))
|
||||
});
|
||||
|
|
@ -145,13 +145,13 @@ impl Drop for DebugContext {
|
|||
|
||||
trait Observable: Send {
|
||||
fn label(&self) -> &str;
|
||||
fn alive(&self) -> bool;
|
||||
// fn alive(&self) -> bool;
|
||||
fn widget(&self) -> &WidgetInstance;
|
||||
}
|
||||
|
||||
struct RegisteredValue<T> {
|
||||
label: String,
|
||||
value: DynamicReader<T>,
|
||||
_value: DynamicReader<T>,
|
||||
widget: WidgetInstance,
|
||||
}
|
||||
|
||||
|
|
@ -163,9 +163,9 @@ where
|
|||
&self.label
|
||||
}
|
||||
|
||||
fn alive(&self) -> bool {
|
||||
self.value.connected()
|
||||
}
|
||||
// fn alive(&self) -> bool {
|
||||
// self.value.connected()
|
||||
// }
|
||||
|
||||
fn widget(&self) -> &WidgetInstance {
|
||||
&self.widget
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ pub struct Button {
|
|||
/// The label to display on the button.
|
||||
pub content: WidgetRef,
|
||||
/// The callback that is invoked when the button is clicked.
|
||||
pub on_click: Option<Callback<()>>,
|
||||
pub on_click: Option<Callback<Option<ButtonClick>>>,
|
||||
/// The kind of button to draw.
|
||||
pub kind: Value<ButtonKind>,
|
||||
focusable: bool,
|
||||
|
|
@ -158,7 +158,7 @@ impl Button {
|
|||
#[must_use]
|
||||
pub fn on_click<F>(mut self, callback: F) -> Self
|
||||
where
|
||||
F: FnMut(()) + Send + 'static,
|
||||
F: FnMut(Option<ButtonClick>) + Send + 'static,
|
||||
{
|
||||
self.on_click = Some(Callback::new(callback));
|
||||
self
|
||||
|
|
@ -171,10 +171,10 @@ impl Button {
|
|||
self
|
||||
}
|
||||
|
||||
fn invoke_on_click(&mut self, context: &WidgetContext<'_>) {
|
||||
fn invoke_on_click(&mut self, button: Option<ButtonClick>, context: &WidgetContext<'_>) {
|
||||
if context.enabled() {
|
||||
if let Some(on_click) = self.on_click.as_mut() {
|
||||
on_click.invoke(());
|
||||
on_click.invoke(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -461,7 +461,7 @@ impl Widget for Button {
|
|||
&mut self,
|
||||
location: Option<Point<Px>>,
|
||||
_device_id: DeviceId,
|
||||
_button: MouseButton,
|
||||
button: MouseButton,
|
||||
context: &mut EventContext<'_>,
|
||||
) {
|
||||
let window_local = self.per_window.entry(context).or_default();
|
||||
|
|
@ -470,12 +470,19 @@ impl Widget for Button {
|
|||
context.deactivate();
|
||||
|
||||
if let (true, Some(location)) = (self.focusable, location) {
|
||||
if Rect::from(context.last_layout().expect("must have been rendered").size)
|
||||
.contains(location)
|
||||
{
|
||||
let last_layout = context.last_layout().expect("must have been rendered");
|
||||
// let button_relative
|
||||
if Rect::from(last_layout.size).contains(location) {
|
||||
context.focus();
|
||||
|
||||
self.invoke_on_click(context);
|
||||
self.invoke_on_click(
|
||||
Some(ButtonClick {
|
||||
mouse_button: button,
|
||||
location,
|
||||
window_location: location + last_layout.origin,
|
||||
}),
|
||||
context,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -533,7 +540,7 @@ impl Widget for Button {
|
|||
// If we have no buttons pressed, the event should fire on activate not
|
||||
// on deactivate.
|
||||
if window_local.buttons_pressed == 0 {
|
||||
self.invoke_on_click(context);
|
||||
self.invoke_on_click(None, context);
|
||||
}
|
||||
self.update_colors(context, true);
|
||||
}
|
||||
|
|
@ -581,3 +588,14 @@ define_components! {
|
|||
ButtonDisabledOutline(Color, "disabled_outline_color", Color::CLEAR_BLACK)
|
||||
}
|
||||
}
|
||||
|
||||
/// A mouse click in a [`Button`].
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub struct ButtonClick {
|
||||
/// The mouse button that caused the event.
|
||||
pub mouse_button: MouseButton,
|
||||
/// The location relative to the button of the click.
|
||||
pub location: Point<Px>,
|
||||
/// The location relative to the window of the click.
|
||||
pub window_location: Point<Px>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ impl MakeWidgetWithTag for Checkbox {
|
|||
.and(self.label)
|
||||
.into_columns()
|
||||
.into_button()
|
||||
.on_click(move |()| {
|
||||
.on_click(move |_| {
|
||||
let mut value = self.state.lock();
|
||||
*value = !*value;
|
||||
})
|
||||
|
|
|
|||
|
|
@ -856,6 +856,12 @@ impl<const N: usize> DerefMut for GridWidgets<N> {
|
|||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct GridSection<const N: usize>([WidgetInstance; N]);
|
||||
|
||||
impl Default for GridSection<0> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl GridSection<0> {
|
||||
/// Returns an empty section.
|
||||
#[must_use]
|
||||
|
|
|
|||
|
|
@ -1243,9 +1243,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct NotVisible(Point<Px>, usize);
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct BlinkState {
|
||||
visible: bool,
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ impl OverlayLayer {
|
|||
layout: OverlayLayout {
|
||||
widget: WidgetRef::new(overlay),
|
||||
relative_to: None,
|
||||
direction: Direction::Right,
|
||||
positioning: Position::Relative(Direction::Right),
|
||||
requires_hover: false,
|
||||
on_dismiss: None,
|
||||
layout: None,
|
||||
|
|
@ -395,26 +395,26 @@ impl OverlayState {
|
|||
context: &mut LayoutContext<'_, '_, '_, '_>,
|
||||
relative_to: WidgetId,
|
||||
) -> Option<Rect<Px>> {
|
||||
let direction = self.overlays[index].direction;
|
||||
let positioning = self.overlays[index].positioning;
|
||||
let relative_to = relative_to.find_in(context)?.last_layout()?;
|
||||
let relative_to_unsigned = relative_to.into_unsigned();
|
||||
|
||||
let constraints = match direction {
|
||||
Direction::Up => Size::new(
|
||||
let constraints = match positioning {
|
||||
Position::Relative(Direction::Up) => Size::new(
|
||||
relative_to_unsigned.size.width,
|
||||
relative_to_unsigned.origin.y,
|
||||
),
|
||||
Direction::Down => Size::new(
|
||||
Position::Relative(Direction::Down) => Size::new(
|
||||
relative_to_unsigned.size.width,
|
||||
available_space.height
|
||||
- relative_to_unsigned.origin.y
|
||||
- relative_to_unsigned.size.height,
|
||||
),
|
||||
Direction::Left => Size::new(
|
||||
Position::Relative(Direction::Left) => Size::new(
|
||||
relative_to_unsigned.origin.x,
|
||||
relative_to_unsigned.size.height,
|
||||
),
|
||||
Direction::Right => Size::new(
|
||||
Position::Relative(Direction::Right) => Size::new(
|
||||
available_space.width.saturating_sub(
|
||||
relative_to_unsigned
|
||||
.origin
|
||||
|
|
@ -423,6 +423,7 @@ impl OverlayState {
|
|||
),
|
||||
relative_to_unsigned.size.height,
|
||||
),
|
||||
Position::At(_) => available_space,
|
||||
};
|
||||
|
||||
let size = context
|
||||
|
|
@ -430,26 +431,39 @@ impl OverlayState {
|
|||
.layout(constraints.map(ConstraintLimit::SizeToFit))
|
||||
.into_signed();
|
||||
|
||||
let mut layout_direction = direction;
|
||||
let mut layout_direction = positioning;
|
||||
let mut layout;
|
||||
loop {
|
||||
let origin = match layout_direction {
|
||||
Direction::Up => Point::new(
|
||||
relative_to.origin.x + relative_to.size.width / 2 - size.width / 2,
|
||||
relative_to.origin.y - size.height,
|
||||
let (origin, intersection_matters) = match layout_direction {
|
||||
Position::Relative(Direction::Up) => (
|
||||
Point::new(
|
||||
relative_to.origin.x + relative_to.size.width / 2 - size.width / 2,
|
||||
relative_to.origin.y - size.height,
|
||||
),
|
||||
true,
|
||||
),
|
||||
Direction::Down => Point::new(
|
||||
relative_to.origin.x + relative_to.size.width / 2 - size.width / 2,
|
||||
relative_to.origin.y + relative_to.size.height,
|
||||
Position::Relative(Direction::Down) => (
|
||||
Point::new(
|
||||
relative_to.origin.x + relative_to.size.width / 2 - size.width / 2,
|
||||
relative_to.origin.y + relative_to.size.height,
|
||||
),
|
||||
true,
|
||||
),
|
||||
Direction::Left => Point::new(
|
||||
relative_to.origin.x - size.width,
|
||||
relative_to.origin.y + relative_to.size.height / 2 - size.height / 2,
|
||||
Position::Relative(Direction::Left) => (
|
||||
Point::new(
|
||||
relative_to.origin.x - size.width,
|
||||
relative_to.origin.y + relative_to.size.height / 2 - size.height / 2,
|
||||
),
|
||||
true,
|
||||
),
|
||||
Direction::Right => Point::new(
|
||||
relative_to.origin.x + relative_to.size.width,
|
||||
relative_to.origin.y + relative_to.size.height / 2 - size.height / 2,
|
||||
Position::Relative(Direction::Right) => (
|
||||
Point::new(
|
||||
relative_to.origin.x + relative_to.size.width,
|
||||
relative_to.origin.y + relative_to.size.height / 2 - size.height / 2,
|
||||
),
|
||||
true,
|
||||
),
|
||||
Position::At(pt) => (pt, false),
|
||||
};
|
||||
|
||||
layout = Rect::new(origin.max(Point::ZERO), size);
|
||||
|
|
@ -462,16 +476,27 @@ impl OverlayState {
|
|||
layout.origin.y -= bottom_right.y - available_space.height.into_signed();
|
||||
}
|
||||
|
||||
if layout.intersects(&relative_to) || self.layout_intersects(index, &layout, context) {
|
||||
layout_direction = layout_direction.next_clockwise();
|
||||
if layout_direction == direction {
|
||||
// No layout worked optimally.
|
||||
if intersection_matters
|
||||
&& (layout.intersects(&relative_to)
|
||||
|| self.layout_intersects(index, &layout, context))
|
||||
{
|
||||
if let Some(next_direction) = layout_direction.next_clockwise() {
|
||||
if layout_direction == positioning {
|
||||
// No layout worked optimally.
|
||||
break;
|
||||
}
|
||||
layout_direction = next_direction;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO check to ensure the widget is fully on-window, otherwise attempt
|
||||
// to shift it to become visible.
|
||||
|
||||
Some(layout)
|
||||
}
|
||||
|
||||
|
|
@ -516,7 +541,7 @@ impl OverlayState {
|
|||
if let Some(relative_to) = self.overlays[index].relative_to {
|
||||
self.layout_overlay_relative(index, widget, available_space, context, relative_to)
|
||||
} else {
|
||||
let direction = self.overlays[index].direction;
|
||||
let direction = self.overlays[index].positioning;
|
||||
let size = context
|
||||
.for_other(widget)
|
||||
.layout(available_space.map(ConstraintLimit::SizeToFit))
|
||||
|
|
@ -525,22 +550,23 @@ impl OverlayState {
|
|||
let available_space = available_space.into_signed();
|
||||
|
||||
let origin = match direction {
|
||||
Direction::Up => Point::new(
|
||||
Position::Relative(Direction::Up) => Point::new(
|
||||
available_space.width / 2,
|
||||
(available_space.height - size.height) / 2,
|
||||
),
|
||||
Direction::Down => Point::new(
|
||||
Position::Relative(Direction::Down) => Point::new(
|
||||
available_space.width / 2,
|
||||
available_space.height / 2 + size.height / 2,
|
||||
),
|
||||
Direction::Right => Point::new(
|
||||
Position::Relative(Direction::Right) => Point::new(
|
||||
available_space.width / 2 + size.width / 2,
|
||||
available_space.height / 2,
|
||||
),
|
||||
Direction::Left => Point::new(
|
||||
Position::Relative(Direction::Left) => Point::new(
|
||||
(available_space.width - size.width) / 2,
|
||||
available_space.height / 2,
|
||||
),
|
||||
Position::At(pt) => pt,
|
||||
};
|
||||
|
||||
Some(Rect::new(origin, size))
|
||||
|
|
@ -592,7 +618,14 @@ impl OverlayBuilder<'_> {
|
|||
#[must_use]
|
||||
pub fn near(mut self, id: WidgetId, direction: Direction) -> Self {
|
||||
self.layout.relative_to = Some(id);
|
||||
self.layout.direction = direction;
|
||||
self.layout.positioning = Position::Relative(direction);
|
||||
self
|
||||
}
|
||||
|
||||
/// Shows this overlay at a specified window `location`.
|
||||
#[must_use]
|
||||
pub fn at(mut self, location: Point<Px>) -> Self {
|
||||
self.layout.positioning = Position::At(location);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -632,7 +665,7 @@ struct OverlayLayout {
|
|||
widget: WidgetRef,
|
||||
opacity: Dynamic<ZeroToOne>,
|
||||
relative_to: Option<WidgetId>,
|
||||
direction: Direction,
|
||||
positioning: Position<Px>,
|
||||
requires_hover: bool,
|
||||
layout: Option<Rect<Px>>,
|
||||
on_dismiss: Option<Arc<Mutex<Callback>>>,
|
||||
|
|
@ -654,7 +687,7 @@ impl PartialEq for OverlayLayout {
|
|||
self.widget == other.widget
|
||||
&& self.opacity == other.opacity
|
||||
&& self.relative_to == other.relative_to
|
||||
&& self.direction == other.direction
|
||||
&& self.positioning == other.positioning
|
||||
&& self.requires_hover == other.requires_hover
|
||||
&& self.layout == other.layout
|
||||
&& match (&self.on_dismiss, &other.on_dismiss) {
|
||||
|
|
@ -665,6 +698,26 @@ impl PartialEq for OverlayLayout {
|
|||
}
|
||||
}
|
||||
|
||||
/// An overlay position.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub enum Position<T> {
|
||||
/// Relative to the parent in a given direction.
|
||||
Relative(Direction),
|
||||
/// At a window coordinate.
|
||||
At(Point<T>),
|
||||
}
|
||||
|
||||
impl<T> Position<T> {
|
||||
/// Returns the next direction when rotating clockwise.
|
||||
#[must_use]
|
||||
pub fn next_clockwise(&self) -> Option<Self> {
|
||||
match self {
|
||||
Self::Relative(direction) => Some(Self::Relative(direction.next_clockwise())),
|
||||
Self::At(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A relative direction.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub enum Direction {
|
||||
|
|
@ -674,7 +727,7 @@ pub enum Direction {
|
|||
Right,
|
||||
/// Positive along the Y axis.
|
||||
Down,
|
||||
/// Legative along the X axis.
|
||||
/// Negative along the X axis.
|
||||
Left,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ where
|
|||
.and(self.label)
|
||||
.into_columns()
|
||||
.into_button()
|
||||
.on_click(move |()| {
|
||||
.on_click(move |_| {
|
||||
self.state.set(self.value.clone());
|
||||
})
|
||||
.kind(self.kind)
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ where
|
|||
});
|
||||
self.label
|
||||
.into_button()
|
||||
.on_click(move |()| {
|
||||
.on_click(move |_| {
|
||||
self.state.set(self.value.clone());
|
||||
})
|
||||
.kind(kind)
|
||||
|
|
|
|||
Loading…
Reference in a new issue