From 1883daff225e539fbbc390f7ac326f1387177e26 Mon Sep 17 00:00:00 2001 From: Kamil Jarosz Date: Thu, 14 Mar 2024 22:25:33 +0100 Subject: [PATCH] avm1: Support `MovieClip.tabChildren` The property `MovieClip.tabChildren` allows changing the behavior of tab ordering hierarchically. When set to `false`, it excludes the whole subtree represented by the movie clip from tab ordering. --- core/src/avm1/globals/movie_clip.rs | 1 + core/src/display_object/container.rs | 9 ++++++++- core/src/display_object/movie_clip.rs | 12 ++++++++++++ core/src/focus_tracker.rs | 4 +++- 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/core/src/avm1/globals/movie_clip.rs b/core/src/avm1/globals/movie_clip.rs index db100ab3e0f4..d73af86ec2aa 100644 --- a/core/src/avm1/globals/movie_clip.rs +++ b/core/src/avm1/globals/movie_clip.rs @@ -119,6 +119,7 @@ const PROTO_DECLS: &[Declaration] = declare_properties! { // NOTE: `tabEnabled` is not a built-in property of MovieClip. // NOTE: `tabIndex` is not enumerable in MovieClip, contrary to Button and TextField "tabIndex" => property(mc_getter!(tab_index), mc_setter!(set_tab_index); DONT_ENUM | VERSION_6); + // NOTE: `tabChildren` is not a built-in property of MovieClip. }; /// Implements `MovieClip` diff --git a/core/src/display_object/container.rs b/core/src/display_object/container.rs index 96c2e912cb3c..8d45d23371e2 100644 --- a/core/src/display_object/container.rs +++ b/core/src/display_object/container.rs @@ -475,12 +475,19 @@ pub trait TDisplayObjectContainer<'gc>: RenderIter::from_container(self.into()) } + fn is_tab_children(&self, _context: &mut UpdateContext<'_, 'gc>) -> bool { + true + } + fn fill_tab_order( &self, tab_order: &mut Vec>, context: &mut UpdateContext<'_, 'gc>, ) { - // TODO Add support for `tabChildren` + if !self.is_tab_children(context) { + return; + } + for child in self.iter_render_list() { if child.is_tab_enabled(context) { tab_order.push(child); diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index 95bb7b61d494..29bd73075c15 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -3051,6 +3051,18 @@ impl<'gc> TDisplayObjectContainer<'gc> for MovieClip<'gc> { fn raw_container_mut(&self, gc_context: &Mutation<'gc>) -> RefMut<'_, ChildContainer<'gc>> { RefMut::map(self.0.write(gc_context), |this| &mut this.container) } + + /// The property `MovieClip.tabChildren` allows changing the behavior of + /// tab ordering hierarchically. + /// When set to `false`, it excludes the whole subtree represented by + /// the movie clip from tab ordering. + /// + /// _NOTE:_ + /// According to the AS2 documentation, it should affect only automatic tab ordering. + /// However, that does not seem to be the case, as it also affects custom ordering. + fn is_tab_children(&self, context: &mut UpdateContext<'_, 'gc>) -> bool { + self.get_avm1_boolean_property(context, "tabChildren", true) + } } impl<'gc> TInteractiveObject<'gc> for MovieClip<'gc> { diff --git a/core/src/focus_tracker.rs b/core/src/focus_tracker.rs index 50b5f0f793e3..43b1917ce8e4 100644 --- a/core/src/focus_tracker.rs +++ b/core/src/focus_tracker.rs @@ -108,6 +108,8 @@ impl<'gc> FocusTracker<'gc> { first }; - self.set(next.copied(), context); + if next.is_some() { + self.set(next.copied(), context); + } } }