add universal _long_release and variants
This commit is contained in:
@@ -23,7 +23,11 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use glam::{Mat4, Vec3};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
rc::Rc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use taffy::{prelude::length, AlignItems, JustifyContent};
|
||||
|
||||
pub struct Params<'a> {
|
||||
@@ -42,6 +46,7 @@ pub struct Params<'a> {
|
||||
/// until "un-clicked". this is visual only.
|
||||
/// set the initial state using `set_sticky_state`
|
||||
pub sticky: bool,
|
||||
pub long_press_time: f32,
|
||||
}
|
||||
|
||||
impl Default for Params<'_> {
|
||||
@@ -59,6 +64,7 @@ impl Default for Params<'_> {
|
||||
text_style: TextStyle::default(),
|
||||
tooltip: None,
|
||||
sticky: false,
|
||||
long_press_time: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,6 +86,7 @@ struct State {
|
||||
on_click: Option<ButtonClickCallback>,
|
||||
active_tooltip: Option<Rc<ComponentTooltip>>,
|
||||
colors: Colors,
|
||||
last_pressed: Instant,
|
||||
}
|
||||
|
||||
struct Data {
|
||||
@@ -152,6 +159,10 @@ impl ComponentButton {
|
||||
rect.params.color2 = get_color2(&color);
|
||||
}
|
||||
|
||||
pub fn get_time_since_last_pressed(&self) -> Duration {
|
||||
self.state.borrow().last_pressed.elapsed()
|
||||
}
|
||||
|
||||
pub fn on_click(&self, func: ButtonClickCallback) {
|
||||
self.state.borrow_mut().on_click = Some(func);
|
||||
}
|
||||
@@ -329,6 +340,7 @@ fn register_event_mouse_press(state: Rc<RefCell<State>>, listeners: &mut EventLi
|
||||
|
||||
if state.hovered {
|
||||
state.down = true;
|
||||
state.last_pressed = Instant::now();
|
||||
Ok(EventResult::Consumed)
|
||||
} else {
|
||||
Ok(EventResult::Pass)
|
||||
@@ -357,7 +369,6 @@ fn register_event_mouse_release(
|
||||
|
||||
if state.down {
|
||||
state.down = false;
|
||||
|
||||
if state.hovered
|
||||
&& let Some(on_click) = &state.on_click
|
||||
{
|
||||
@@ -507,6 +518,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
||||
on_click: None,
|
||||
active_tooltip: None,
|
||||
sticky_down: false,
|
||||
last_pressed: Instant::now(),
|
||||
colors: Colors {
|
||||
color,
|
||||
border_color,
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::{
|
||||
i18n::Translation,
|
||||
layout::WidgetID,
|
||||
parser::{
|
||||
parse_check_f32, parse_check_i32, parse_children, print_invalid_attrib, process_component,
|
||||
parse_check_f32, parse_check_i32, parse_children, parse_f32, print_invalid_attrib, process_component,
|
||||
style::{parse_color_opt, parse_round, parse_style, parse_text_style},
|
||||
AttribPair, ParserContext, ParserFile,
|
||||
},
|
||||
@@ -28,6 +28,7 @@ pub fn parse_component_button<'a>(
|
||||
let mut tooltip: Option<String> = None;
|
||||
let mut tooltip_side: Option<tooltip::TooltipSide> = None;
|
||||
let mut sticky: bool = false;
|
||||
let mut long_press_time = 0.0;
|
||||
let mut sprite_src: Option<AssetPath> = None;
|
||||
|
||||
let mut translation: Option<Translation> = None;
|
||||
@@ -92,6 +93,9 @@ pub fn parse_component_button<'a>(
|
||||
let mut sticky_i32 = 0;
|
||||
sticky = parse_check_i32(value, &mut sticky_i32) && sticky_i32 == 1;
|
||||
}
|
||||
"long_press_time" => {
|
||||
long_press_time = parse_f32(value).unwrap_or(long_press_time);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -113,6 +117,7 @@ pub fn parse_component_button<'a>(
|
||||
text: Translation::from_translation_key(&t),
|
||||
}),
|
||||
sticky,
|
||||
long_press_time,
|
||||
sprite_src,
|
||||
},
|
||||
)?;
|
||||
|
||||
@@ -205,7 +205,11 @@ impl EventResult {
|
||||
|
||||
#[must_use]
|
||||
pub fn merge(self, other: Self) -> Self {
|
||||
if self > other { self } else { other }
|
||||
if self > other {
|
||||
self
|
||||
} else {
|
||||
other
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,6 +121,9 @@ pub struct GeneralConfig {
|
||||
#[serde(default = "def_one")]
|
||||
pub scroll_speed: f32,
|
||||
|
||||
#[serde(default = "def_one")]
|
||||
pub long_press_duration: f32,
|
||||
|
||||
#[serde(default = "def_mouse_move_interval_ms")]
|
||||
pub mouse_move_interval_ms: u32,
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</template>
|
||||
|
||||
<template name="TopButtonDanger">
|
||||
<Button macro="button_style" tooltip="${tooltip}" _press="${press}" _release="${release}" border_color="~color_danger_translucent" color="~color_danger_5" color2="~color_danger_1">
|
||||
<Button macro="button_style" tooltip="${tooltip}" _long_release="${long_release}" border_color="~color_danger_translucent" color="~color_danger_5" color2="~color_danger_1">
|
||||
<sprite width="48" height="48" src="${src}" />
|
||||
</Button>
|
||||
</template>
|
||||
@@ -48,7 +48,7 @@
|
||||
<TopButton sticky="0" id="top_mouse" src="edit/normal.svg" tooltip="EDIT_MODE.MOUSE.TITLE" press="::EditModeTab mouse" />
|
||||
<!-- TopButton sticky="0" id="top_move" src="edit/move-all.svg" tooltip="EDIT_MODE.MOVE_PRESS_AND_DRAG" / -->
|
||||
<!-- TopButton sticky="0" id="top_resize" src="edit/resize.svg" tooltip="EDIT_MODE.RESIZE_PRESS_AND_DRAG" / -->
|
||||
<TopButtonDanger src="edit/delete.svg" tooltip="EDIT_MODE.DELETE" press="::EditModeDeletePress" release="::EditModeDeleteRelease" />
|
||||
<TopButtonDanger src="edit/delete.svg" tooltip="EDIT_MODE.DELETE" long_release="::EditModeDelete" />
|
||||
<div width="8" height="100%" />
|
||||
<TopButtonFaded src="watch/edit.svg" tooltip="EDIT_MODE.LEAVE" press="::EditToggle" />
|
||||
</div>
|
||||
|
||||
@@ -35,7 +35,7 @@ All overlays are listed on bottom row.
|
||||
|
||||
<template name="Overlay">
|
||||
<Button macro="button_style" id="overlay_${idx}"
|
||||
tooltip="WATCH.TOGGLE_FOR_CURRENT_SET" _press="::SingleSetOverlayToggle ${idx}"
|
||||
tooltip="WATCH.TOGGLE_FOR_CURRENT_SET" _press="::SingleSetOverlayToggle ${idx}" _long_release="::SingleSetOverlayReset ${idx}"
|
||||
align_items="center"
|
||||
height="40">
|
||||
<sprite id="overlay_${idx}_sprite" src_builtin="${src}" width="32" height="32" />
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
<sprite color="~set_color" width="40" height="40" src="watch/wayvr_dashboard_mono.svg" />
|
||||
</Button>
|
||||
<div id="edit_delete" display="none">
|
||||
<Button macro="button_style" _press="::EditModeDeleteDown" _release="::EditModeDeleteUp" tooltip="WATCH.LONG_PRESS_TO_DELETE_SET" tooltip_side="top" border_color="~color_danger_translucent" color="~color_danger_5" color2="~color_danger_1">
|
||||
<Button macro="button_style" _long_release="::EditModeDeleteSet" tooltip="WATCH.LONG_PRESS_TO_DELETE_SET" tooltip_side="top" border_color="~color_danger_translucent" color="~color_danger_5" color2="~color_danger_1">
|
||||
<sprite color="~set_color" width="40" height="40" src="edit/delete.svg" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -81,11 +81,17 @@ Supported events:
|
||||
<button _press="..." _release="..." />
|
||||
```
|
||||
|
||||
Laser-color-specific variants are also available:
|
||||
Laser-color-specific variants are also available
|
||||
- `_press_left` & `_release_left` for blue laser
|
||||
- `_press_right` & `_release_right` for orange laser
|
||||
- `_press_middle` & `_release_middle` for purple laser
|
||||
|
||||
Release after short/long press (length controlled by config `long_press_duration`)
|
||||
- `_short_release` & `_long_release` for any laser
|
||||
- `_short_release_left` & `_long_release_left` for blue laser
|
||||
- `_short_release_right` & `_long_release_right` for orange laser
|
||||
- `_short_release_middle` & `_long_release_middle` for purple laser
|
||||
|
||||
#### Supported button actions
|
||||
|
||||
##### `::ShellExec <command> [args ..]`
|
||||
|
||||
@@ -33,38 +33,115 @@ use crate::{
|
||||
#[cfg(feature = "wayvr")]
|
||||
use crate::backend::wayvr::WayVRAction;
|
||||
|
||||
pub const BUTTON_EVENTS: [(&str, EventListenerKind, fn(&mut CallbackData) -> bool); 8] = [
|
||||
("_press", EventListenerKind::MousePress, any_button),
|
||||
("_release", EventListenerKind::MouseRelease, any_button),
|
||||
("_press_left", EventListenerKind::MousePress, left_button),
|
||||
pub const BUTTON_EVENTS: [(
|
||||
&str,
|
||||
EventListenerKind,
|
||||
fn(&mut CallbackData) -> bool,
|
||||
fn(&ComponentButton, &AppState) -> bool,
|
||||
); 16] = [
|
||||
(
|
||||
"_press",
|
||||
EventListenerKind::MousePress,
|
||||
button_any,
|
||||
short_duration,
|
||||
),
|
||||
(
|
||||
"_release",
|
||||
EventListenerKind::MouseRelease,
|
||||
button_any,
|
||||
ignore_duration,
|
||||
),
|
||||
(
|
||||
"_press_left",
|
||||
EventListenerKind::MousePress,
|
||||
button_left,
|
||||
ignore_duration,
|
||||
),
|
||||
(
|
||||
"_release_left",
|
||||
EventListenerKind::MouseRelease,
|
||||
left_button,
|
||||
button_left,
|
||||
ignore_duration,
|
||||
),
|
||||
(
|
||||
"_press_right",
|
||||
EventListenerKind::MousePress,
|
||||
button_right,
|
||||
ignore_duration,
|
||||
),
|
||||
("_press_right", EventListenerKind::MousePress, right_button),
|
||||
(
|
||||
"_release_right",
|
||||
EventListenerKind::MouseRelease,
|
||||
right_button,
|
||||
button_right,
|
||||
ignore_duration,
|
||||
),
|
||||
(
|
||||
"_press_middle",
|
||||
EventListenerKind::MousePress,
|
||||
middle_button,
|
||||
button_middle,
|
||||
ignore_duration,
|
||||
),
|
||||
(
|
||||
"_release_middle",
|
||||
EventListenerKind::MouseRelease,
|
||||
middle_button,
|
||||
button_middle,
|
||||
ignore_duration,
|
||||
),
|
||||
(
|
||||
"_short_release",
|
||||
EventListenerKind::MouseRelease,
|
||||
button_any,
|
||||
short_duration,
|
||||
),
|
||||
(
|
||||
"_short_release_left",
|
||||
EventListenerKind::MouseRelease,
|
||||
button_left,
|
||||
short_duration,
|
||||
),
|
||||
(
|
||||
"_short_release_right",
|
||||
EventListenerKind::MouseRelease,
|
||||
button_right,
|
||||
short_duration,
|
||||
),
|
||||
(
|
||||
"_short_release_middle",
|
||||
EventListenerKind::MouseRelease,
|
||||
button_middle,
|
||||
short_duration,
|
||||
),
|
||||
(
|
||||
"_long_release",
|
||||
EventListenerKind::MouseRelease,
|
||||
button_any,
|
||||
long_duration,
|
||||
),
|
||||
(
|
||||
"_long_release_left",
|
||||
EventListenerKind::MouseRelease,
|
||||
button_left,
|
||||
long_duration,
|
||||
),
|
||||
(
|
||||
"_long_release_right",
|
||||
EventListenerKind::MouseRelease,
|
||||
button_right,
|
||||
long_duration,
|
||||
),
|
||||
(
|
||||
"_long_release_middle",
|
||||
EventListenerKind::MouseRelease,
|
||||
button_middle,
|
||||
long_duration,
|
||||
),
|
||||
];
|
||||
|
||||
fn any_button(_: &mut CallbackData) -> bool {
|
||||
fn button_any(_: &mut CallbackData) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn left_button(data: &mut CallbackData) -> bool {
|
||||
fn button_left(data: &mut CallbackData) -> bool {
|
||||
if let CallbackMetadata::MouseButton(b) = data.metadata
|
||||
&& let MouseButtonIndex::Left = b.index
|
||||
{
|
||||
@@ -73,7 +150,7 @@ fn left_button(data: &mut CallbackData) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
fn right_button(data: &mut CallbackData) -> bool {
|
||||
fn button_right(data: &mut CallbackData) -> bool {
|
||||
if let CallbackMetadata::MouseButton(b) = data.metadata
|
||||
&& let MouseButtonIndex::Right = b.index
|
||||
{
|
||||
@@ -82,7 +159,7 @@ fn right_button(data: &mut CallbackData) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
fn middle_button(data: &mut CallbackData) -> bool {
|
||||
fn button_middle(data: &mut CallbackData) -> bool {
|
||||
if let CallbackMetadata::MouseButton(b) = data.metadata
|
||||
&& let MouseButtonIndex::Middle = b.index
|
||||
{
|
||||
@@ -92,13 +169,23 @@ fn middle_button(data: &mut CallbackData) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn ignore_duration(_btn: &ComponentButton, _app: &AppState) -> bool {
|
||||
true
|
||||
}
|
||||
fn long_duration(btn: &ComponentButton, app: &AppState) -> bool {
|
||||
btn.get_time_since_last_pressed().as_secs_f32() > app.session.config.long_press_duration
|
||||
}
|
||||
fn short_duration(btn: &ComponentButton, app: &AppState) -> bool {
|
||||
btn.get_time_since_last_pressed().as_secs_f32() < app.session.config.long_press_duration
|
||||
}
|
||||
|
||||
pub(super) fn setup_custom_button<S: 'static>(
|
||||
layout: &mut Layout,
|
||||
attribs: &CustomAttribsInfoOwned,
|
||||
_app: &AppState,
|
||||
button: Rc<ComponentButton>,
|
||||
) {
|
||||
for (name, kind, test_btn) in &BUTTON_EVENTS {
|
||||
for (name, kind, test_button, test_duration) in &BUTTON_EVENTS {
|
||||
let Some(action) = attribs.get_value(name) else {
|
||||
continue;
|
||||
};
|
||||
@@ -108,10 +195,12 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
continue;
|
||||
};
|
||||
|
||||
let button = button.clone();
|
||||
|
||||
let callback: EventCallback<AppState, S> = match command {
|
||||
#[cfg(feature = "wayvr")]
|
||||
"::DashToggle" => Box::new(move |_common, data, app, _| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -126,7 +215,7 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
return;
|
||||
};
|
||||
Box::new(move |_common, data, app, _| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -142,7 +231,7 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
};
|
||||
|
||||
Box::new(move |_common, data, app, _| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -160,7 +249,7 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
})
|
||||
}
|
||||
"::EditToggle" => Box::new(move |_common, data, app, _| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -170,7 +259,7 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
}),
|
||||
#[cfg(feature = "wayland")]
|
||||
"::NewMirror" => Box::new(move |_common, data, app, _| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -187,7 +276,7 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
Ok(EventResult::Consumed)
|
||||
}),
|
||||
"::CleanupMirrors" => Box::new(move |_common, data, app, _| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -196,7 +285,7 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
Ok(EventResult::Consumed)
|
||||
}),
|
||||
"::PlayspaceReset" => Box::new(move |_common, data, app, _| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -204,7 +293,7 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
Ok(EventResult::Consumed)
|
||||
}),
|
||||
"::PlayspaceRecenter" => Box::new(move |_common, data, app, _| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -213,7 +302,7 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
Ok(EventResult::Consumed)
|
||||
}),
|
||||
"::PlayspaceFixFloor" => Box::new(move |_common, data, app, _| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -233,8 +322,8 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
);
|
||||
Ok(EventResult::Consumed)
|
||||
}),
|
||||
"::Shutdown" => Box::new(move |_common, data, _app, _| {
|
||||
if !test_btn(data) {
|
||||
"::Shutdown" => Box::new(move |_common, data, app, _| {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -255,7 +344,7 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
return;
|
||||
};
|
||||
Box::new(move |_common, data, app, _| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -285,8 +374,8 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
}),
|
||||
);
|
||||
|
||||
Box::new(move |_common, data, _app, _| {
|
||||
if !test_btn(data) {
|
||||
Box::new(move |_common, data, app, _| {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -314,7 +403,7 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
}
|
||||
|
||||
Box::new(move |_common, data, app, _| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,8 @@ pub type OnCustomIdFunc<S> = Box<
|
||||
) -> anyhow::Result<()>,
|
||||
>;
|
||||
|
||||
pub type OnCustomAttribFunc = Box<dyn Fn(&mut Layout, &CustomAttribsInfoOwned, &AppState)>;
|
||||
pub type OnCustomAttribFunc =
|
||||
Box<dyn Fn(&mut Layout, &ParserState, &CustomAttribsInfoOwned, &AppState)>;
|
||||
|
||||
pub struct NewGuiPanelParams<S> {
|
||||
pub on_custom_id: Option<OnCustomIdFunc<S>>, // used only in `new_from_template`
|
||||
@@ -155,7 +156,7 @@ impl<S: 'static> GuiPanel<S> {
|
||||
}
|
||||
|
||||
if let Some(on_custom_attrib) = ¶ms.on_custom_attrib {
|
||||
on_custom_attrib(&mut layout, elem, app);
|
||||
on_custom_attrib(&mut layout, &parser_state, elem, app);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,21 +47,9 @@ mod sprite_tab;
|
||||
mod stereo;
|
||||
pub mod tab;
|
||||
|
||||
pub(super) struct LongPressButtonState {
|
||||
pub(super) pressed: Instant,
|
||||
}
|
||||
impl Default for LongPressButtonState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
pressed: Instant::now(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct EditModeState {
|
||||
tasks: Rc<RefCell<TaskContainer>>,
|
||||
id: Rc<RefCell<OverlayID>>,
|
||||
delete: LongPressButtonState,
|
||||
tabs: ButtonPaneTabSwitcher,
|
||||
lock: InteractLockHandler,
|
||||
pos: SpriteTabHandler<PosTabState>,
|
||||
@@ -272,9 +260,6 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
||||
let state = EditModeState {
|
||||
id: Rc::new(RefCell::new(OverlayID::null())),
|
||||
tasks: Rc::new(RefCell::new(TaskContainer::new())),
|
||||
delete: LongPressButtonState {
|
||||
pressed: Instant::now(),
|
||||
},
|
||||
tabs: ButtonPaneTabSwitcher::default(),
|
||||
lock: InteractLockHandler::default(),
|
||||
pos: SpriteTabHandler::default(),
|
||||
@@ -284,8 +269,14 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
||||
|
||||
let anim_mult = app.wgui_globals.defaults().animation_mult;
|
||||
|
||||
let on_custom_attrib: OnCustomAttribFunc = Box::new(move |layout, attribs, _app| {
|
||||
for (name, kind, test_btn) in &BUTTON_EVENTS {
|
||||
let on_custom_attrib: OnCustomAttribFunc = Box::new(move |layout, parser, attribs, _app| {
|
||||
let Ok(button) =
|
||||
parser.fetch_component_from_widget_id_as::<ComponentButton>(attribs.widget_id)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
for (name, kind, test_button, test_duration) in &BUTTON_EVENTS {
|
||||
let Some(action) = attribs.get_value(name) else {
|
||||
continue;
|
||||
};
|
||||
@@ -295,9 +286,11 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
||||
continue;
|
||||
};
|
||||
|
||||
let button = button.clone();
|
||||
|
||||
let callback: EventCallback<AppState, EditModeState> = match command {
|
||||
"::EditModeToggleLock" => Box::new(move |common, data, app, state| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -308,7 +301,7 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
||||
Ok(EventResult::Consumed)
|
||||
}),
|
||||
"::EditModeToggleGrab" => Box::new(move |_common, data, app, state| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -324,8 +317,8 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
||||
}),
|
||||
"::EditModeTab" => {
|
||||
let tab_name = args.next().unwrap().to_owned();
|
||||
Box::new(move |common, data, _app, state| {
|
||||
if !test_btn(data) {
|
||||
Box::new(move |common, data, app, state| {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -336,7 +329,7 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
||||
"::EditModeSetPos" => {
|
||||
let key = args.next().unwrap().to_owned();
|
||||
Box::new(move |common, data, app, state| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -350,7 +343,7 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
||||
"::EditModeSetStereo" => {
|
||||
let key = args.next().unwrap().to_owned();
|
||||
Box::new(move |common, data, app, state| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -364,7 +357,7 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
||||
"::EditModeSetMouse" => {
|
||||
let key = args.next().unwrap().to_owned();
|
||||
Box::new(move |common, data, app, state| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -375,23 +368,11 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
||||
Ok(EventResult::Consumed)
|
||||
})
|
||||
}
|
||||
"::EditModeDeletePress" => Box::new(move |_common, data, _app, state| {
|
||||
if !test_btn(data) {
|
||||
"::EditModeDelete" => Box::new(move |_common, data, app, state| {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
state.delete.pressed = Instant::now();
|
||||
// TODO: animate to light up button after 2s
|
||||
Ok(EventResult::Consumed)
|
||||
}),
|
||||
"::EditModeDeleteRelease" => Box::new(move |_common, data, app, state| {
|
||||
if !test_btn(data) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
if state.delete.pressed.elapsed() < Duration::from_secs(1) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify(
|
||||
OverlaySelector::Id(*state.id.borrow()),
|
||||
Box::new(move |_app, owc| {
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
rc::Rc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use std::{collections::HashMap, rc::Rc, time::Duration};
|
||||
|
||||
use glam::{Affine3A, Quat, Vec3, Vec3A, vec3};
|
||||
use idmap::DirectIdMap;
|
||||
@@ -31,7 +27,6 @@ use crate::{
|
||||
panel::{GuiPanel, NewGuiPanelParams, OnCustomAttribFunc, button::BUTTON_EVENTS},
|
||||
timer::GuiTimer,
|
||||
},
|
||||
overlays::edit::LongPressButtonState,
|
||||
state::AppState,
|
||||
windowing::{
|
||||
OverlayID, OverlaySelector, Z_ORDER_WATCH,
|
||||
@@ -70,7 +65,6 @@ struct WatchState {
|
||||
keyboard_oid: OverlayID,
|
||||
dashboard_oid: OverlayID,
|
||||
num_sets: usize,
|
||||
delete: LongPressButtonState,
|
||||
}
|
||||
|
||||
#[allow(clippy::significant_drop_tightening)]
|
||||
@@ -78,8 +72,14 @@ struct WatchState {
|
||||
pub fn create_watch(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
||||
let state = WatchState::default();
|
||||
|
||||
let on_custom_attrib: OnCustomAttribFunc = Box::new(move |layout, attribs, _app| {
|
||||
for (name, kind, test_btn) in &BUTTON_EVENTS {
|
||||
let on_custom_attrib: OnCustomAttribFunc = Box::new(move |layout, parser, attribs, _app| {
|
||||
let Ok(button) =
|
||||
parser.fetch_component_from_widget_id_as::<ComponentButton>(attribs.widget_id)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
for (name, kind, test_button, test_duration) in &BUTTON_EVENTS {
|
||||
let Some(action) = attribs.get_value(name) else {
|
||||
continue;
|
||||
};
|
||||
@@ -89,29 +89,20 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
||||
continue;
|
||||
};
|
||||
|
||||
let button = button.clone();
|
||||
|
||||
let callback: EventCallback<AppState, WatchState> = match command {
|
||||
"::EditModeDeleteDown" => Box::new(move |_common, data, _app, state| {
|
||||
if !test_btn(data) {
|
||||
"::EditModeDeleteSet" => Box::new(move |_common, data, app, _state| {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
state.delete.pressed = Instant::now();
|
||||
Ok(EventResult::Consumed)
|
||||
}),
|
||||
"::EditModeDeleteUp" => Box::new(move |_common, data, app, state| {
|
||||
if !test_btn(data) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
if state.delete.pressed.elapsed() < Duration::from_secs(1) {
|
||||
return Ok(EventResult::Consumed);
|
||||
}
|
||||
app.tasks
|
||||
.enqueue(TaskType::Overlay(OverlayTask::DeleteActiveSet));
|
||||
Ok(EventResult::Consumed)
|
||||
}),
|
||||
"::EditModeAddSet" => Box::new(move |_common, data, app, _state| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -125,7 +116,7 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
||||
return;
|
||||
};
|
||||
Box::new(move |_common, data, app, state| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -154,7 +145,7 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
||||
return;
|
||||
};
|
||||
Box::new(move |_common, data, app, state| {
|
||||
if !test_btn(data) {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
@@ -170,6 +161,29 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
||||
Ok(EventResult::Consumed)
|
||||
})
|
||||
}
|
||||
"::SingleSetOverlayReset" => {
|
||||
let arg = args.next().unwrap_or_default();
|
||||
let Ok(idx) = arg.parse::<usize>() else {
|
||||
log::error!("{command} has invalid argument: \"{arg}\"");
|
||||
return;
|
||||
};
|
||||
Box::new(move |_common, data, app, state| {
|
||||
if !test_button(data) || !test_duration(&button, app) {
|
||||
return Ok(EventResult::Pass);
|
||||
}
|
||||
|
||||
let Some(overlay) = state.overlay_metas.get(idx) else {
|
||||
log::error!("No overlay at index {idx}.");
|
||||
return Ok(EventResult::Consumed);
|
||||
};
|
||||
|
||||
app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify(
|
||||
OverlaySelector::Id(overlay.id),
|
||||
Box::new(|app, owc| owc.activate(app)),
|
||||
)));
|
||||
Ok(EventResult::Consumed)
|
||||
})
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
#color_accent: "#008cff"
|
||||
#color_danger: "#ff3300"
|
||||
#color_faded: "#668299"
|
||||
#color_background: "#010206",
|
||||
#color_background: "#010206"
|
||||
|
||||
## Multiplier for animation speed. 2.0 → double speed, 0.5 → half speed
|
||||
#animation_speed: 1.0
|
||||
@@ -175,6 +175,10 @@
|
||||
#xr_click_sensitivity: 0.7
|
||||
#xr_click_sensitivity_release: 0.5
|
||||
|
||||
## How many seconds to buttons need to be held
|
||||
## before it's considered a long press
|
||||
#long_press_duration: 1.0
|
||||
|
||||
## Change speed of scrolling
|
||||
# 0.5 → half the speed
|
||||
# 2.0 → twice the speed
|
||||
|
||||
Reference in New Issue
Block a user