rework interactions

This commit is contained in:
galister
2024-02-04 14:23:28 +01:00
parent e846014a88
commit 82f53e6668
15 changed files with 201 additions and 102 deletions

View File

@@ -3,7 +3,6 @@ use std::{
io::Cursor,
process::{Child, Command},
str::FromStr,
sync::Arc,
};
use crate::{
@@ -26,6 +25,8 @@ const PIXELS_PER_UNIT: f32 = 80.;
const BUTTON_PADDING: f32 = 4.;
const AUTO_RELEASE_MODS: [KeyModifier; 5] = [SHIFT, CTRL, ALT, SUPER, META];
pub const KEYBOARD_NAME: &str = "kbd";
pub fn create_keyboard<O>(app: &AppState) -> OverlayData<O>
where
O: Default,
@@ -116,9 +117,11 @@ where
OverlayData {
state: OverlayState {
name: Arc::from("kbd"),
name: KEYBOARD_NAME.into(),
size: (size.x as _, size.y as _),
grabbable: true,
recenter: true,
interactable: true,
spawn_scale: width,
spawn_point: vec3a(0., -0.5, -1.),
interaction_transform,

View File

@@ -1,3 +1,4 @@
pub mod keyboard;
pub mod screen;
pub mod toast;
pub mod watch;

View File

@@ -378,6 +378,8 @@ where
size,
want_visible: session.show_screens.iter().any(|s| s == &*output.name),
grabbable: true,
recenter: true,
interactable: true,
spawn_scale: 1.5 * session.config.desktop_view_scale,
spawn_point: vec3a(0., 0.5, -1.),
spawn_rotation: Quat::from_axis_angle(axis, angle),

34
src/overlays/toast.rs Normal file
View File

@@ -0,0 +1,34 @@
use std::sync::Arc;
pub struct Toast {
pub title: Arc<str>,
pub body: Arc<str>,
pub opacity: f32,
pub timeout: f32,
pub sound: bool,
}
#[allow(dead_code)]
impl Toast {
pub fn new(title: Arc<str>, body: Arc<str>) -> Self {
Toast {
title,
body,
opacity: 1.0,
timeout: 3.0,
sound: false,
}
}
pub fn with_timeout(mut self, timeout: f32) -> Self {
self.timeout = timeout;
self
}
pub fn with_opacity(mut self, opacity: f32) -> Self {
self.opacity = opacity;
self
}
pub fn with_sound(mut self) -> Self {
self.sound = true;
self
}
}

View File

@@ -6,12 +6,15 @@ use glam::{vec2, Affine2};
use crate::{
backend::{
common::{OverlaySelector, TaskType},
input::PointerMode,
overlay::{OverlayData, OverlayState, RelativeTo},
},
gui::{color_parse, CanvasBuilder},
gui::{color_parse, CanvasBuilder, Control},
state::AppState,
};
use super::{keyboard::KEYBOARD_NAME, toast::Toast};
pub const WATCH_NAME: &str = "watch";
pub fn create_watch<O>(state: &AppState, screens: &[OverlayData<O>]) -> OverlayData<O>
@@ -79,44 +82,21 @@ where
let button_width = 360. / num_buttons as f32;
let mut button_x = 40.;
let keyboard = canvas.button(button_x + 2., 162., button_width - 4., 36., "kbd".into());
let keyboard = canvas.button(
button_x + 2.,
162.,
button_width - 4.,
36.,
KEYBOARD_NAME.into(),
);
keyboard.state = Some(WatchButtonState {
pressed_at: Instant::now(),
scr_idx: 0,
overlay: OverlaySelector::Name(KEYBOARD_NAME.into()),
mode: PointerMode::Left,
});
keyboard.on_press = Some(|control, _data, _app, _| {
if let Some(state) = control.state.as_mut() {
state.pressed_at = Instant::now();
}
});
keyboard.on_release = Some(|control, _data, app| {
if let Some(state) = control.state.as_ref() {
if Instant::now()
.saturating_duration_since(state.pressed_at)
.as_millis()
< 2000
{
app.tasks.enqueue(TaskType::Overlay(
OverlaySelector::Name("kbd".into()),
Box::new(|app, o| {
o.show_hide = !o.show_hide;
o.want_visible = o.show_hide;
if app.session.recenter_on_show {
o.reset(app, false);
}
}),
));
} else {
app.tasks.enqueue(TaskType::Overlay(
OverlaySelector::Name("kbd".into()),
Box::new(|app, o| {
o.reset(app, true);
}),
));
}
}
});
keyboard.on_press = Some(overlay_button_dn);
keyboard.on_release = Some(overlay_button_up);
button_x += button_width;
canvas.bg_color = color_parse("#405060");
@@ -131,42 +111,12 @@ where
);
button.state = Some(WatchButtonState {
pressed_at: Instant::now(),
scr_idx: screen.state.id,
overlay: OverlaySelector::Id(screen.state.id),
mode: PointerMode::Left,
});
button.on_press = Some(|control, _data, _app, _| {
if let Some(state) = control.state.as_mut() {
state.pressed_at = Instant::now();
}
});
button.on_release = Some(|control, _data, app| {
if let Some(state) = control.state.as_ref() {
let scr_idx = state.scr_idx;
if Instant::now()
.saturating_duration_since(state.pressed_at)
.as_millis()
< 2000
{
app.tasks.enqueue(TaskType::Overlay(
OverlaySelector::Id(scr_idx),
Box::new(|app, o| {
o.show_hide = !o.show_hide;
o.want_visible = o.show_hide;
if app.session.recenter_on_show {
o.reset(app, false);
}
}),
));
} else {
app.tasks.enqueue(TaskType::Overlay(
OverlaySelector::Id(scr_idx),
Box::new(|app, o| {
o.reset(app, true);
}),
));
}
}
});
button.on_press = Some(overlay_button_dn);
button.on_release = Some(overlay_button_up);
button_x += button_width;
}
let interaction_transform =
@@ -179,6 +129,7 @@ where
name: WATCH_NAME.into(),
size: (400, 200),
want_visible: true,
interactable: true,
spawn_scale: 0.11 * state.session.config.watch_scale,
spawn_point: state.session.watch_pos.into(),
spawn_rotation: state.session.watch_rot,
@@ -193,5 +144,82 @@ where
struct WatchButtonState {
pressed_at: Instant,
scr_idx: usize,
mode: PointerMode,
overlay: OverlaySelector,
}
fn overlay_button_dn(
control: &mut Control<(), WatchButtonState>,
_: &mut (),
_: &mut AppState,
mode: PointerMode,
) {
if let Some(state) = control.state.as_mut() {
state.pressed_at = Instant::now();
state.mode = mode;
}
}
fn overlay_button_up(control: &mut Control<(), WatchButtonState>, _: &mut (), app: &mut AppState) {
if let Some(state) = control.state.as_ref() {
let selector = state.overlay.clone();
if Instant::now()
.saturating_duration_since(state.pressed_at)
.as_millis()
< 2000
{
match state.mode {
PointerMode::Left => {
app.tasks.enqueue(TaskType::Overlay(
selector,
Box::new(|app, o| {
o.want_visible = !o.want_visible;
if o.recenter {
o.show_hide = o.want_visible;
o.reset(app, false);
}
}),
));
}
PointerMode::Right => {
app.tasks.enqueue(TaskType::Overlay(
selector,
Box::new(|app, o| {
o.recenter = !o.recenter;
o.grabbable = o.recenter;
o.show_hide = o.recenter;
if !o.recenter {
app.tasks.enqueue(TaskType::Toast(Toast::new(
format!("{} is now locked in place!", o.name).into(),
"Right-click again to toggle.".into(),
)))
}
}),
));
}
PointerMode::Middle => {
app.tasks.enqueue(TaskType::Overlay(
selector,
Box::new(|app, o| {
o.interactable = !o.interactable;
if !o.interactable {
app.tasks.enqueue(TaskType::Toast(Toast::new(
format!("{} is now non-interactable!", o.name).into(),
"Middle-click again to toggle.".into(),
)))
}
}),
));
}
_ => {}
}
} else {
app.tasks.enqueue(TaskType::Overlay(
selector,
Box::new(|app, o| {
o.reset(app, true);
}),
));
}
}
}