avm1: Implement TextField.type

This commit is contained in:
Mike Welsh 2020-11-21 15:13:27 -08:00
parent 43e0208842
commit a61d2b54ae
6 changed files with 108 additions and 0 deletions

View File

@ -208,6 +208,64 @@ macro_rules! with_text_field {
}};
}
macro_rules! with_text_field_props {
($obj:ident, $gc:ident, $fn_proto:ident, $($name:literal => [$get:ident $(, $set:ident)*],)*) => {
$(
$obj.add_property(
$gc,
$name,
with_text_field_props!(getter $gc, $fn_proto, $get),
with_text_field_props!(setter $gc, $fn_proto, $($set),*),
Default::default()
);
)*
};
(getter $gc:ident, $fn_proto:ident, $get:ident) => {
FunctionObject::function(
$gc,
Executable::Native(
|activation: &mut Activation<'_, 'gc, '_>, this, _args| -> Result<Value<'gc>, Error<'gc>> {
if let Some(display_object) = this.as_display_object() {
if let Some(edit_text) = display_object.as_edit_text() {
return $get(edit_text, activation);
}
}
Ok(Value::Undefined)
} as crate::avm1::function::NativeFunction<'gc>
),
Some($fn_proto),
$fn_proto
)
};
(setter $gc:ident, $fn_proto:ident, $set:ident) => {
Some(FunctionObject::function(
$gc,
Executable::Native(
|activation: &mut Activation<'_, 'gc, '_>, this, args| -> Result<Value<'gc>, Error<'gc>> {
if let Some(display_object) = this.as_display_object() {
if let Some(edit_text) = display_object.as_edit_text() {
let value = args
.get(0)
.unwrap_or(&Value::Undefined)
.clone();
$set(edit_text, activation, value)?;
}
}
Ok(Value::Undefined)
} as crate::avm1::function::NativeFunction<'gc>
),
Some($fn_proto),
$fn_proto)
)
};
(setter $gc:ident, $fn_proto:ident,) => {
None
};
}
pub fn text_width<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
@ -452,6 +510,11 @@ pub fn create_proto<'gc>(
"replaceText" => replace_text
);
with_text_field_props!(
object, gc_context, fn_proto,
"type" => [get_type, set_type],
);
object.into()
}
@ -770,3 +833,31 @@ fn replace_text<'gc>(
Ok(Value::Undefined)
}
pub fn get_type<'gc>(
this: EditText<'gc>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error<'gc>> {
let tf_type = match this.is_editable() {
true => "input",
false => "dynamic",
};
Ok(AvmString::new(activation.context.gc_context, tf_type).into())
}
pub fn set_type<'gc>(
this: EditText<'gc>,
activation: &mut Activation<'_, 'gc, '_>,
value: Value<'gc>,
) -> Result<(), Error<'gc>> {
match value
.coerce_to_string(activation)?
.to_ascii_lowercase()
.as_str()
{
"input" => this.set_editable(true, &mut activation.context),
"dynamic" => this.set_editable(false, &mut activation.context),
value => log::warn!("Invalid TextField.type: {}", value),
};
Ok(())
}

View File

@ -411,6 +411,14 @@ impl<'gc> EditText<'gc> {
self.relayout(context);
}
pub fn is_editable(self) -> bool {
self.0.read().is_editable
}
pub fn set_editable(self, is_editable: bool, context: &mut UpdateContext<'_, 'gc, '_>) {
self.0.write(context.gc_context).is_editable = is_editable;
}
pub fn is_multiline(self) -> bool {
self.0.read().is_multiline
}

View File

@ -245,6 +245,7 @@ swf_tests! {
#[ignore] (edittext_html_roundtrip, "avm1/edittext_html_roundtrip", 1),
(edittext_newline_stripping, "avm1/edittext_newline_stripping", 1),
(define_local, "avm1/define_local", 1),
(textfield_properties, "avm1/textfield_properties", 1),
(textfield_variable, "avm1/textfield_variable", 8),
(error, "avm1/error", 1),
(color_transform, "avm1/color_transform", 1),

View File

@ -0,0 +1,8 @@
// txt.type:
dynamic
// txt.type = 'input':
input
// txt.type = 'DYNAMIC':
dynamic
// txt.type = 'invalid':
dynamic

Binary file not shown.

Binary file not shown.