mirror of
https://github.com/slint-ui/slint.git
synced 2025-11-01 20:31:27 +00:00
ContextMenuArea: Intercept long press on Android
This commit is contained in:
parent
bd80829a44
commit
7390df1b47
5 changed files with 53 additions and 7 deletions
|
|
@ -235,7 +235,9 @@ fn default_config() -> cbindgen::Config {
|
|||
config.defines = [
|
||||
("target_pointer_width = 64".into(), "SLINT_TARGET_64".into()),
|
||||
("target_pointer_width = 32".into(), "SLINT_TARGET_32".into()),
|
||||
("target_arch = wasm32".into(), "SLINT_TARGET_WASM".into()), // Disable any wasm guarded code in C++, too - so that there are no gaps in enums.
|
||||
// Disable any wasm guarded code in C++, too - so that there are no gaps in enums.
|
||||
("target_arch = wasm32".into(), "SLINT_TARGET_WASM".into()),
|
||||
("target_os = android".into(), "__ANDROID__".into()),
|
||||
]
|
||||
.iter()
|
||||
.cloned()
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ Use the non-visual `ContextMenuArea` element to declare an area where the user c
|
|||
|
||||
The context menu is shown if the user right-clicks on the area covered by the `ContextMenuArea` element,
|
||||
or if the user presses the "Menu" key on their keyboard while a `FocusScope` within the `ContextMenuArea` has focus.
|
||||
On Android, the menu is shown with a long press.
|
||||
Call the `show()` function on the `ContextMenuArea` element to programmatically show the context menu.
|
||||
|
||||
One of the children of the `ContextMenuArea` must be a `Menu` element, which defines the menu to be shown.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ pub use android_activity::AndroidApp;
|
|||
use android_activity::PollEvent;
|
||||
use androidwindowadapter::AndroidWindowAdapter;
|
||||
use core::ops::ControlFlow;
|
||||
use core::time::Duration;
|
||||
use i_slint_core::api::{EventLoopError, PlatformError};
|
||||
use i_slint_core::platform::{Clipboard, WindowAdapter};
|
||||
use i_slint_renderer_skia::SkiaRendererExt;
|
||||
|
|
@ -100,7 +101,7 @@ impl i_slint_core::platform::Platform for AndroidPlatform {
|
|||
let mut timeout = i_slint_core::platform::duration_until_next_timer_update();
|
||||
if self.window.window.has_active_animations() {
|
||||
// FIXME: we should not hardcode a value here
|
||||
let frame_duration = std::time::Duration::from_millis(10);
|
||||
let frame_duration = Duration::from_millis(10);
|
||||
timeout = Some(match timeout {
|
||||
Some(x) => x.min(frame_duration),
|
||||
None => frame_duration,
|
||||
|
|
@ -152,6 +153,10 @@ impl i_slint_core::platform::Platform for AndroidPlatform {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn long_press_interval(&self, _: i_slint_core::InternalToken) -> Duration {
|
||||
self.window.java_helper.long_press_timeout().unwrap_or(Duration::from_millis(500))
|
||||
}
|
||||
}
|
||||
|
||||
enum Event {
|
||||
|
|
|
|||
|
|
@ -1216,6 +1216,8 @@ pub struct ContextMenu {
|
|||
pub show: Callback<PointArg>,
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
pub popup_id: Cell<Option<NonZeroU32>>,
|
||||
#[cfg(target_os = "android")]
|
||||
long_press_timer: Cell<Option<crate::timers::Timer>>,
|
||||
}
|
||||
|
||||
impl Item for ContextMenu {
|
||||
|
|
@ -1244,11 +1246,40 @@ impl Item for ContextMenu {
|
|||
_window_adapter: &Rc<dyn WindowAdapter>,
|
||||
_self_rc: &ItemRc,
|
||||
) -> InputEventResult {
|
||||
if let MouseEvent::Pressed { position, button: PointerEventButton::Right, .. } = event {
|
||||
self.show.call(&(crate::api::LogicalPosition::from_euclid(position),));
|
||||
InputEventResult::EventAccepted
|
||||
} else {
|
||||
InputEventResult::EventIgnored
|
||||
match event {
|
||||
MouseEvent::Pressed { position, button: PointerEventButton::Right, .. } => {
|
||||
self.show.call(&(crate::api::LogicalPosition::from_euclid(position),));
|
||||
InputEventResult::EventAccepted
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
MouseEvent::Pressed { position, button: PointerEventButton::Left, .. } => {
|
||||
let timer = crate::timers::Timer::default();
|
||||
let self_weak = _self_rc.downgrade();
|
||||
timer.start(
|
||||
crate::timers::TimerMode::SingleShot,
|
||||
WindowInner::from_pub(_window_adapter.window())
|
||||
.ctx
|
||||
.platform()
|
||||
.long_press_interval(crate::InternalToken),
|
||||
move || {
|
||||
let Some(self_rc) = self_weak.upgrade() else { return };
|
||||
let Some(self_) = self_rc.downcast::<ContextMenu>() else { return };
|
||||
self_.show.call(&(crate::api::LogicalPosition::from_euclid(position),));
|
||||
},
|
||||
);
|
||||
self.long_press_timer.set(Some(timer));
|
||||
InputEventResult::GrabMouse
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
MouseEvent::Released { .. } | MouseEvent::Exit => {
|
||||
if let Some(timer) = self.long_press_timer.take() {
|
||||
timer.stop();
|
||||
}
|
||||
InputEventResult::EventIgnored
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
MouseEvent::Moved { .. } => InputEventResult::EventAccepted,
|
||||
_ => InputEventResult::EventIgnored,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -126,6 +126,13 @@ pub trait Platform {
|
|||
fn debug_log(&self, _arguments: core::fmt::Arguments) {
|
||||
crate::tests::default_debug_log(_arguments);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
#[doc(hidden)]
|
||||
/// The long press interval before showing a context menu
|
||||
fn long_press_interval(&self, _: crate::InternalToken) -> core::time::Duration {
|
||||
core::time::Duration::from_millis(500)
|
||||
}
|
||||
}
|
||||
|
||||
/// The clip board, used in [`Platform::clipboard_text`] and [Platform::set_clipboard_text`]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue