avm1: Fix some issues with `Selection.getFocus()` and `setFocus()`
This commit is contained in:
parent
7a6e6cf214
commit
5e165a0682
|
@ -2,7 +2,7 @@ use crate::avm1::activation::Activation;
|
||||||
use crate::avm1::error::Error;
|
use crate::avm1::error::Error;
|
||||||
use crate::avm1::globals::as_broadcaster::BroadcasterFunctions;
|
use crate::avm1::globals::as_broadcaster::BroadcasterFunctions;
|
||||||
use crate::avm1::property_decl::{define_properties_on, Declaration};
|
use crate::avm1::property_decl::{define_properties_on, Declaration};
|
||||||
use crate::avm1::{Object, ScriptObject, TObject, Value};
|
use crate::avm1::{Object, ScriptObject, Value};
|
||||||
use crate::display_object::{EditText, TDisplayObject, TextSelection};
|
use crate::display_object::{EditText, TDisplayObject, TextSelection};
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::MutationContext;
|
||||||
|
|
||||||
|
@ -108,10 +108,14 @@ pub fn get_focus<'gc>(
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
let focus = activation.context.focus_tracker.get();
|
let focus = activation.context.focus_tracker.get();
|
||||||
match focus {
|
Ok(match focus {
|
||||||
Some(focus) => Ok(focus.object()),
|
Some(focus) => focus
|
||||||
None => Ok(Value::Null),
|
.object()
|
||||||
}
|
.coerce_to_string(activation)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.into(),
|
||||||
|
None => Value::Null,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_focus<'gc>(
|
pub fn set_focus<'gc>(
|
||||||
|
@ -121,38 +125,23 @@ pub fn set_focus<'gc>(
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
let tracker = activation.context.focus_tracker;
|
let tracker = activation.context.focus_tracker;
|
||||||
match args.get(0) {
|
match args.get(0) {
|
||||||
|
None => Ok(false.into()),
|
||||||
Some(Value::Undefined | Value::Null) => {
|
Some(Value::Undefined | Value::Null) => {
|
||||||
tracker.set(None, &mut activation.context);
|
tracker.set(None, &mut activation.context);
|
||||||
Ok(true.into())
|
Ok(true.into())
|
||||||
}
|
}
|
||||||
Some(Value::Object(obj)) => {
|
Some(focus) => {
|
||||||
if let Some(display_object) = obj.as_display_object() {
|
let start_clip = activation.target_clip_or_root();
|
||||||
|
let object = activation.resolve_target_display_object(start_clip, *focus, false)?;
|
||||||
|
if let Some(display_object) = object {
|
||||||
if display_object.is_focusable() {
|
if display_object.is_focusable() {
|
||||||
tracker.set(Some(display_object), &mut activation.context);
|
tracker.set(object, &mut activation.context);
|
||||||
|
return Ok(true.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// [NA] Note: The documentation says true is success and false is failure,
|
|
||||||
// but from testing this seems to be opposite.
|
|
||||||
Ok(false.into())
|
Ok(false.into())
|
||||||
} else {
|
|
||||||
Ok(true.into())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(Value::MovieClip(_)) => {
|
|
||||||
let obj = args.get(0).unwrap().coerce_to_object(activation);
|
|
||||||
|
|
||||||
if let Some(display_object) = obj.as_display_object() {
|
|
||||||
if display_object.is_focusable() {
|
|
||||||
tracker.set(Some(display_object), &mut activation.context);
|
|
||||||
}
|
|
||||||
// [NA] Note: The documentation says true is success and false is failure,
|
|
||||||
// but from testing this seems to be opposite.
|
|
||||||
Ok(false.into())
|
|
||||||
} else {
|
|
||||||
Ok(true.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Ok(false.into()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_selection_object<'gc>(
|
pub fn create_selection_object<'gc>(
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use crate::avm1::Avm1;
|
use crate::avm1::Avm1;
|
||||||
use crate::avm1::Value;
|
use crate::avm1::Value;
|
||||||
use crate::context::UpdateContext;
|
use crate::context::UpdateContext;
|
||||||
pub use crate::display_object::{DisplayObject, TDisplayObject, TDisplayObjectContainer};
|
pub use crate::display_object::{
|
||||||
|
DisplayObject, TDisplayObject, TDisplayObjectContainer, TextSelection,
|
||||||
|
};
|
||||||
use gc_arena::{Collect, GcCell, MutationContext};
|
use gc_arena::{Collect, GcCell, MutationContext};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Collect)]
|
#[derive(Clone, Copy, Collect)]
|
||||||
|
@ -22,24 +24,15 @@ impl<'gc> FocusTracker<'gc> {
|
||||||
focused_element: Option<DisplayObject<'gc>>,
|
focused_element: Option<DisplayObject<'gc>>,
|
||||||
context: &mut UpdateContext<'_, 'gc>,
|
context: &mut UpdateContext<'_, 'gc>,
|
||||||
) {
|
) {
|
||||||
if let Some(text_field) = focused_element.and_then(|e| e.as_edit_text()) {
|
|
||||||
if text_field.is_editable() {
|
|
||||||
context.ui.open_virtual_keyboard();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let old = std::mem::replace(&mut *self.0.write(context.gc_context), focused_element);
|
let old = std::mem::replace(&mut *self.0.write(context.gc_context), focused_element);
|
||||||
|
|
||||||
if old.is_none() && focused_element.is_none() {
|
if old.is_none() && focused_element.is_none() {
|
||||||
// We didn't have anything, we still don't, no change.
|
// We didn't have anything, we still don't, no change.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if old.is_some() == focused_element.is_some()
|
if !(old.is_some() == focused_element.is_some()
|
||||||
&& old.unwrap().as_ptr() == focused_element.unwrap().as_ptr()
|
&& old.unwrap().as_ptr() == focused_element.unwrap().as_ptr())
|
||||||
{
|
{
|
||||||
// We're setting it to the same object as before, no change.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(old) = old {
|
if let Some(old) = old {
|
||||||
old.on_focus_changed(context.gc_context, false);
|
old.on_focus_changed(context.gc_context, false);
|
||||||
}
|
}
|
||||||
|
@ -62,4 +55,18 @@ impl<'gc> FocusTracker<'gc> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This applies even if the focused element hasn't changed.
|
||||||
|
if let Some(text_field) = focused_element.and_then(|e| e.as_edit_text()) {
|
||||||
|
if text_field.is_editable() {
|
||||||
|
let length = text_field.text_length();
|
||||||
|
text_field.set_selection(
|
||||||
|
Some(TextSelection::for_range(0, length)),
|
||||||
|
context.gc_context,
|
||||||
|
);
|
||||||
|
|
||||||
|
context.ui.open_virtual_keyboard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ _level0.a
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
false
|
true
|
||||||
|
|
||||||
// Selection.setFocus(b)
|
// Selection.setFocus(b)
|
||||||
! - onSetFocus
|
! - onSetFocus
|
||||||
|
@ -50,7 +50,7 @@ _level0.b
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
false
|
true
|
||||||
|
|
||||||
// Selection.setSelection(0)
|
// Selection.setSelection(0)
|
||||||
undefined
|
undefined
|
||||||
|
@ -133,7 +133,7 @@ _level0.b
|
||||||
|
|
||||||
|
|
||||||
// Selection.setFocus(b)
|
// Selection.setFocus(b)
|
||||||
false
|
true
|
||||||
|
|
||||||
// b.focusEnabled = false;
|
// b.focusEnabled = false;
|
||||||
// Selection.getBeginIndex()
|
// Selection.getBeginIndex()
|
||||||
|
@ -195,7 +195,7 @@ _level0.c
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
false
|
true
|
||||||
|
|
||||||
// Selection.setFocus(d)
|
// Selection.setFocus(d)
|
||||||
false
|
false
|
||||||
|
@ -246,7 +246,7 @@ _level0.button
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
false
|
true
|
||||||
|
|
||||||
// Selection.setFocus(text_input
|
// Selection.setFocus(text_input
|
||||||
! - onSetFocus
|
! - onSetFocus
|
||||||
|
@ -270,7 +270,7 @@ _level0.text_input
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
false
|
true
|
||||||
|
|
||||||
// Selection.setFocus(text_selectable)
|
// Selection.setFocus(text_selectable)
|
||||||
! - onSetFocus
|
! - onSetFocus
|
||||||
|
@ -294,7 +294,7 @@ _level0.text_selectable
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
false
|
true
|
||||||
|
|
||||||
// Selection.setSelection(0)
|
// Selection.setSelection(0)
|
||||||
undefined
|
undefined
|
||||||
|
@ -414,7 +414,7 @@ _level0.text_non_selectable
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
false
|
true
|
||||||
|
|
||||||
// Selection.setFocus(text_input)
|
// Selection.setFocus(text_input)
|
||||||
! - onSetFocus
|
! - onSetFocus
|
||||||
|
@ -438,7 +438,7 @@ _level0.text_input
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
false
|
true
|
||||||
|
|
||||||
// Selection.setSelection(1, 3)
|
// Selection.setSelection(1, 3)
|
||||||
// text_input.text
|
// text_input.text
|
||||||
|
|
Loading…
Reference in New Issue