package { //import com.example.programmingas3.filterWorkbench.IFilterFactory; //import com.example.programmingas3.filterWorkbench.ImageType; import flash.display.DisplayObject; import flash.display.Loader; import flash.events.Event; import flash.events.EventDispatcher; import flash.events.IOErrorEvent; import flash.events.ProgressEvent; import flash.filters.BitmapFilter; import flash.net.URLRequest; // ------- Events ------- /** * Dispatched when progress occurs while the filter target image is loading. */ [Event(name="progress", type="flash.events.ProgressEvent")] /** * Dispatched when the filter target image finishes loading. */ [Event(name="complete", type="flash.events.Event")] /** * Dispatched when the filter target image changes (its filters change). */ [Event(name="change", type="flash.events.Event")] /** * The main class that provides the functionality of the FilterWorkbench application, * including tracking sets of filters and applying the filters to the currently * selected filter target. */ public class actionscript_book_FilterWorkbench_com_example_programmingas3_filterWorkbench_FilterWorkbenchController extends EventDispatcher { // ------- Private vars ------- private var _filterFactory:actionscript_book_FilterWorkbench_com_example_programmingas3_filterWorkbench_IFilterFactory; private var _currentFilters:Array; private var _currentTarget:DisplayObject; private var _loader:Loader; private var _loading:Boolean; // ------- Constructor ------- public function actionscript_book_FilterWorkbench_com_example_programmingas3_filterWorkbench_FilterWorkbenchController() { super(); } // ------- Public Methods ------- /** * Selects a new type of image to be the "filter target" (the image to which * the filters will be applied). Calling this method starts the process of * loading the specified image; the image is available when the Event.COMPLETE * event is dispatched. * * @param targetType The ImageType constant representing the type of image * desired. */ public function setFilterTarget(targetType:actionscript_book_FilterWorkbench_com_example_programmingas3_filterWorkbench_ImageType):void { if (targetType == null) { return; } if (_loading) { _loader.close(); _loading = false; } if (_currentTarget != null) { _currentTarget = null; } _loader = new Loader(); _loader.load(new URLRequest(targetType.url)); _loading = true; _loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, targetLoadIOError); _loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, targetLoadProgress); _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, targetLoadComplete); setFilter(null); // Reset the filters array _currentFilters = new Array(); } /** * Retrieves the current "filter target" -- the image that was selected to have filters * applied to it * @return The current filter target image */ public function getFilterTarget():DisplayObject { return _currentTarget; } /** * Adds a new filter to the set of filters that are applied to * the current filter target. Calling this method clears away the * current "temporary" filter and replaces it with the one * that's passed in the factory parameter. * * @param factory The IFilterFactory that will build the * current working filter. */ public function setFilter(factory:actionscript_book_FilterWorkbench_com_example_programmingas3_filterWorkbench_IFilterFactory):void { if (_filterFactory == factory) { return; } // Clean up the previous filter factory if (_filterFactory != null) { _filterFactory.removeEventListener(Event.CHANGE, filterChange); if (_currentTarget != null) { // refresh the image's filters (removing the last temporary filter) _currentTarget.filters = _currentFilters; } } // Store the new one (even if it's null) _filterFactory = factory; // Notify listeners that the filter has changed dispatchEvent(new Event(Event.CHANGE)); if (factory == null || _currentTarget == null) { return; } // apply the new filter applyTemporaryFilter(); _filterFactory.addEventListener(Event.CHANGE, filterChange); } /** * "Permanently" adds the current filter to the set of filters applied * to the target image. After this method is called, the next time * a filter's values change it is added as an additional filter rather than * replacing the filter that is current when applyFilter() is called. */ public function applyFilter():void { if (_filterFactory != null) { _currentFilters.push(_filterFactory.getFilter()); _currentTarget.filters = _currentFilters; setFilter(null); } } /** * Retrieves a String containing the ActionScript code that would be used to create the * currently selected filter. * * @return The ActionScript code to create the filter effect */ public function getCode():String { return (_filterFactory != null) ? _filterFactory.getCode() : ""; } // ------- Event Handling ------- private function filterChange(event:Event):void { applyTemporaryFilter(); // dispatch our own change event so the app knows to update the code display dispatchEvent(new Event(Event.CHANGE)); } // Called when an IO Error is reported by a loading filter target image. private function targetLoadIOError(event:IOErrorEvent):void { _loading = false; _loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, targetLoadIOError); _loader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, targetLoadProgress); _loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, targetLoadComplete); trace("load error"); } // Called when loading progress is reported by a loading filter target image. private function targetLoadProgress(event:ProgressEvent):void { dispatchEvent(event); } // Called when a filter target image finishes loading. private function targetLoadComplete(event:Event):void { _loading = false; _loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, targetLoadIOError); _loader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, targetLoadProgress); _loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, targetLoadComplete); _currentTarget = _loader.content; dispatchEvent(event); } private function applyTemporaryFilter():void { var currentFilter:BitmapFilter = _filterFactory.getFilter(); // Add the current filter to the set temporarily _currentFilters.push(currentFilter); // Refresh the filter set of the filter target _currentTarget.filters = _currentFilters; // Remove the current filter from the set // (This doesn't remove it from the filter target, since // the target uses a copy of the filters array internally.) _currentFilters.pop(); } } }