| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585 |
- package com.imt.intimamedia.helpers
- {
- import flash.events.MouseEvent;
-
- import flexlib.events.WindowShadeEvent;
-
- import mx.core.EdgeMetrics;
- import mx.core.IFactory;
- import mx.core.LayoutContainer;
- import mx.core.ScrollPolicy;
- import mx.effects.Resize;
- import mx.effects.effectClasses.ResizeInstance;
- import mx.events.EffectEvent;
- import mx.events.PropertyChangeEvent;
- import mx.styles.CSSStyleDeclaration;
- import mx.styles.StyleManager;
- import mx.utils.StringUtil;
-
- /**
- * This is the icon displayed on the headerButton when the WindowShade is in the open state.
- */
- [Style(name="openIcon", type="Class", inherit="no")]
- /**
- * This is the icon displayed on the headerButton when the WindowShade is in the closed state.
- */
- [Style(name="closeIcon", type="Class", inherit="no")]
- /**
- * The duration of the WindowShade opening transition, in milliseconds. The value 0 specifies no transition.
- *
- * @default 250
- */
- [Style(name="openDuration", type="Number", format="Time", inherit="no")]
- /**
- * The duration of the WindowShade closing transition, in milliseconds. The value 0 specifies no transition.
- *
- * @default 250
- */
- [Style(name="closeDuration", type="Number", format="Time", inherit="no")]
- /**
- * The class from which the headerButton will be instantiated. Must be mx.controls.Button
- * or a subclass.
- *
- * @default mx.controls.Button
- */
- [Style(name="headerClass", type="Class", inherit="no")]
-
- /**
- * Name of CSS style declaration that specifies styles for the headerButton.
- */
- [Style(name="headerStyleName", type="String", inherit="no")]
- /**
- * Alignment of text on the headerButton. The value set for this style is used as
- * the textAlign style on the headerButton. Valid values are "left", "center" and "right".
- *
- * @default "right"
- */
- [Style(name="headerTextAlign", type="String", inherit="no")]
- /**
- * If true, the value of the headerButton's <code>toggle</code> property will be set to true;
- * otherwise the <code>toggle</code> property will be left in its default state.
- *
- * @default false
- */
- [Style(name="toggleHeader", type="Boolean", inherit="no")]
- /**
- * Dispatched when the <code>opened</code> property is changed, either through user action
- * or programatically. This event is cancelable. When cancelled through a call to Event.preventDefault(),
- * the <code>opened</code> property will be restored to its previous state.
- *
- * @eventType flexlib.events.WindowShadeEvent.OPENED_CHANGED
- */
- [Event(name="openedChanged", type="flexlib.events.WindowShadeEvent")]
- /**
- * Dispatched when the WindowShade is about to be opened.
- *
- * <p>In most cases, an event of this type will be followed by an event of type WindowShadeEvent.OPEN_END (<code>openEnd</code>); however,
- * if the user clicks the header button before the closing transition has run to completion, the <code>openEnd</code> event will
- * not be dispatched, since the WindowShade will not be left in the opened state.</p>
- *
- * @eventType flexlib.events.WindowShadeEvent.OPEN_BEGIN
- */
- [Event(name="openBegin", type="flexlib.events.WindowShadeEvent")]
- /**
- * Dispatched when the WindowShade has finished opening. This event cannot be cancelled.
- *
- * @eventType flexlib.events.WindowShadeEvent.OPEN_END
- */
- [Event(name="openEnd", type="flexlib.events.WindowShadeEvent")]
- /**
- * Dispatched when the WindowShade is about to be closed. This event cannot be cancelled.
- *
- * <p>In most cases, an event of this type will be followed by an event of type WindowShadeEvent.CLOSE_END (<code>closeEnd</code>); however,
- * if the user clicks the header button before the closing transition has run to completion, the <code>closeEnd</code> event will
- * not be dispatched, since the WindowShade will not be left in the closed state.</p>
- *
- * @eventType flexlib.events.WindowShadeEvent.CLOSE_BEGIN
- */
- [Event(name="closeBegin", type="flexlib.events.WindowShadeEvent")]
- /**
- * Dispatched when the WindowShade has finished closing. This event cannot be cancelled.
- *
- * @eventType flexlib.events.WindowShadeEvent.CLOSE_END
- */
- [Event(name="closeEnd", type="flexlib.events.WindowShadeEvent")]
- /**
- * This control displays a button, which when clicked, will cause a panel to "unroll" beneath
- * it like a windowshade being pulled down; or if the panel is already displayed it
- * will be "rolled up" like a windowshade being rolled up. When multiple WindowShades are stacked
- * in a VBox, the result will be similar to an mx.containers.Accordian container, except that multiple
- * WindowShades can be opened simultaneously whereas an Accordian acts like a tab navigator, with only
- * one panel visible at a time.
- */
- public class WindowShade extends LayoutContainer {
- private static var styleDefaults:Object = {
- openDuration:250
- ,closeDuration:250
- ,paddingTop:10
- ,headerClass:WindowShadeButton
- ,headerTextAlign:"left"
- ,toggleHeader:false
- ,headerStyleName:null
- };
- private static var classConstructed:Boolean = constructClass();
- private static function constructClass():Boolean {
- var css:CSSStyleDeclaration = StyleManager.getStyleDeclaration("WindowShade")
- var changed:Boolean = false;
- if(!css) {
- // If there is no CSS definition for WindowShade,
- // then create one and set the default value.
- css = new CSSStyleDeclaration();
- changed = true;
- }
- // make sure we have a valid values for each style. If not, set the defaults.
- for(var styleProp:String in styleDefaults) {
- if(!StyleManager.isValidStyleValue(css.getStyle(styleProp))) {
- css.setStyle(styleProp, styleDefaults[styleProp]);
- changed = true;
- }
- }
- if(changed) {
- StyleManager.setStyleDeclaration("WindowShade", css, true);
- }
- return true;
- }
- /**
- * @private
- * A reference to the Button that will be used for the header. Must always be a Button or subclass of Button.
- */
- private var _headerButton : WindowShadeButton = null;
-
- private var headerChanged:Boolean;
-
- /**
- * @private
- * The header renderer factory that will get used to create the header.
- */
- private var _headerRenderer:IFactory;
-
- /**
- * To control the header used on the WindowShade component you can either set the <code>headerClass</code> or the
- * <code>headerRenderer</code>. The <code>headerRenderer</code> works similar to the itemRenderer of a List control.
- * You can set this using MXML using any Button control. This would let you customize things like button skin. You could
- * even combine this with the CanvasButton component to make complex headers.
- */
- public function set headerRenderer(value:IFactory):void {
- _headerRenderer = value;
-
- headerChanged = true;
- invalidateProperties();
- }
-
- public function get headerRenderer():IFactory {
- return _headerRenderer;
- }
-
- /**
- * @private
- * Boolean dirty flag to let us know if we need to change the icon in the commitProperties method.
- */
- private var _openedChanged:Boolean = false;
- public function WindowShade() {
- super();
-
- //default scroll policies are off
- this.verticalScrollPolicy = ScrollPolicy.OFF;
- this.horizontalScrollPolicy = ScrollPolicy.OFF;
- addEventListener(EffectEvent.EFFECT_END, onEffectEnd);
- }
- protected function createOrReplaceHeaderButton():void {
- if(_headerButton) {
- _headerButton.removeEventListener(MouseEvent.CLICK, headerButton_clickHandler);
-
- if(rawChildren.contains(_headerButton)) {
- rawChildren.removeChild(_headerButton);
- }
- }
-
- if(_headerRenderer) {
- _headerButton = _headerRenderer.newInstance() as WindowShadeButton;
- }
- else {
- var headerClass:Class = getStyle("headerClass");
- _headerButton = new headerClass();
- }
-
- applyHeaderButtonStyles(_headerButton);
- _headerButton.addEventListener(MouseEvent.CLICK, headerButton_clickHandler);
-
- rawChildren.addChild(_headerButton);
- // Fix for Issue #85
- _headerButton.tabEnabled = false;
- }
- protected function applyHeaderButtonStyles(button:WindowShadeButton):void {
- button.setStyle("textAlign", getStyle("headerTextAlign"));
-
- var headerStyleName:String = getStyle("headerStyleName");
- if(headerStyleName) {
- headerStyleName = StringUtil.trim(headerStyleName);
- button.styleName = headerStyleName;
- }
-
- button.toggle = getStyle("toggleHeader");
- button.label = label;
- if(_opened) {
- button.setStyle('icon', getStyle("openIcon"));
- }
- else {
- button.setStyle('icon', getStyle("closeIcon"));
- }
- if(button.toggle) {
- button.selected = _opened;
- }
- }
- /**
- * The text that appears on the headerButton.
- */
- override public function get label():String {
- // This override is here only to keep the ASDoc tool from incorrectly marking this a write-only property.
- return super.label;
- }
- /**
- * @private
- */
- override public function set label(value:String):void {
- super.label = value;
-
- if(_headerButton) _headerButton.label = value;
- }
- /**
- * @private
- */
- private var _opened:Boolean = true;
-
- /**
- * Sets or gets the state of this WindowShade, either opened (true) or closed (false).
- */
- public function get opened():Boolean {
- return _opened;
- }
-
- private var _headerLocation:String = "top";
-
- [Bindable]
- [Inspectable(enumeration="top,bottom", defaultValue="top")]
- /**
- * Specifies where the header button is placed relative tot he content of this WindowShade. Possible
- * values are <code>top</code> and <code>bottom</code>.
- */
- public function set headerLocation(value:String):void {
- _headerLocation = value;
- invalidateSize();
- invalidateDisplayList();
- }
-
- public function get headerLocation():String {
- return _headerLocation;
- }
- /**
- * @private
- */
- [Bindable]
- public function set opened(value:Boolean):void {
- var old:Boolean = _opened;
-
- _opened = value;
- _openedChanged = _openedChanged || (old != _opened);
-
- if(_openedChanged && initialized) {
- // we only want to dispatch the WindowShadeEvent.OPENED_CHANGED when the property actually changes. The _openedChanged
- // flag may be set from a previous call with the same value. In that case we want to leave it set
- // for the commitProperties() method.
- if((old != _opened) && willTrigger(WindowShadeEvent.OPENED_CHANGED)) {
- var evt:WindowShadeEvent = new WindowShadeEvent(WindowShadeEvent.OPENED_CHANGED, false, true);
- dispatchEvent(evt);
- var cancelled:Boolean = evt.isDefaultPrevented();
- if(evt.isDefaultPrevented()) {
- // restore the old setting. We use callLater so it happens after the PropertyChangeEvent fired
- // by the binding wrapper.
- callLater(restoreOpened, [old]);
- return;
- }
- }
- measure();
- runResizeEffect();
-
- invalidateProperties();
- }
- }
- /**
- * @private
- *
- * This exists to allow us to restore a previous opened state when a WindowShadeEvent.OPENED_CHANGED event is
- * cancelled, while bypassing the code that changes the visual state of the WindowShade and dispatches the WindowShadeEvent.
- */
- protected function restoreOpened(value:Boolean):void {
- var old:Boolean = _opened;
- _opened = value;
- _openedChanged = _openedChanged || (old != _opened);
- if(_opened != old) {
- dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, "opened", old, _opened));
- }
- }
- /**
- * @private
- */
- override public function styleChanged(styleProp:String):void {
- super.styleChanged(styleProp);
-
- if(styleProp == "headerClass") {
- headerChanged = true;
- invalidateProperties();
- }
- else if(styleProp == "headerStyleName" || styleProp == "headerTextAlign" || styleProp == "toggleHeader"
- || styleProp == "openIcon" || styleProp == "closeIcon") {
- applyHeaderButtonStyles(_headerButton);
- }
-
- invalidateDisplayList();
- }
- /**
- * @private
- */
- override protected function createChildren():void {
- super.createChildren();
-
- createOrReplaceHeaderButton();
- }
- /**
- * @private
- */
- override protected function commitProperties():void {
-
- super.commitProperties();
-
- if(headerChanged) {
- createOrReplaceHeaderButton();
- headerChanged = false;
- }
-
- if(_openedChanged) {
-
- if(_opened) {
- _headerButton.setStyle('icon', getStyle("openIcon"));
- }
- else {
- _headerButton.setStyle('icon', getStyle("closeIcon"));
- }
-
- _openedChanged = false;
- }
- }
- /**
- * @private
- */
- override protected function updateDisplayList(w:Number, h:Number):void {
- super.updateDisplayList(w, h);
-
- if(_headerLocation == "top") {
- _headerButton.move(0,0);
- }
- else if(_headerLocation == "bottom") {
- _headerButton.move(0,h - _headerButton.getExplicitOrMeasuredHeight());
- }
-
- _headerButton.setActualSize(w, _headerButton.getExplicitOrMeasuredHeight());
- }
- /**
- * @private
- */
- private var _viewMetrics:EdgeMetrics;
-
- override public function get viewMetrics():EdgeMetrics
- {
- // The getViewMetrics function needs to return its own object.
- // Rather than allocating a new one each time, we'll allocate
- // one once and then hold a pointer to it.
- if (!_viewMetrics)
- _viewMetrics = new EdgeMetrics(0, 0, 0, 0);
-
- var vm:EdgeMetrics = _viewMetrics;
-
- var o:EdgeMetrics = super.viewMetrics;
-
- vm.left = o.left;
- vm.top = o.top;
- vm.right = o.right;
- vm.bottom = o.bottom;
-
- var hHeight:Number = _headerButton.getExplicitOrMeasuredHeight();
- if (!isNaN(hHeight)) {
- if(_headerLocation == "top") {
- vm.top += hHeight;
- }
- else if(_headerLocation == "bottom") {
- vm.bottom += hHeight;
- }
- }
-
- return vm;
- }
-
- public var closedHeight:Number = 0;
-
- /**
- * @private
- */
- override protected function measure():void {
- super.measure();
-
- if(_opened) {
- //if this WindowShade is opened then we have to include the height of the header button
- //measuredHeight += _headerButton.getExplicitOrMeasuredHeight();
- }
- else {
- //if the WindowShade is closed then the height is only the height of the header button
- measuredHeight = closedHeight + _headerButton.getExplicitOrMeasuredHeight();
- }
- }
- /**
- * @private
- */
- private var resize:Resize;
- /**
- * @private
- */
- private var resizeInstance:ResizeInstance;
- /**
- * @private
- */
- private var resetExplicitHeight:Boolean;
- private var transitionCompleted:Boolean = true;
-
- /**
- * @private
- */
- protected function runResizeEffect():void {
- if(resize && resize.isPlaying) {
- // The user has clicked the header button before an open or close transition has run
- // to completion. We'll set the transitionCompleted flag to false to prevent the
- // completion event from being dispatched in onEffectEnd.
- transitionCompleted = false;
- // before the call to end() returns, the onEffectEnd method will have been called
- // for the currently playing resize.
- resize.end();
- }
- transitionCompleted = true;
- var beginEvent:String = _opened ? WindowShadeEvent.OPEN_BEGIN : WindowShadeEvent.CLOSE_BEGIN;
- if(willTrigger(beginEvent)) {
- dispatchEvent(new WindowShadeEvent(beginEvent, false, false));
- }
-
- var duration:Number = _opened ? getStyle("openDuration") : getStyle("closeDuration");
- if(duration == 0) {
- this.setActualSize(getExplicitOrMeasuredWidth(), measuredHeight);
-
- invalidateSize();
- invalidateDisplayList();
- var endEvent:String = _opened ? WindowShadeEvent.OPEN_END : WindowShadeEvent.CLOSE_END;
- if(willTrigger(endEvent)) {
- dispatchEvent(new WindowShadeEvent(endEvent, false, false));
- }
- return;
- }
-
- resize = new Resize(this);
- // If this WindowShade currently has no explicit height set, we want to
- // restore that state when the resize effect is finished, in the onEffectEnd method.
- // If it does, then the final height set by the effect will be retained.
- resetExplicitHeight = isNaN(explicitHeight);
- resize.heightTo = Math.min(maxHeight, measuredHeight);
- resize.duration = duration;
- var instances:Array = resize.play();
- if(instances && instances.length) {
- resizeInstance = instances[0];
- }
- }
- /**
- * @private
- */
- protected function onEffectEnd(evt:EffectEvent):void {
- // Make sure this is our effect ending
- if(evt.effectInstance == resizeInstance) {
- if(resetExplicitHeight) explicitHeight = NaN;
- resizeInstance = null;
- // the transitionCompleted flag will be false if the user clicked the headerButton
- // twice in succession. We only want to fire events for transitions that run
- // all the way to completion.
- if(transitionCompleted) {
- var endEvent:String = _opened ? WindowShadeEvent.OPEN_END : WindowShadeEvent.CLOSE_END;
- if(willTrigger(endEvent)) {
- dispatchEvent(new WindowShadeEvent(endEvent, false, false));
- }
- }
- }
- }
- /**
- * @private
- */
- protected function headerButton_clickHandler(event:MouseEvent):void {
- //opened = !_opened;
- }
- }
- }
|