From 86ec2c6cb8d52977438f8a279791aff555a5f18d Mon Sep 17 00:00:00 2001 From: Mike Welsh Date: Tue, 25 Feb 2020 01:45:38 -0800 Subject: [PATCH] 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). --- core/src/backend/input.rs | 26 ++++++++++++++++++++++++++ core/src/player.rs | 21 ++++++++++++++++++--- desktop/src/input.rs | 13 ++++++++++++- web/src/input.rs | 36 +++++++++++++++++++++++++++--------- 4 files changed, 83 insertions(+), 13 deletions(-) diff --git a/core/src/backend/input.rs b/core/src/backend/input.rs index a12bd952e..6c74eb7ec 100644 --- a/core/src/backend/input.rs +++ b/core/src/backend/input.rs @@ -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, +} diff --git a/core/src/player.rs b/core/src/player.rs index 7c7d0488a..488748024 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -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. diff --git a/desktop/src/input.rs b/desktop/src/input.rs index 398286d0e..a47274f21 100644 --- a/desktop/src/input.rs +++ b/desktop/src/input.rs @@ -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`. diff --git a/web/src/input.rs b/web/src/input.rs index 30d196610..c5dc71c0d 100644 --- a/web/src/input.rs +++ b/web/src/input.rs @@ -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, 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(); } }