topical media & game development

talk show tell print

lib-flex-store-productsView-ProductCatalogPanel.mx

lib-flex-store-productsView-ProductCatalogPanel.mx (swf ) [ flash ] flex


  <?xml version="1.0" encoding="utf-8"?>
  <!--
  
//////////////////////////////////////////////////////////////////////////

// // Copyright (C) 2003-2006 Adobe Macromedia Software LLC and its licensors. // All Rights Reserved. // The following is Sample Code and is subject to all restrictions on such code // as contained in the End User License Agreement accompanying this product. // If you have received this file from a source other than Adobe, // then your use, modification, or distribution of it requires // the prior written permission of Adobe. //
//////////////////////////////////////////////////////////////////////////

--> <mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:productsView="*" layout="vertical" currentState="browse" verticalScrollPolicy="off" horizontalScrollPolicy="off" styleName="catalogPanel"> <mx:Metadata> [Event(name="purchase", type="lib_flex_store_samples_flexstore_ProductThumbEvent")] [Event(name="compare", type="lib_flex_store_samples_flexstore_ProductThumbEvent")] [Event(name="details", type="lib_flex_store_samples_flexstore_ProductThumbEvent")] </mx:Metadata> <mx:Script> <![CDATA[ import flash.utils.Dictionary; import mx.collections.ArrayCollection; import mx.collections.IViewCursor; import mx.core.DragSource; import mx.core.IUIComponent; import mx.effects.Effect; import mx.effects.Fade; import mx.effects.Move; import mx.events.EffectEvent; import mx.events.DragEvent; import mx.managers.DragManager; //import samples.flexstore.Product; //import samples.flexstore.ProductFilter; //import samples.flexstore.ProductFilterEvent; //import samples.flexstore.ProductThumbEvent; private var accepted:Dictionary = new Dictionary(); private var thumbnails:Array; private var filterCount:int; private var thumbnailState:String = 'browse'; //either 'browse' or 'compare' [Bindable] private var titleButtons:lib_flex_store_productsView_CatalogTitleButtons; //the buttons that also allow the panel to switch sides override protected function createChildren():void { super.createChildren(); titleButtons = new lib_flex_store_productsView_CatalogTitleButtons(); titleBar.addChild(titleButtons); } override protected function layoutChrome(unscaledWidth:Number, unscaledHeight:Number):void { super.layoutChrome(unscaledWidth, unscaledHeight); //when adding to a UIComponent (not a Container) need explicit width/height titleButtons.width = unscaledWidth / 2; //make it big so as we add cart items we can stretch) titleButtons.height = titleButtons.measuredHeight; //this placement algorithm is pretty hacky, there are better ways that probably //involve copying more of the Panel layoutChrome method and supporting methods titleButtons.move(statusTextField.x - titleButtons.width, titleTextField.y); } [Bindable] public var cartCount:int; //----------------------------- // catalog //----------------------------- private var _catalog:ArrayCollection; [Bindable] public function set catalog(c:ArrayCollection):void { _catalog = c; createThumbnails(); } public function get catalog():ArrayCollection { return _catalog; } //---------------------------------------------------------------------- // methods //---------------------------------------------------------------------- private function createThumbnails():void { var i:int; //variables are hoisted up in scope so declare here to avoid warning if (thumbnails != null) { for (i=0; i < thumbnails.length; i++) { thumbContent.removeChild(thumbnails[i]); } } var row:int = 0; var col:int = -1; var n:int = catalog.length; thumbnails = new Array(n); filterCount = n; for (i=0; i < n; i++) { var thumb:lib_flex_store_productsView_ProductCatalogThumbnail = new lib_flex_store_productsView_ProductCatalogThumbnail(); thumbnails[i] = thumb; thumbnails[i].showInAutomationHierarchy = true; thumb.product = catalog.getItemAt(i) as lib_flex_store_samples_flexstore_Product; accepted[thumb.product] = true; thumbContent.addChild(thumb); thumb.addEventListener(lib_flex_store_samples_flexstore_ProductThumbEvent.PURCHASE, productThumbEventHandler); thumb.addEventListener(lib_flex_store_samples_flexstore_ProductThumbEvent.COMPARE, productThumbEventHandler); thumb.addEventListener(lib_flex_store_samples_flexstore_ProductThumbEvent.DETAILS, productThumbEventHandler); thumb.addEventListener(DragEvent.DRAG_START,thumbDragStartHandler); } layoutCatalog(); } private function thumbDragStartHandler(event:MouseEvent):void { if (DragManager.isDragging == false) { var thumb:lib_flex_store_productsView_ProductCatalogThumbnail = event.target as lib_flex_store_productsView_ProductCatalogThumbnail; var ds:DragSource = new DragSource(); ds.addData(thumb.product, "product"); var di:lib_flex_store_productsView_ProductCatalogThumbnail = new lib_flex_store_productsView_ProductCatalogThumbnail(); di.product = thumb.product; //the offset logic is honestly not the most intuitive but //it's necessary to get the dragProxy positioned correctly DragManager.doDrag(thumbContent, ds, event, di, -thumb.x, -thumb.y + thumbContent.verticalScrollPosition, 0.5, false); } } public function filter(productFilter:lib_flex_store_samples_flexstore_ProductFilter, live:Boolean):void { currentState = "browse"; thumbnailState = "browse"; var count:int=0; var n:int = thumbnails.length; var fadeOut:Fade = new Fade(); fadeOut.alphaFrom = 1; fadeOut.alphaTo = .1; var targets:Array = []; for (var i:int = 0; i < n; i++) { var thumb:lib_flex_store_productsView_ProductCatalogThumbnail = thumbnails[i]; var product:lib_flex_store_samples_flexstore_Product = thumb.product; if (productFilter.accept(product)) { accepted[product] = true; thumb.alpha = 1; count++; } else { accepted[product] = false; if (live) { thumb.alpha = .1; } else if (thumb.alpha == 1) //only fade if we hadn't started { targets.push(thumb); } } } productFilter.count = count; filterCount = count; if (targets.length > 0) { fadeOut.targets = targets; fadeOut.play(); fadeOut.addEventListener(EffectEvent.EFFECT_END, function(event:EffectEvent):void { layoutCatalog(); }); } else if (!live) { layoutCatalog(); } } private function layoutCatalog():Effect { var tileWidth:Number; var tileHeight:Number; var numCols:int; if (filterCount > 9 || currentState == "compare") { numCols = 4; tileWidth = lib_flex_store_productsView_ProductCatalogThumbnail.COL_WIDTH_4; tileWidth = currentState == "compare" ? lib_flex_store_productsView_ProductCatalogThumbnail.COMPARE_WIDTH : lib_flex_store_productsView_ProductCatalogThumbnail.COL_WIDTH_4 tileHeight = currentState == "compare" ? height - 4 : lib_flex_store_productsView_ProductCatalogThumbnail.COL_HEIGHT_4; } else if (filterCount > 4) { numCols = 3; tileWidth = lib_flex_store_productsView_ProductCatalogThumbnail.COL_WIDTH_3; tileHeight = lib_flex_store_productsView_ProductCatalogThumbnail.COL_HEIGHT_3; } else if (filterCount <= 9) { numCols = 2; tileWidth = lib_flex_store_productsView_ProductCatalogThumbnail.COL_WIDTH_2; tileHeight = lib_flex_store_productsView_ProductCatalogThumbnail.COL_HEIGHT_2; } else { } var row:int = 0; var col:int = -1; var move:Move = null; var n:int = catalog.length; for (var i:int = 0 ; i < n ; i++) { var product:lib_flex_store_samples_flexstore_Product = catalog.getItemAt(i) as lib_flex_store_samples_flexstore_Product; var thumb:lib_flex_store_productsView_ProductCatalogThumbnail = thumbnails[i]; if (accepted[product]) { thumb.currentState = "" + numCols + "cols"; col++; if (col > numCols - 1) { row++; col = 0; } var xTo:Number = col * (tileWidth + lib_flex_store_productsView_ProductCatalogThumbnail.HORIZONTAL_GAP); var yTo:Number = row * (tileHeight + lib_flex_store_productsView_ProductCatalogThumbnail.VERTICAL_GAP); // If the thumbnail is already visible // animate it to its new position. if (thumb.visible) { // Animate only if the position is different // from its current position. if (thumb.x != xTo || thumb.y != yTo) { move = new Move(thumb); move.xTo = xTo; move.yTo = yTo; move.play(); } } // If the thumbnail was not previously visible, sets its // x and y coordinates. We'll make it reappear after all // the visible thumbnails have reached their new position. else { thumb.x = xTo; thumb.y = yTo; thumb.includeInLayout = true; } } else { thumb.visible = false; thumb.includeInLayout = false; } } if (!move) { // No visible thumbnails were animated to a new position; // fade in newly selected thumbnails right away. fadeInThumbnails(); } else { //since movement is happening get the scrollbar back to the top thumbContent.verticalScrollPosition = 0; // Fade in newly selected thumbnails after the last // visible thumbnail has moved to its new position. move.addEventListener(EffectEvent.EFFECT_END, function(event:EffectEvent):void { fadeInThumbnails(); }); } //return the last move to watch return move; } //return the last effect so we could add effectEnd handler if desired private function fadeInThumbnails():void { var n:int = thumbnails.length; var effect:Fade = new Fade(); effect.alphaTo = 1; var targets:Array = []; for (var i:int = 0; i < n ; i++) { var thumb:lib_flex_store_productsView_ProductCatalogThumbnail = thumbnails[i]; if (accepted[thumb.product] && !thumb.visible) { thumb.alpha = 0; thumb.visible = true; targets.push(thumb); } } if (targets.length > 0) { effect.targets = targets; effect.play(); } } private function showDetails(product:lib_flex_store_samples_flexstore_Product):void { if (currentState == "details") { details.product = product; return; } var row:int = -1; //should be computed using border metrics instead of hard-coding the 20, but... var xTo:Number = thumbContent.width - lib_flex_store_productsView_ProductCatalogThumbnail.COL_WIDTH_4 - 20; var yTo:Number; var move:Move; var first:Boolean = true; var selectedThumb:lib_flex_store_productsView_ProductCatalogThumbnail; var n:int = thumbnails.length; for (var i:int = 0; i < n; i++) { var thumb:lib_flex_store_productsView_ProductCatalogThumbnail = thumbnails[i]; if (thumb.visible) { row++; yTo = row * (lib_flex_store_productsView_ProductCatalogThumbnail.COL_HEIGHT_4 + lib_flex_store_productsView_ProductCatalogThumbnail.VERTICAL_GAP); thumb.currentState = "4cols"; if (thumb.x != xTo || thumb.y != yTo) { move = new Move(thumb); if (first) { move.addEventListener(EffectEvent.EFFECT_END, function(event:EffectEvent):void { details.product = product; currentState = "details"; }); first = false; } move.xTo = xTo; move.yTo = yTo; move.play(); } if (thumb.product == product) { selectedThumb = thumb; } } } if (selectedThumb != null) { //make sure that the selected thumb is visible in the list on the right move.addEventListener(EffectEvent.EFFECT_END, function(e:EffectEvent):void { var curpos:int = thumbContent.verticalScrollPosition; if (selectedThumb.y < curpos) { thumbContent.verticalScrollPosition = y; } else if (selectedThumb.y + lib_flex_store_productsView_ProductCatalogThumbnail.COL_HEIGHT_4 > curpos + thumbContent.height) { //this logic doesn't seem to be perfect but it will do var diff:int = selectedThumb.y - (curpos + thumbContent.height) thumbContent.verticalScrollPosition += diff + lib_flex_store_productsView_ProductCatalogThumbnail.COL_HEIGHT_4 + lib_flex_store_productsView_ProductCatalogThumbnail.VERTICAL_GAP; } }); } } private function productThumbEventHandler(event:lib_flex_store_samples_flexstore_ProductThumbEvent):void { if (event.type == lib_flex_store_samples_flexstore_ProductThumbEvent.DETAILS) { showDetails(event.product); } else if (event.type == lib_flex_store_samples_flexstore_ProductThumbEvent.BROWSE) { if (thumbnailState == "browse") { currentState = "browse"; layoutCatalog(); } else { compare(); } } else { dispatchEvent(event); } } public function compare(toCompare:Array=null):void { currentState = "compare"; thumbnailState = "compare"; if (toCompare != null) { var n:int = thumbnails.length; for (var i:int = 0; i < n; i++) { accepted[thumbnails[i].product] = false; } for (i=0; i < toCompare.length; i++) { accepted[toCompare[i]] = true; } } var lastEffect:Effect = layoutCatalog(); if (lastEffect != null) { lastEffect.addEventListener(EffectEvent.EFFECT_END, function (event:EffectEvent):void { setCompareState(); }); } else { setCompareState(); } } private function setCompareState():void { //avoid an issue if the user clicks quickly where we move into //compare state even though we're no longer in compare if (currentState == "compare") { var n:int = thumbnails.length; for (var i:int = 0; i < n; i++) { var thumb:lib_flex_store_productsView_ProductCatalogThumbnail = thumbnails[i]; if (accepted[thumb.product]) { thumb.currentState = "compare"; } } } } ]]> </mx:Script> <mx:Binding source="cartCount" destination="titleButtons.cartCount" /> <!-- two-way binding between the states of panel title buttons and the product view state --> <mx:Binding source="lib_flex_store_ProductsView(parentDocument).currentState" destination="titleButtons.currentState" /> <mx:Binding destination="lib_flex_store_ProductsView(parentDocument).currentState" source="titleButtons.currentState" /> <mx:Canvas width="100%" height="100%" verticalScrollPolicy="off" horizontalScrollPolicy="off" paddingRight="0"> <mx:Canvas id="thumbContent" width="100%" height="100%" horizontalScrollPolicy="off"/> <productsView:lib_flex_store_productsView_ProductDetails id="details" width="{lib_flex_store_productsView_ProductCatalogThumbnail.COL_WIDTH_4 * 3}" height="100%" visible="false" compare="productThumbEventHandler(event)" purchase="productThumbEventHandler(event)" browse="productThumbEventHandler(event)" /> </mx:Canvas> <mx:states> <mx:State name="browse"> <mx:SetProperty name="title" value="Browse"/> </mx:State> <mx:State name="compare"> <mx:SetProperty name="title" value="Product Comparison"/> </mx:State> <mx:State name="details"> <mx:SetProperty name="title" value="Product Details"/> <mx:SetProperty target="{details}" name="visible" value="true"/> </mx:State> </mx:states> </mx:Panel>


(C) Æliens 18/6/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.