blob: c2f8d247a3a2180e989f1e2d34f3c00e2d7715f0 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package spark.components
{
import flash.events.Event;
import flash.events.MouseEvent;
import mx.core.ClassFactory;
import mx.core.IFactory;
import mx.core.mx_internal;
import mx.utils.BitFlagUtil;
import spark.components.Button;
import spark.events.DropDownEvent;
import spark.events.PopUpEvent;
import spark.layouts.supportClasses.LayoutBase;
import spark.components.supportClasses.CallOutDropDownController;
import spark.components.supportClasses.IDropDownContainer;
use namespace mx_internal;
[Event(name="close", type="spark.events.DropDownEvent")]
[Event(name="open", type="spark.events.DropDownEvent")]
[DefaultProperty("calloutContent")]
public class CallOutButton extends Button implements IDropDownContainer
{
//--------------------------------------------------------------------------
//
// Class constants
//
//--------------------------------------------------------------------------
/**
* @private
*/
mx_internal static const CALLOUT_CONTENT_PROPERTY_FLAG:uint = 1 << 0;
/**
* @private
*/
mx_internal static const CALLOUT_LAYOUT_PROPERTY_FLAG:uint = 1 << 1;
/**
* @private
*/
mx_internal static const HORIZONTAL_POSITION_PROPERTY_FLAG:uint = 1 << 2;
/**
* @private
*/
mx_internal static const VERTICAL_POSITION_PROPERTY_FLAG:uint = 1 << 3;
[SkinPart(required="false")]
public var dropDown:IFactory;
public var topCallOut:CallOut;
public var subCallOut:CallOut;
private var _callout:CallOut;
[Bindable("calloutChanged")]
public function get callout():CallOut
{
return _callout;
}
protected function setCallout(value:CallOut):void
{
_callout = value;
if (hasEventListener("calloutChanged")) dispatchEvent(new Event("calloutChanged"));
}
private var _calloutContent:Array;
[ArrayElementType("mx.core.IVisualElement")]
public function get calloutContent():Array
{
return _calloutContent;
}
public function set calloutContent(value:Array):void
{
_calloutContent = value;
if (callout) callout.mxmlContent = value;
}
private var _calloutLayout:LayoutBase;
public function get calloutLayout():LayoutBase
{
return _calloutLayout;
}
public function set calloutLayout(value:LayoutBase):void
{
_calloutLayout = value;
if (callout) callout.layout = value;
}
[Inspectable(category="General", enumeration="rollOver,click", defaultValue="rollOver")] //mouseOver
public var triggerEvent:String = MouseEvent.ROLL_OVER;
private var dropDownController:CallOutDropDownController;
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* @private
* Several properties are proxied to callout. However, when callout
* is not around, we need to store values set on CalloutButton. This object
* stores those values. If callout is around, the values are stored
* on the callout directly. However, we need to know what values
* have been set by the developer on the CalloutButton (versus set on
* the callout or defaults of the callout) as those are values
* we want to carry around if the callout changes (via a new skin).
* In order to store this info effeciently, calloutProperties becomes
* a uint to store a series of BitFlags. These bits represent whether a
* property has been explicitely set on this CalloutButton. When the
* callout is not around, calloutProperties is a typeless
* object to store these proxied properties. When callout is around,
* calloutProperties stores booleans as to whether these properties
* have been explicitely set or not.
*/
mx_internal var calloutProperties:Object = {};
//----------------------------------
// horizontalPosition
//----------------------------------
[Inspectable(category="General", enumeration="before,start,middle,end,after,auto", defaultValue="auto")]
/**
* @copy spark.components.Callout#horizontalPosition
*
* @langversion 3.0
* @playerversion AIR 3
* @productversion Flex 4.6
*/
public function get horizontalPosition():String
{
if (callout)
return callout.horizontalPosition;
return calloutProperties.horizontalPosition;
}
/**
* @private
*/
public function set horizontalPosition(value:String):void
{
if (callout)
{
callout.horizontalPosition = value;
calloutProperties = BitFlagUtil.update(calloutProperties as uint,
HORIZONTAL_POSITION_PROPERTY_FLAG, value != null);
}
else
calloutProperties.horizontalPosition = value;
}
//----------------------------------
// verticalPosition
//----------------------------------
[Inspectable(category="General", enumeration="before,start,middle,end,after,auto", defaultValue="auto")]
/**
* @copy spark.components.Callout#verticalPosition
*
* @langversion 3.0
* @playerversion AIR 3
* @productversion Flex 4.6
*/
public function get verticalPosition():String
{
if (callout)
return callout.verticalPosition;
return calloutProperties.verticalPosition;
}
/**
* @private
*/
public function set verticalPosition(value:String):void
{
if (callout)
{
callout.verticalPosition = value;
calloutProperties = BitFlagUtil.update(calloutProperties as uint,
VERTICAL_POSITION_PROPERTY_FLAG, value != null);
}
else
calloutProperties.verticalPosition = value;
}
override public function initialize():void
{
dropDownController = new CallOutDropDownController();
dropDownController.closeOnResize = false;
dropDownController.addEventListener(DropDownEvent.OPEN, handleDropDownOpen);
dropDownController.addEventListener(DropDownEvent.CLOSE, handleDropDownClose);
dropDownController.rollOverOpenDelay = (triggerEvent == MouseEvent.CLICK) ? NaN : 0;
dropDownController.openButton = this;
super.initialize();
}
override protected function partAdded(partName:String, instance:Object):void
{
super.partAdded(partName, instance);
if (partName == "dropDown")
{
// copy proxied values from calloutProperties (if set) to callout
var newCalloutProperties:uint = 0;
var calloutInstance:CallOut = instance as CallOut;
if (calloutInstance && dropDownController)
{
calloutInstance.id = "callout";
dropDownController.dropDown = calloutInstance;
calloutInstance.addEventListener(PopUpEvent.OPEN, handleCalloutOpen);
calloutInstance.addEventListener(PopUpEvent.CLOSE, handleCalloutClose);
calloutInstance.mxmlContent = _calloutContent;
if (_calloutLayout) calloutInstance.layout = _calloutLayout;
/*
if (calloutProperties.calloutContent !== undefined)
{
calloutInstance.mxmlContent = calloutProperties.calloutContent;
newCalloutProperties = BitFlagUtil.update(newCalloutProperties,
CALLOUT_CONTENT_PROPERTY_FLAG, true);
}
if (calloutProperties.calloutLayout !== undefined)
{
calloutInstance.layout = calloutProperties.calloutLayout;
newCalloutProperties = BitFlagUtil.update(newCalloutProperties,
CALLOUT_LAYOUT_PROPERTY_FLAG, true);
}
*/
if (calloutProperties.horizontalPosition !== undefined)
{
calloutInstance.horizontalPosition = calloutProperties.horizontalPosition;
newCalloutProperties = BitFlagUtil.update(newCalloutProperties, HORIZONTAL_POSITION_PROPERTY_FLAG, true);
}
if (calloutProperties.verticalPosition !== undefined)
{
calloutInstance.verticalPosition = calloutProperties.verticalPosition;
newCalloutProperties = BitFlagUtil.update(newCalloutProperties, VERTICAL_POSITION_PROPERTY_FLAG, true);
}
calloutProperties = newCalloutProperties;
}
}
}
override protected function attachSkin():void
{
super.attachSkin();
if (!dropDown && !("dropDown" in skin)) dropDown = new ClassFactory(CallOut);
}
private function handleDropDownOpen(event:DropDownEvent):void
{
if (!callout) setCallout(createDynamicPartInstance("dropDown") as CallOut);
if (!callout) return;
if(topCallOut != null)
if(topCallOut.owner != null)
(this.topCallOut.owner as CallOutButton).subCallOut = callout;
addEventListener(Event.REMOVED_FROM_STAGE, handleButtonRemoved);
callout.open(this, false);
}
private function handleDropDownClose(event:DropDownEvent):void
{
if (!callout) return;
removeEventListener(Event.REMOVED_FROM_STAGE, handleButtonRemoved);
callout.close();
}
private function handleCalloutOpen(event:PopUpEvent):void
{
dispatchEvent(new DropDownEvent(DropDownEvent.OPEN));
}
private function handleCalloutClose(event:PopUpEvent):void
{
if (dropDownController.isOpen) closeDropDown();
/*if (calloutDestructionPolicy == ContainerDestructionPolicy.AUTO)
destroyCallout();*/
dispatchEvent(new DropDownEvent(DropDownEvent.CLOSE));
}
private function handleButtonRemoved(event:Event):void
{
if (!isDropDownOpen) return;
callout.visible = false;
closeDropDown();
}
public function get isDropDownOpen():Boolean
{
return dropDownController ? dropDownController.isOpen : false;
}
public function openDropDown():void
{
dropDownController.openDropDown();
}
public function closeDropDown():void
{
dropDownController.closeDropDown(false);
}
public function updatePopUpPosition():void
{
callout.updatePopUpPosition();
}
}
}