From f3aa6f7f015b176134e144e0f2f4786d219180e1 Mon Sep 17 00:00:00 2001 From: CUB3D Date: Fri, 3 Jul 2020 01:59:48 +0100 Subject: [PATCH] core: Add stub of ContextMenuItem --- core/src/avm1/globals.rs | 23 ++++- core/src/avm1/globals/context_menu.rs | 79 ++++++++++------- core/src/avm1/globals/context_menu_item.rs | 99 ++++++++++++++++++++++ 3 files changed, 170 insertions(+), 31 deletions(-) create mode 100644 core/src/avm1/globals/context_menu_item.rs diff --git a/core/src/avm1/globals.rs b/core/src/avm1/globals.rs index 865643d58..2a716cb29 100644 --- a/core/src/avm1/globals.rs +++ b/core/src/avm1/globals.rs @@ -40,6 +40,7 @@ pub(crate) mod text_field; mod text_format; mod xml; pub(crate) mod context_menu; +pub(crate) mod context_menu_item; #[allow(non_snake_case, unused_must_use)] //can't use errors yet pub fn getURL<'a, 'gc>( @@ -316,6 +317,8 @@ pub fn create_globals<'gc>( let object = object::create_object_object(gc_context, object_proto, function_proto); let context_menu_proto = context_menu::create_proto(gc_context, object_proto, function_proto); + let context_menu_item_proto = context_menu_item::create_proto(gc_context, object_proto, function_proto); + let button = FunctionObject::function( gc_context, @@ -459,11 +462,27 @@ pub fn create_globals<'gc>( EnumSet::empty(), ); - let context_menu = context_menu::create_context_menu_object(gc_context, Some(context_menu_proto), Some(function_proto)); globals.define_value( gc_context, "ContextMenu", - context_menu.into(), + FunctionObject::function( + gc_context, + Executable::Native(context_menu::constructor), + Some(function_proto), + Some(context_menu_proto), + ).into(), + EnumSet::empty() + ); + + globals.define_value( + gc_context, + "ContextMenuItem", + FunctionObject::function( + gc_context, + Executable::Native(context_menu_item::constructor), + Some(function_proto), + Some(context_menu_item_proto), + ).into(), EnumSet::empty() ); diff --git a/core/src/avm1/globals/context_menu.rs b/core/src/avm1/globals/context_menu.rs index 5cb2b278e..f67fa066d 100644 --- a/core/src/avm1/globals/context_menu.rs +++ b/core/src/avm1/globals/context_menu.rs @@ -1,60 +1,81 @@ use gc_arena::MutationContext; -use crate::avm1::{Value, ScriptObject, Avm1}; -use crate::avm1::function::{FunctionObject, Executable}; +use crate::avm1::{Value, ScriptObject}; use crate::avm1::Object; use crate::context::UpdateContext; -use crate::avm1::return_value::ReturnValue; use crate::avm1::error::Error; use enumset::EnumSet; +use crate::avm1::activation::Activation; +use crate::avm1::object::TObject; + +//TODO: in future this will want to be a custom object, as it has a callback function in constructor arg +//TODO: note: callback should be called when menu is opened but before it is displayed +//TODO: check for hidden props +//TODO: there shuold be a menu prop somewhere (as2:444) pub fn constructor<'gc>( - _avm: &mut Avm1<'gc>, - _context: &mut UpdateContext<'_, 'gc, '_>, - _this: Object<'gc>, + activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'_, 'gc, '_>, + this: Object<'gc>, _args: &[Value<'gc>], -) -> Result, Error> { +) -> Result, Error<'gc>> { + let obj_proto = activation.avm().prototypes.object; + let built_in_items = obj_proto.new(activation, context, obj_proto, &[])?; + let _ = crate::avm1::globals::object::constructor(activation, context, built_in_items, &[]); + //TODO Check that this lines up with FP + built_in_items.set("zoom", true.into(), activation, context)?; + built_in_items.set("quality", true.into(), activation, context)?; + built_in_items.set("play", true.into(), activation, context)?; + built_in_items.set("loop", true.into(), activation, context)?; + built_in_items.set("rewind", true.into(), activation, context)?; + built_in_items.set("forward_back", true.into(), activation, context)?; + built_in_items.set("print", true.into(), activation, context)?; + + //TODO: check if these are on the proto or not + //TODO: are they virt? + this.set("builtInItems", built_in_items.into(), activation, context)?; + + let array_proto = activation.avm().prototypes.array; + let custom_items = array_proto.new(activation, context, array_proto, &[])?; + let _ = crate::avm1::globals::array::constructor(activation, context, custom_items, &[]); + + this.set("customItems", custom_items.into(), activation, context)?; + Ok(Value::Undefined.into()) } -pub fn create_context_menu_object<'gc>( - gc_context: MutationContext<'gc, '_>, - context_menu_proto: Option>, - fn_proto: Option>, -) -> Object<'gc> { - FunctionObject::function( - gc_context, - Executable::Native(constructor), - fn_proto, - context_menu_proto, - ) -} - pub fn copy<'gc>( - _avm: &mut Avm1<'gc>, + _activation: &mut Activation<'_, 'gc>, _context: &mut UpdateContext<'_, 'gc, '_>, _this: Object<'gc>, _args: &[Value<'gc>], -) -> Result, Error> { +) -> Result, Error<'gc>> { log::warn!("ContextMenu.copy() not implemented"); Ok(Value::Undefined.into()) } pub fn hide_builtin_items<'gc>( - _avm: &mut Avm1<'gc>, - _context: &mut UpdateContext<'_, 'gc, '_>, - _this: Object<'gc>, + activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'_, 'gc, '_>, + this: Object<'gc>, _args: &[Value<'gc>], -) -> Result, Error> { - log::warn!("ContextMenu.hideBuiltInItems() not implemented"); +) -> Result, Error<'gc>> { + let built_in_items = this.get("builtInItems", activation, context)?.coerce_to_object(activation, context); + built_in_items.set("zoom", false.into(), activation, context)?; + built_in_items.set("quality", false.into(), activation, context)?; + built_in_items.set("play", false.into(), activation, context)?; + built_in_items.set("loop", false.into(), activation, context)?; + built_in_items.set("rewind", false.into(), activation, context)?; + built_in_items.set("forward_back", false.into(), activation, context)?; + built_in_items.set("print", false.into(), activation, context)?; Ok(Value::Undefined.into()) } pub fn on_select<'gc>( - _avm: &mut Avm1<'gc>, + _activation: &mut Activation<'_, 'gc>, _context: &mut UpdateContext<'_, 'gc, '_>, _this: Object<'gc>, _args: &[Value<'gc>], -) -> Result, Error> { +) -> Result, Error<'gc>> { log::warn!("ContextMenu.onSelect() not implemented"); Ok(Value::Undefined.into()) } diff --git a/core/src/avm1/globals/context_menu_item.rs b/core/src/avm1/globals/context_menu_item.rs new file mode 100644 index 000000000..cd258fdfb --- /dev/null +++ b/core/src/avm1/globals/context_menu_item.rs @@ -0,0 +1,99 @@ +use gc_arena::MutationContext; +use crate::avm1::{Value, ScriptObject}; +use crate::avm1::Object; +use crate::context::UpdateContext; +use crate::avm1::error::Error; +use enumset::EnumSet; +use crate::avm1::activation::Activation; +use crate::avm1::object::TObject; + +// TODO: should appear at the top of the context menu with a seperator between it and built ins +//TODO: Max 15 custom items/context menu +//TODO: items must have a visible name (at leat one char, not whitespace/newline/control) +//TODO: length <= 100 +//TODO: can't be the same as an existing item (custom or otherwise) +//TODO: two items are the same if they have the same caption, ignoing case, punctuation and whitespace + + +pub fn constructor<'gc>( + activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'_, 'gc, '_>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let caption = args.get(0) + .unwrap_or(&Value::Undefined) + .to_owned() + .coerce_to_string(activation, context)? + .to_string(); + let _callback = args.get(1) + .unwrap_or(&Value::Undefined) + .to_owned() + .coerce_to_object(activation, context); + let separator_before = args.get(2) + .unwrap_or(&Value::Bool(false)) + .to_owned() + .as_bool(activation.swf_version()); + let enabled = args.get(3) + .unwrap_or(&Value::Bool(true)) + .to_owned() + .as_bool(activation.swf_version()); + let visible = args.get(4) + .unwrap_or(&Value::Bool(true)) + .to_owned() + .as_bool(activation.swf_version()); + + //TODO: check for virt + this.set("caption", caption.into(), activation, context)?; + this.set("enabled", enabled.into(), activation, context)?; + this.set("separatorBefore", separator_before.into(), activation, context)?; + this.set("visible", visible.into(), activation, context)?; + + Ok(Value::Undefined.into()) +} + +pub fn copy<'gc>( + _activation: &mut Activation<'_, 'gc>, + _context: &mut UpdateContext<'_, 'gc, '_>, + _this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + log::warn!("ContextMenuItem.copy() not implemented"); + Ok(Value::Undefined.into()) +} + +pub fn on_select<'gc>( + _activation: &mut Activation<'_, 'gc>, + _context: &mut UpdateContext<'_, 'gc, '_>, + _this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + log::warn!("ContextMenuItem.onSelect() not implemented"); + Ok(Value::Undefined.into()) +} + +pub fn create_proto<'gc>( + gc_context: MutationContext<'gc, '_>, + proto: Object<'gc>, + fn_proto: Object<'gc>, +) -> Object<'gc> { + let mut object = ScriptObject::object(gc_context, Some(proto)); + + object.force_set_function( + "copy", + copy, + gc_context, + EnumSet::empty(), + Some(fn_proto) + ); + + object.force_set_function( + "onSelect", + on_select, + gc_context, + EnumSet::empty(), + Some(fn_proto) + ); + + object.into() +}