core: Move has_focus to InteractiveObject
All the interactive objects had the has_focus flag in their concrete implementations (even AVM2 button, which did not use it at all). This patch moves it to InteractiveObject (as a bit flag), making it easier to manage and use through the has_focus, set_has_focus methods. Additionally, the operation of setting the current focus to None when an object was having it was popular enough that it warranted its own method of drop_focus.
This commit is contained in:
parent
19b7cc9025
commit
8d50d1fead
|
@ -45,7 +45,6 @@ pub struct Avm1ButtonData<'gc> {
|
|||
tracking: Cell<ButtonTracking>,
|
||||
object: Lock<Option<Object<'gc>>>,
|
||||
initialized: Cell<bool>,
|
||||
has_focus: Cell<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Collect)]
|
||||
|
@ -98,7 +97,6 @@ impl<'gc> Avm1Button<'gc> {
|
|||
} else {
|
||||
ButtonTracking::Push
|
||||
}),
|
||||
has_focus: Cell::new(false),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
@ -393,11 +391,7 @@ impl<'gc> TDisplayObject<'gc> for Avm1Button<'gc> {
|
|||
}
|
||||
|
||||
fn avm1_unload(&self, context: &mut UpdateContext<'_, 'gc>) {
|
||||
let had_focus = self.0.has_focus.get();
|
||||
if had_focus {
|
||||
let tracker = context.focus_tracker;
|
||||
tracker.set(None, context);
|
||||
}
|
||||
self.drop_focus(context);
|
||||
if let Some(node) = self.maskee() {
|
||||
node.set_masker(context.gc(), None, true);
|
||||
} else if let Some(node) = self.masker() {
|
||||
|
@ -530,7 +524,7 @@ impl<'gc> TInteractiveObject<'gc> for Avm1Button<'gc> {
|
|||
if let Some(name) = event.method_name() {
|
||||
// Keyboard events don't fire their methods
|
||||
// unless the Button has focus (like for MovieClips).
|
||||
if !event.is_key_event() || self.0.has_focus.get() {
|
||||
if !event.is_key_event() || self.has_focus() {
|
||||
context.action_queue.queue_action(
|
||||
self_display_object,
|
||||
ActionType::Method {
|
||||
|
@ -608,15 +602,6 @@ impl<'gc> TInteractiveObject<'gc> for Avm1Button<'gc> {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_focus_changed(
|
||||
&self,
|
||||
_context: &mut UpdateContext<'_, 'gc>,
|
||||
focused: bool,
|
||||
_other: Option<InteractiveObject<'gc>>,
|
||||
) {
|
||||
self.0.has_focus.set(focused);
|
||||
}
|
||||
|
||||
fn tab_enabled_avm1(&self, context: &mut UpdateContext<'_, 'gc>) -> bool {
|
||||
self.get_avm1_boolean_property(context, "tabEnabled", |_| true)
|
||||
}
|
||||
|
|
|
@ -74,7 +74,6 @@ pub struct Avm2ButtonData<'gc> {
|
|||
/// The AVM2 representation of this button.
|
||||
object: Lock<Option<Avm2Object<'gc>>>,
|
||||
|
||||
has_focus: Cell<bool>,
|
||||
enabled: Cell<bool>,
|
||||
use_hand_cursor: Cell<bool>,
|
||||
|
||||
|
@ -135,7 +134,6 @@ impl<'gc> Avm2Button<'gc> {
|
|||
} else {
|
||||
ButtonTracking::Push
|
||||
}),
|
||||
has_focus: Cell::new(false),
|
||||
enabled: Cell::new(true),
|
||||
use_hand_cursor: Cell::new(true),
|
||||
skip_current_frame: Cell::new(false),
|
||||
|
@ -823,15 +821,6 @@ impl<'gc> TInteractiveObject<'gc> for Avm2Button<'gc> {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_focus_changed(
|
||||
&self,
|
||||
_context: &mut UpdateContext<'_, 'gc>,
|
||||
focused: bool,
|
||||
_other: Option<InteractiveObject<'gc>>,
|
||||
) {
|
||||
self.0.has_focus.set(focused);
|
||||
}
|
||||
|
||||
fn tab_enabled_avm2_default(&self, _context: &mut UpdateContext<'_, 'gc>) -> bool {
|
||||
true
|
||||
}
|
||||
|
|
|
@ -987,7 +987,7 @@ impl<'gc> EditText<'gc> {
|
|||
..Default::default()
|
||||
});
|
||||
|
||||
let visible_selection = if edit_text.flags.contains(EditTextFlag::HAS_FOCUS) {
|
||||
let visible_selection = if self.has_focus() {
|
||||
edit_text.selection
|
||||
} else {
|
||||
None
|
||||
|
@ -2121,7 +2121,7 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
|
|||
let has_parent = self.parent().is_some();
|
||||
|
||||
if self.movie().is_action_script_3() && had_parent && !has_parent {
|
||||
let had_focus = self.0.read().flags.contains(EditTextFlag::HAS_FOCUS);
|
||||
let had_focus = self.has_focus();
|
||||
if had_focus {
|
||||
let tracker = context.focus_tracker;
|
||||
tracker.set(None, context);
|
||||
|
@ -2237,7 +2237,7 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
|
|||
});
|
||||
|
||||
if edit_text.layout.is_empty() && !edit_text.flags.contains(EditTextFlag::READ_ONLY) {
|
||||
let visible_selection = if edit_text.flags.contains(EditTextFlag::HAS_FOCUS) {
|
||||
let visible_selection = if self.has_focus() {
|
||||
edit_text.selection
|
||||
} else {
|
||||
None
|
||||
|
@ -2275,11 +2275,7 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
|
|||
}
|
||||
|
||||
fn avm1_unload(&self, context: &mut UpdateContext<'_, 'gc>) {
|
||||
let had_focus = self.0.read().flags.contains(EditTextFlag::HAS_FOCUS);
|
||||
if had_focus {
|
||||
let tracker = context.focus_tracker;
|
||||
tracker.set(None, context);
|
||||
}
|
||||
self.drop_focus(context);
|
||||
|
||||
if let Some(node) = self.maskee() {
|
||||
node.set_masker(context.gc_context, None, true);
|
||||
|
@ -2459,11 +2455,9 @@ impl<'gc> TInteractiveObject<'gc> for EditText<'gc> {
|
|||
focused: bool,
|
||||
_other: Option<InteractiveObject<'gc>>,
|
||||
) {
|
||||
let is_action_script_3 = self.movie().is_action_script_3();
|
||||
let mut text = self.0.write(context.gc_context);
|
||||
text.flags.set(EditTextFlag::HAS_FOCUS, focused);
|
||||
if !focused && !is_action_script_3 {
|
||||
text.selection = None;
|
||||
let is_avm1 = !self.movie().is_action_script_3();
|
||||
if !focused && is_avm1 {
|
||||
self.0.write(context.gc_context).selection = None;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2494,7 +2488,6 @@ bitflags::bitflags! {
|
|||
struct EditTextFlag: u16 {
|
||||
const FIRING_VARIABLE_BINDING = 1 << 0;
|
||||
const HAS_BACKGROUND = 1 << 1;
|
||||
const HAS_FOCUS = 1 << 2;
|
||||
|
||||
// The following bits need to match `swf::EditTextFlag`.
|
||||
const READ_ONLY = 1 << 3;
|
||||
|
|
|
@ -76,6 +76,9 @@ bitflags! {
|
|||
|
||||
/// Whether this `InteractiveObject` accepts double-clicks.
|
||||
const DOUBLE_CLICK_ENABLED = 1 << 1;
|
||||
|
||||
/// Whether this `InteractiveObject` is currently focused.
|
||||
const HAS_FOCUS = 1 << 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,6 +170,18 @@ pub trait TInteractiveObject<'gc>:
|
|||
.set(InteractiveObjectFlags::DOUBLE_CLICK_ENABLED, value)
|
||||
}
|
||||
|
||||
fn has_focus(self) -> bool {
|
||||
self.raw_interactive()
|
||||
.flags
|
||||
.contains(InteractiveObjectFlags::HAS_FOCUS)
|
||||
}
|
||||
|
||||
fn set_has_focus(self, mc: &Mutation<'gc>, value: bool) {
|
||||
self.raw_interactive_mut(mc)
|
||||
.flags
|
||||
.set(InteractiveObjectFlags::HAS_FOCUS, value)
|
||||
}
|
||||
|
||||
fn context_menu(self) -> Avm2Value<'gc> {
|
||||
self.raw_interactive().context_menu
|
||||
}
|
||||
|
@ -536,6 +551,14 @@ pub trait TInteractiveObject<'gc>:
|
|||
) {
|
||||
}
|
||||
|
||||
/// If this object has focus, this method drops it.
|
||||
fn drop_focus(&self, context: &mut UpdateContext<'_, 'gc>) {
|
||||
if self.has_focus() {
|
||||
let tracker = context.focus_tracker;
|
||||
tracker.set(None, context);
|
||||
}
|
||||
}
|
||||
|
||||
fn call_focus_handler(
|
||||
&self,
|
||||
context: &mut UpdateContext<'_, 'gc>,
|
||||
|
|
|
@ -162,7 +162,6 @@ pub struct MovieClipData<'gc> {
|
|||
avm2_class: Option<Avm2ClassObject<'gc>>,
|
||||
#[collect(require_static)]
|
||||
drawing: Drawing,
|
||||
has_focus: bool,
|
||||
avm2_enabled: bool,
|
||||
|
||||
/// Show a hand cursor when the clip is in button mode.
|
||||
|
@ -212,7 +211,6 @@ impl<'gc> MovieClip<'gc> {
|
|||
flags: MovieClipFlags::empty(),
|
||||
avm2_class: None,
|
||||
drawing: Drawing::new(),
|
||||
has_focus: false,
|
||||
avm2_enabled: true,
|
||||
avm2_use_hand_cursor: true,
|
||||
button_mode: false,
|
||||
|
@ -255,7 +253,6 @@ impl<'gc> MovieClip<'gc> {
|
|||
flags: MovieClipFlags::empty(),
|
||||
avm2_class: Some(class),
|
||||
drawing: Drawing::new(),
|
||||
has_focus: false,
|
||||
avm2_enabled: true,
|
||||
avm2_use_hand_cursor: true,
|
||||
button_mode: false,
|
||||
|
@ -299,7 +296,6 @@ impl<'gc> MovieClip<'gc> {
|
|||
flags: MovieClipFlags::PLAYING,
|
||||
avm2_class: None,
|
||||
drawing: Drawing::new(),
|
||||
has_focus: false,
|
||||
avm2_enabled: true,
|
||||
avm2_use_hand_cursor: true,
|
||||
button_mode: false,
|
||||
|
@ -368,7 +364,6 @@ impl<'gc> MovieClip<'gc> {
|
|||
flags: MovieClipFlags::PLAYING,
|
||||
avm2_class: None,
|
||||
drawing: Drawing::new(),
|
||||
has_focus: false,
|
||||
avm2_enabled: true,
|
||||
avm2_use_hand_cursor: true,
|
||||
button_mode: false,
|
||||
|
@ -2962,11 +2957,7 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
|
|||
}
|
||||
}
|
||||
|
||||
let had_focus = self.0.read().has_focus;
|
||||
if had_focus {
|
||||
let tracker = context.focus_tracker;
|
||||
tracker.set(None, context);
|
||||
}
|
||||
self.drop_focus(context);
|
||||
|
||||
{
|
||||
let mut mc = self.0.write(context.gc_context);
|
||||
|
@ -3101,7 +3092,7 @@ impl<'gc> TInteractiveObject<'gc> for MovieClip<'gc> {
|
|||
if swf_version >= 6 {
|
||||
if let Some(name) = event.method_name() {
|
||||
// Keyboard events don't fire their methods unless the MovieClip has focus (#2120).
|
||||
if !event.is_key_event() || read.has_focus {
|
||||
if !event.is_key_event() || self.has_focus() {
|
||||
context.action_queue.queue_action(
|
||||
self.into(),
|
||||
ActionType::Method {
|
||||
|
@ -3386,15 +3377,6 @@ impl<'gc> TInteractiveObject<'gc> for MovieClip<'gc> {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_focus_changed(
|
||||
&self,
|
||||
context: &mut UpdateContext<'_, 'gc>,
|
||||
focused: bool,
|
||||
_other: Option<InteractiveObject<'gc>>,
|
||||
) {
|
||||
self.0.write(context.gc_context).has_focus = focused;
|
||||
}
|
||||
|
||||
fn tab_enabled_avm1(&self, context: &mut UpdateContext<'_, 'gc>) -> bool {
|
||||
self.get_avm1_boolean_property(context, "tabEnabled", |context| {
|
||||
self.tab_index().is_some() || self.is_button_mode(context)
|
||||
|
|
|
@ -98,10 +98,12 @@ impl<'gc> FocusTracker<'gc> {
|
|||
self.update_highlight(context);
|
||||
|
||||
if let Some(old) = old {
|
||||
old.set_has_focus(context.gc(), false);
|
||||
old.on_focus_changed(context, false, new);
|
||||
old.call_focus_handler(context, false, new);
|
||||
}
|
||||
if let Some(new) = new {
|
||||
new.set_has_focus(context.gc(), true);
|
||||
new.on_focus_changed(context, true, old);
|
||||
new.call_focus_handler(context, true, old);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue