input: Add InputBackend::set_mouse_cursor. Change cursor on buttons

It doesn't feel like Flash without having the hand cursor display
when hovering over buttons. First pass at implementing this;
core communicates which mouse cursor to use via
`InputBackend::set_mouse_cursor`.

TODO: Hand cursor only displayed for Button display objects
currently. Movie clips should also display this when they are in
"button mode" (when a button mouse event is set on them in AVM1,
or `buttonMode` property in AVM2).
This commit is contained in:
Mike Welsh 2020-02-25 01:45:38 -08:00
parent a917fa4028
commit 86ec2c6cb8
4 changed files with 83 additions and 13 deletions

View File

@ -11,6 +11,9 @@ pub trait InputBackend: Downcast {
fn hide_mouse(&mut self);
fn show_mouse(&mut self);
/// Changes the mouse cursor image.
fn set_mouse_cursor(&mut self, cursor: MouseCursor);
}
impl_downcast!(InputBackend);
@ -39,6 +42,8 @@ impl InputBackend for NullInputBackend {
fn hide_mouse(&mut self) {}
fn show_mouse(&mut self) {}
fn set_mouse_cursor(&mut self, _cursor: MouseCursor) {}
}
impl Default for NullInputBackend {
@ -46,3 +51,24 @@ impl Default for NullInputBackend {
NullInputBackend::new()
}
}
/// A mouse cursor icon displayed by the Flash Player.
/// Communicated from the core to the input backend via `InputBackend::set_mouse_cursor`.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MouseCursor {
/// The default arrow icon.
/// Equivalent to AS3 `MouseCursor.ARROW`.
Arrow,
/// The hand icon incdicating a button or link.
/// Equivalent to AS3 `MouseCursor.BUTTON`.
Hand,
/// The text I-beam.
/// Equivalent to AS3 `MouseCursor.IBEAM`.
IBeam,
/// The grabby-dragging hand icon.
/// Equivalent to AS3 `MouseCursor.HAND`.
Grab,
}

View File

@ -1,6 +1,6 @@
use crate::avm1::listeners::SystemListener;
use crate::avm1::Avm1;
use crate::backend::input::InputBackend;
use crate::backend::input::{InputBackend, MouseCursor};
use crate::backend::{
audio::AudioBackend, navigator::NavigatorBackend, render::Letterbox, render::RenderBackend,
};
@ -130,6 +130,9 @@ pub struct Player {
mouse_pos: (Twips, Twips),
is_mouse_down: bool,
/// The current mouse cursor icon.
mouse_cursor: MouseCursor,
/// Self-reference to ourselves.
///
/// This is a weak reference that is upgraded and handed out in various
@ -224,6 +227,7 @@ impl Player {
mouse_pos: (Twips::new(0), Twips::new(0)),
is_mouse_down: false,
mouse_cursor: MouseCursor::Arrow,
renderer,
audio,
@ -485,7 +489,8 @@ impl Player {
}
let mouse_pos = self.mouse_pos;
self.mutate_with_update_context(|avm, context| {
let mut new_cursor = self.mouse_cursor;
let hover_changed = self.mutate_with_update_context(|avm, context| {
// Check hovered object.
let mut new_hovered = None;
for (_depth, level) in context.levels.iter().rev() {
@ -507,9 +512,11 @@ impl Player {
}
// RollOver on new node.
new_cursor = MouseCursor::Arrow;
if let Some(node) = new_hovered {
if let Some(mut button) = node.as_button() {
button.handle_button_event(context, ButtonEvent::RollOver);
new_cursor = MouseCursor::Hand;
}
}
@ -520,7 +527,15 @@ impl Player {
} else {
false
}
})
});
// Update mouse cursor if it has changed.
if new_cursor != self.mouse_cursor {
self.mouse_cursor = new_cursor;
self.input.set_mouse_cursor(new_cursor)
}
hover_changed
}
/// Preload the first movie in the player.

View File

@ -1,5 +1,5 @@
use glium::Display;
use ruffle_core::backend::input::InputBackend;
use ruffle_core::backend::input::{InputBackend, MouseCursor};
use ruffle_core::events::{KeyCode, PlayerEvent};
use std::collections::HashSet;
use winit::event::{ElementState, VirtualKeyCode, WindowEvent};
@ -178,6 +178,17 @@ impl InputBackend for WinitInputBackend {
self.display.gl_window().window().set_cursor_visible(true);
self.cursor_visible = true;
}
fn set_mouse_cursor(&mut self, cursor: MouseCursor) {
use winit::window::CursorIcon;
let icon = match cursor {
MouseCursor::Arrow => CursorIcon::Arrow,
MouseCursor::Hand => CursorIcon::Hand,
MouseCursor::IBeam => CursorIcon::Text,
MouseCursor::Grab => CursorIcon::Grab,
};
self.display.gl_window().window().set_cursor_icon(icon);
}
}
/// Converts a winit `VirtualKeyCode` into a Ruffle `KeyCode`.

View File

@ -1,5 +1,5 @@
use crate::utils::JsResult;
use ruffle_core::backend::input::InputBackend;
use ruffle_core::backend::input::{InputBackend, MouseCursor};
use ruffle_core::events::KeyCode;
use std::collections::HashSet;
use web_sys::HtmlCanvasElement;
@ -10,6 +10,7 @@ pub struct WebInputBackend {
keys_down: HashSet<String>,
canvas: HtmlCanvasElement,
cursor_visible: bool,
cursor: MouseCursor,
last_key: KeyCode,
}
@ -19,6 +20,7 @@ impl WebInputBackend {
keys_down: HashSet::new(),
canvas: canvas.clone(),
cursor_visible: true,
cursor: MouseCursor::Arrow,
last_key: KeyCode::Unknown,
}
}
@ -33,6 +35,23 @@ impl WebInputBackend {
pub fn keyup(&mut self, code: String) {
self.keys_down.remove(&code);
}
fn update_mouse_cursor(&self) {
let cursor = if self.cursor_visible {
"none"
} else {
match self.cursor {
MouseCursor::Arrow => "auto",
MouseCursor::Hand => "pointer",
MouseCursor::IBeam => "text",
MouseCursor::Grab => "grab",
}
};
self.canvas
.style()
.set_property("cursor", cursor)
.warn_on_error();
}
}
impl InputBackend for WebInputBackend {
@ -151,19 +170,18 @@ impl InputBackend for WebInputBackend {
}
fn hide_mouse(&mut self) {
self.canvas
.style()
.set_property("cursor", "none")
.warn_on_error();
self.cursor_visible = false;
self.update_mouse_cursor();
}
fn show_mouse(&mut self) {
self.canvas
.style()
.set_property("cursor", "auto")
.warn_on_error();
self.cursor_visible = true;
self.update_mouse_cursor();
}
fn set_mouse_cursor(&mut self, cursor: MouseCursor) {
self.cursor = cursor;
self.update_mouse_cursor();
}
}