--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
+ xmlns:s="library://ns.adobe.com/flex/spark"
+ xmlns:mx="library://ns.adobe.com/flex/mx"
+ height="18"
+ width="10">
+
+ <fx:Declarations>
+ <fx:uint id="dotColor">0x8B8B8B</fx:uint>
+ <fx:uint id="fillColor">0xFFFFFF</fx:uint>
+ <fx:Number id="fillAlpha">0.2</fx:Number>
+ <fx:Boolean id="fillVisible">true</fx:Boolean>
+ </fx:Declarations>
+
+ <!-- fill a rectangle: -->
+ <s:Rect height="100%"
+ width="100%"
+ visible="{fillVisible}">
+ <s:fill>
+ <s:SolidColor color="{fillColor}"
+ alpha="{fillAlpha}"/>
+ </s:fill>
+ </s:Rect>
+
+ <!-- draw the drag dots handle -->
+ <!-- .. -->
+ <!-- .. -->
+ <!-- .. -->
+ <!-- .. -->
+ <s:Rect height="2"
+ width="2"
+ left="2"
+ top="2">
+ <s:fill>
+ <s:SolidColor color="{dotColor}"/>
+ </s:fill>
+ </s:Rect>
+ <s:Rect height="2"
+ width="2"
+ left="6"
+ top="2">
+ <s:fill>
+ <s:SolidColor color="{dotColor}"/>
+ </s:fill>
+ </s:Rect>
+ <s:Rect height="2"
+ width="2"
+ left="2"
+ top="6">
+ <s:fill>
+ <s:SolidColor color="{dotColor}"/>
+ </s:fill>
+ </s:Rect>
+ <s:Rect height="2"
+ width="2"
+ left="6"
+ top="6">
+ <s:fill>
+ <s:SolidColor color="{dotColor}"/>
+ </s:fill>
+ </s:Rect>
+ <s:Rect height="2"
+ width="2"
+ left="2"
+ top="10">
+ <s:fill>
+ <s:SolidColor color="{dotColor}"/>
+ </s:fill>
+ </s:Rect>
+ <s:Rect height="2"
+ width="2"
+ left="6"
+ top="10">
+ <s:fill>
+ <s:SolidColor color="{dotColor}"/>
+ </s:fill>
+ </s:Rect>
+ <s:Rect height="2"
+ width="2"
+ left="2"
+ top="14">
+ <s:fill>
+ <s:SolidColor color="{dotColor}"/>
+ </s:fill>
+ </s:Rect>
+ <s:Rect height="2"
+ width="2"
+ left="6"
+ top="14">
+ <s:fill>
+ <s:SolidColor color="{dotColor}"/>
+ </s:fill>
+ </s:Rect>
+
+</s:Group>
--- /dev/null
+package net.systemeD.controls {\r
+ import flash.events.Event;\r
+ import flash.events.MouseEvent;\r
+ import flash.geom.Rectangle;\r
+\r
+ import mx.controls.Button;\r
+ import mx.core.Container;\r
+ import mx.core.EdgeMetrics;\r
+ import mx.core.UIComponent;\r
+ import mx.managers.CursorManager;\r
+\r
+ /**\r
+ * Similar to the ResizeManager, this class adds support for moving a component by dragging it\r
+ * with the mouse. It also supports showing a custom cursor while dragging.\r
+ *\r
+ * @author Chris Callendar\r
+ * @date March 17th, 2009\r
+ */\r
+ public class MoveManager {\r
+\r
+ public static const DRAG_START:String = "dragStart";\r
+\r
+ public static const DRAGGING:String = "dragging";\r
+\r
+ public static const DRAG_END:String = "dragEnd";\r
+\r
+ // the component that is being moved\r
+ private var moveComponent:UIComponent;\r
+\r
+ // the component that when dragged causes the above component to move\r
+ private var dragComponent:UIComponent;\r
+\r
+ private var dragging:Boolean;\r
+\r
+ private var _enabled:Boolean;\r
+\r
+ private var _bringToFrontOnMove:Boolean;\r
+\r
+ private var _constrainToParentBounds:Boolean;\r
+\r
+ private var _constrainToBounds:Rectangle;\r
+\r
+ [Embed(source="../../../embedded/cursor_move.gif")]\r
+ public var moveIcon:Class;\r
+\r
+ private var moveCursorID:int;\r
+\r
+ public function MoveManager(moveComponent:UIComponent = null, dragComponent:UIComponent = null) {\r
+ dragging = false;\r
+ _enabled = true;\r
+ _bringToFrontOnMove = false;\r
+ _constrainToParentBounds = false;\r
+ _constrainToBounds = null;\r
+ moveCursorID = 0;\r
+ addMoveSupport(moveComponent, dragComponent);\r
+ }\r
+\r
+ public function get enabled():Boolean {\r
+ return _enabled;\r
+ }\r
+\r
+ public function set enabled(en:Boolean):void {\r
+ if (en != _enabled) {\r
+ _enabled = en;\r
+ }\r
+ }\r
+\r
+ public function get bringToFrontOnMove():Boolean {\r
+ return _bringToFrontOnMove;\r
+ }\r
+\r
+ public function set bringToFrontOnMove(value:Boolean):void {\r
+ _bringToFrontOnMove = value;\r
+ }\r
+\r
+ /**\r
+ * Returns true if the component's movement is constrained to within\r
+ * the parent's bounds.\r
+ */\r
+ public function get constrainToParentBounds():Boolean {\r
+ return _constrainToParentBounds;\r
+ }\r
+\r
+ /**\r
+ * Set to true if the component's movement is to be constrained to within\r
+ * the parent's bounds.\r
+ */\r
+ public function set constrainToParentBounds(value:Boolean):void {\r
+ _constrainToParentBounds = value;\r
+ }\r
+\r
+ /**\r
+ * Returns the bounds used to constrain the component's movement.\r
+ */\r
+ public function get constrainToBounds():Rectangle {\r
+ return _constrainToBounds;\r
+ }\r
+\r
+ /**\r
+ * Sets the bounds used to constrain the component's movement.\r
+ */\r
+ public function set constrainToBounds(value:Rectangle):void {\r
+ _constrainToBounds = value;\r
+ }\r
+\r
+ /**\r
+ * Adds support for moving a component.\r
+ * @param moveComponent the component that will have its x and y values changed\r
+ * @param dragComponent the component that will have a mouse_down listener added to listen\r
+ * for when the user drags it. If null then the moveComponent is used instead.\r
+ */\r
+ public function addMoveSupport(moveComponent:UIComponent, dragComponent:UIComponent = null):void {\r
+ this.moveComponent = moveComponent;\r
+ this.dragComponent = dragComponent;\r
+ if (dragComponent) {\r
+ dragComponent.addEventListener(MouseEvent.MOUSE_DOWN, dragComponentMouseDown);\r
+ } else if (moveComponent) {\r
+ moveComponent.addEventListener(MouseEvent.MOUSE_DOWN, dragComponentMouseDown);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Removes move support, removes the mouse listener and the move handle.\r
+ */\r
+ public function removeMoveSupport():void {\r
+ if (dragComponent) {\r
+ dragComponent.removeEventListener(MouseEvent.MOUSE_DOWN, dragComponentMouseDown);\r
+ } else if (moveComponent) {\r
+ moveComponent.removeEventListener(MouseEvent.MOUSE_DOWN, dragComponentMouseDown);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * This function gets called when the user presses down the mouse button on the\r
+ * dragComponent (or if not specified then the moveComponent).\r
+ * It starts the drag process.\r
+ */\r
+ private function dragComponentMouseDown(event:MouseEvent):void {\r
+ if (!enabled) {\r
+ return;\r
+ }\r
+\r
+ // move above all others\r
+ if (bringToFrontOnMove && moveComponent.parent) {\r
+ var index:int = moveComponent.parent.getChildIndex(moveComponent);\r
+ var last:int = moveComponent.parent.numChildren - 1;\r
+ if (index != last) {\r
+ moveComponent.parent.setChildIndex(moveComponent, last);\r
+ }\r
+ }\r
+\r
+ // Constain the movement by the parent's bounds?\r
+ var bounds:Rectangle = null;\r
+ if (constrainToBounds != null) {\r
+ bounds = constrainToBounds;\r
+ } else if (constrainToParentBounds && moveComponent.parent) {\r
+ bounds = new Rectangle(0, 0, moveComponent.parent.width, moveComponent.parent.height);\r
+ // need to reduce the size by the component's width/height\r
+ bounds.width = Math.max(0, bounds.width - moveComponent.width);\r
+ bounds.height = Math.max(0, bounds.height - moveComponent.height);\r
+ }\r
+ moveComponent.startDrag(false, bounds);\r
+ setMoveCursor();\r
+ moveComponent.systemManager.addEventListener(MouseEvent.MOUSE_MOVE, dragComponentMove);\r
+ moveComponent.systemManager.addEventListener(MouseEvent.MOUSE_UP, dragComponentMouseUp);\r
+ moveComponent.systemManager.stage.addEventListener(Event.MOUSE_LEAVE, dragComponentMouseUp);\r
+ }\r
+\r
+ private function dragComponentMove(event:MouseEvent):void {\r
+ if (!dragging) {\r
+ dragging = true;\r
+ moveComponent.clearStyle("top");\r
+ moveComponent.clearStyle("right");\r
+ moveComponent.clearStyle("bottom");\r
+ moveComponent.clearStyle("left");\r
+ moveComponent.dispatchEvent(new Event(DRAG_START));\r
+ }\r
+ moveComponent.dispatchEvent(new Event(DRAGGING));\r
+ }\r
+\r
+ private function dragComponentMouseUp(event:Event):void {\r
+ moveComponent.stopDrag();\r
+ removeMoveCursor();\r
+ if (dragging) {\r
+ dragging = false;\r
+ moveComponent.dispatchEvent(new Event(DRAG_END));\r
+ }\r
+ moveComponent.systemManager.removeEventListener(MouseEvent.MOUSE_MOVE, dragComponentMove);\r
+ moveComponent.systemManager.removeEventListener(MouseEvent.MOUSE_UP, dragComponentMouseUp);\r
+ moveComponent.systemManager.stage.removeEventListener(Event.MOUSE_LEAVE, dragComponentMouseUp);\r
+ }\r
+\r
+ private function setMoveCursor():void {\r
+ if ((moveCursorID == 0) && (moveIcon != null)) {\r
+ moveCursorID = CursorManager.setCursor(moveIcon, 2, -12, -10);\r
+ }\r
+ }\r
+\r
+ private function removeMoveCursor():void {\r
+ if (moveCursorID != 0) {\r
+ CursorManager.removeCursor(moveCursorID);\r
+ moveCursorID = 0;\r
+ }\r
+ }\r
+\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--- A skin class for a Spark TitleWindow container which supports resizing the window.
+
+ @see spark.skins.spark.TitleWindowCloseButtonSkin
+ @see spark.components.TitleWindow
+-->
+<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
+ xmlns:s="library://ns.adobe.com/flex/spark"
+ xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
+ xmlns:controls="net.systemeD.controls.*"
+ minHeight="76"
+ minWidth="76"
+ creationComplete="created(event)"
+ alpha.disabled="0.5"
+ alpha.disabledWithControlBar="0.5"
+ blendMode="normal"
+ mouseEnabled="false">
+
+ <fx:Metadata>
+ <![CDATA[
+ /** @copy spark.skins.spark.ApplicationSkin#hostComponent */
+ [HostComponent("spark.components.TitleWindow")]
+ ]]>
+ </fx:Metadata>
+
+ <fx:Script fb:purpose="styling">
+ /* Define the skin elements that should not be colorized.
+ For panel, border and title background are skinned, but the content area and title text are not. */
+ static private const exclusions:Array = ["background", "titleDisplay", "contentGroup"];
+
+ private var cornerRadius:Number;
+
+ override public function get colorizeExclusions():Array {
+ return exclusions;
+ }
+
+ override protected function initializationComplete():void {
+ useChromeColor = true;
+ super.initializationComplete();
+ }
+
+ override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
+ if (getStyle("borderVisible") == true) {
+ border.visible = true;
+ background.left = background.top = background.right = background.bottom = 1;
+ contents.left = contents.top = contents.right = contents.bottom = 1;
+ } else {
+ border.visible = false;
+ background.left = background.top = background.right = background.bottom = 0;
+ contents.left = contents.top = contents.right = contents.bottom = 0;
+ }
+
+ dropShadow.visible = getStyle("dropShadowVisible");
+
+ var cr:Number = getStyle("cornerRadius");
+ var withControls:Boolean =
+ (currentState == "disabledWithControlBar" ||
+ currentState == "normalWithControlBar" ||
+ currentState == "inactiveWithControlBar");
+
+ if (cornerRadius != cr) {
+ cornerRadius = cr;
+
+ dropShadow.tlRadius = cornerRadius;
+ dropShadow.trRadius = cornerRadius;
+ dropShadow.blRadius = withControls ? cornerRadius : 0;
+ dropShadow.brRadius = withControls ? cornerRadius : 0;
+
+ setPartCornerRadii(topMaskRect, withControls);
+ setPartCornerRadii(border, withControls);
+ setPartCornerRadii(background, withControls);
+ }
+
+ if (bottomMaskRect) {
+ setPartCornerRadii(bottomMaskRect, withControls);
+ }
+ borderStroke.color = getStyle("borderColor");
+ borderStroke.alpha = getStyle("borderAlpha");
+ backgroundFill.color = getStyle("backgroundColor");
+ backgroundFill.alpha = getStyle("backgroundAlpha");
+
+ super.updateDisplayList(unscaledWidth, unscaledHeight);
+ }
+
+ private function setPartCornerRadii(target:Rect, includeBottom:Boolean):void {
+ target.topLeftRadiusX = cornerRadius;
+ target.topRightRadiusX = cornerRadius;
+ target.bottomLeftRadiusX = includeBottom ? cornerRadius : 0;
+ target.bottomRightRadiusX = includeBottom ? cornerRadius : 0;
+ }
+ </fx:Script>
+ <fx:Script>
+ <![CDATA[
+ import mx.events.FlexEvent;
+
+ [Bindable]
+ public var resizeManager:ResizeManager;
+
+ [Bindable]
+ public var moveManager:MoveManager;
+
+ private function created(event:FlexEvent):void {
+ if (hostComponent.minWidth == 0) {
+ hostComponent.minWidth = minWidth;
+ }
+ if (hostComponent.minHeight == 0) {
+ hostComponent.minHeight = minHeight;
+ }
+ resizeManager = new ResizeManager(hostComponent, resizeHandle);
+ moveManager = new MoveManager(hostComponent, moveArea);
+ }
+ ]]>
+ </fx:Script>
+
+ <s:states>
+ <s:State name="normal"/>
+ <s:State name="inactive"
+ stateGroups="inactiveGroup"/>
+ <s:State name="disabled"/>
+ <s:State name="normalWithControlBar"
+ stateGroups="withControls"/>
+ <s:State name="inactiveWithControlBar"
+ stateGroups="withControls, inactiveGroup"/>
+ <s:State name="disabledWithControlBar"
+ stateGroups="withControls"/>
+ </s:states>
+
+ <!--- drop shadow can't be hittable so it stays sibling of other graphics @private-->
+ <s:RectangularDropShadow id="dropShadow"
+ bottom="0"
+ color="0x000000"
+ left="0"
+ right="0"
+ top="0"
+ alpha="0.32"
+ alpha.inactiveGroup="0.22"
+ angle="90"
+ blurX="20"
+ blurY="20"
+ distance="11"
+ distance.inactiveGroup="7"/>
+
+ <!--- drop shadow can't be hittable so all other graphics go in this group -->
+ <s:Group bottom="0"
+ left="0"
+ right="0"
+ top="0">
+
+ <!--- top group mask @private-->
+ <s:Group id="topGroupMask"
+ bottom="1"
+ left="1"
+ right="1"
+ top="1">
+ <!--- @private-->
+ <s:Rect id="topMaskRect"
+ bottom="0"
+ left="0"
+ right="0"
+ top="0">
+ <s:fill>
+ <s:SolidColor alpha="0"/>
+ </s:fill>
+ </s:Rect>
+ </s:Group>
+
+ <!--- bottom group mask @private-->
+ <s:Group id="bottomGroupMask"
+ includeIn="withControls"
+ bottom="1"
+ left="1"
+ right="1"
+ top="1">
+ <!--- @private-->
+ <s:Rect id="bottomMaskRect"
+ bottom="0"
+ left="0"
+ right="0"
+ top="0">
+ <s:fill>
+ <s:SolidColor alpha="0"/>
+ </s:fill>
+ </s:Rect>
+ </s:Group>
+
+ <!--- layer 1: border @private -->
+ <s:Rect id="border"
+ bottom="0"
+ left="0"
+ right="0"
+ top="0">
+ <s:stroke>
+ <!--- Defines the TitleWindowSkin class's border stroke. The default value is 1. -->
+ <s:SolidColorStroke id="borderStroke"
+ weight="1"/>
+ </s:stroke>
+ </s:Rect>
+
+ <!-- layer 2: background fill -->
+ <!--- Defines the appearance of the TitleWindowSkin class's background. -->
+ <s:Rect id="background"
+ bottom="1"
+ left="1"
+ right="1"
+ top="1">
+ <s:fill>
+ <!--- Defines the TitleWindowSkin class's background fill. The default color is 0xFFFFFF. -->
+ <s:SolidColor id="backgroundFill"
+ color="#FFFFFF"/>
+ </s:fill>
+ </s:Rect>
+
+ <!-- layer 3: contents -->
+ <!--- Contains the vertical stack of title bar content and control bar. -->
+ <s:Group id="contents"
+ bottom="1"
+ left="1"
+ right="1"
+ top="1">
+ <s:layout>
+ <s:VerticalLayout horizontalAlign="justify"
+ gap="0"/>
+ </s:layout>
+ <!--- @private -->
+ <s:Group id="topGroup"
+ mask="{topGroupMask}">
+
+ <!--- layer 0: title bar fill @private -->
+ <s:Rect id="tbFill"
+ bottom="1"
+ left="0"
+ right="0"
+ top="0">
+ <s:fill>
+ <s:LinearGradient rotation="90">
+ <s:GradientEntry color="0xD2D2D2"
+ color.inactiveGroup="0xEAEAEA"/>
+ <s:GradientEntry color="0x9A9A9A"
+ color.inactiveGroup="0xCECECE"/>
+ </s:LinearGradient>
+ </s:fill>
+ </s:Rect>
+
+ <!--- layer 1: title bar highlight @private -->
+ <s:Rect id="tbHilite"
+ bottom="0"
+ left="0"
+ right="0"
+ top="0">
+ <s:stroke>
+ <s:LinearGradientStroke rotation="90"
+ weight="1">
+ <s:GradientEntry color="0xE6E6E6"/>
+ <s:GradientEntry color="0xFFFFFF"
+ alpha="0.22"/>
+ </s:LinearGradientStroke>
+ </s:stroke>
+ <s:fill>
+ <s:LinearGradient rotation="90">
+ <s:GradientEntry color="0xFFFFFF"
+ alpha="0.15"/>
+ <s:GradientEntry color="0xFFFFFF"
+ alpha="0.15"
+ ratio="0.44"/>
+ <s:GradientEntry color="0xFFFFFF"
+ alpha="0"
+ ratio="0.4401"/>
+ </s:LinearGradient>
+ </s:fill>
+ </s:Rect>
+
+ <!--- layer 2: title bar divider @private -->
+ <s:Rect id="tbDiv"
+ height="1"
+ bottom="0"
+ left="0"
+ right="0">
+ <s:fill>
+ <s:SolidColor color="0x000000"
+ alpha="0.75"/>
+ </s:fill>
+ </s:Rect>
+
+ <!-- layer 3: text -->
+ <!--- @copy spark.components.Panel#titleDisplay -->
+ <s:Label id="titleDisplay"
+ minHeight="30"
+ bottom="0"
+ fontWeight="bold"
+ left="19"
+ right="36"
+ top="1"
+ verticalAlign="middle"
+ maxDisplayedLines="1"/>
+
+ <!-- layer 4: moveArea -->
+ <!--- @copy spark.components.TitleWindow#moveArea -->
+ <s:Group id="moveArea"
+ bottom="0"
+ left="0"
+ right="0"
+ top="0">
+ <controls:DragHandle left="4"
+ verticalCenter="0"
+ dotColor="#8B8B8B"
+ fillAlpha="0"/>
+ </s:Group>
+
+ <!--- @copy spark.components.TitleWindow#closeButton -->
+ <s:Button id="closeButton"
+ height="15"
+ width="15"
+ right="7"
+ top="7"
+ skinClass="spark.skins.spark.TitleWindowCloseButtonSkin"/>
+ </s:Group>
+
+ <!--
+ Note: setting the minimum size to 0 here so that changes to the host component's
+ size will not be thwarted by this skin part's minimum size. This is a compromise,
+ more about it here: http://bugs.adobe.com/jira/browse/SDK-21143
+ -->
+ <!--- @copy spark.components.SkinnableContainer#contentGroup -->
+ <s:Group id="contentGroup"
+ height="100%"
+ minHeight="0"
+ minWidth="0"
+ width="100%">
+ </s:Group>
+
+ <!--- @private -->
+ <s:Group id="bottomGroup"
+ includeIn="withControls"
+ minHeight="0"
+ minWidth="0">
+
+ <s:Group bottom="0"
+ left="0"
+ right="0"
+ top="0"
+ mask="{bottomGroupMask}">
+
+ <!-- layer 0: control bar divider line -->
+ <s:Rect height="1"
+ left="0"
+ right="0"
+ top="0"
+ alpha="0.22">
+ <s:fill>
+ <s:SolidColor color="0x000000"/>
+ </s:fill>
+ </s:Rect>
+
+ <!-- layer 1: control bar highlight -->
+ <s:Rect bottom="0"
+ left="0"
+ right="0"
+ top="1">
+ <s:stroke>
+ <s:LinearGradientStroke rotation="90"
+ weight="1">
+ <s:GradientEntry color="0xFFFFFF"/>
+ <s:GradientEntry color="0xD8D8D8"/>
+ </s:LinearGradientStroke>
+ </s:stroke>
+ </s:Rect>
+
+ <!-- layer 2: control bar fill -->
+ <s:Rect bottom="1"
+ left="1"
+ right="1"
+ top="2">
+ <s:fill>
+ <s:LinearGradient rotation="90">
+ <s:GradientEntry color="0xEDEDED"/>
+ <s:GradientEntry color="0xCDCDCD"/>
+ </s:LinearGradient>
+ </s:fill>
+ </s:Rect>
+ </s:Group>
+
+ <!--- @copy spark.components.Panel#controlBarGroup -->
+ <s:Group id="controlBarGroup"
+ minHeight="0"
+ minWidth="0"
+ bottom="1"
+ left="0"
+ right="0"
+ top="1">
+ <s:layout>
+ <s:HorizontalLayout paddingBottom="7"
+ paddingLeft="10"
+ paddingRight="10"
+ paddingTop="7"
+ gap="10"/>
+ </s:layout>
+ </s:Group>
+ </s:Group>
+ </s:Group>
+ </s:Group>
+
+ <controls:ResizeHandleLines id="resizeHandle"
+ enabled="{resizeManager.enabled}"
+ bottom="1"
+ right="1"
+ visible="{resizeManager.enabled}"/>
+
+</s:SparkSkin>
--- /dev/null
+package flexScript {
+ import flash.events.MouseEvent;
+
+ import mx.containers.Panel;
+ import mx.controls.Button;
+
+ public class ResizablePanel extends Panel {
+ private var resizer:Button = new Button();
+
+ public function ResizablePanel() {
+ super();
+ resizer.addEventListener(MouseEvent.MOUSE_DOWN, resizeDown);
+ }
+ override protected function createChildren():void {
+ resizer.height=10;
+ resizer.width = 10;
+ super.createChildren();
+ rawChildren.addChild(resizer);
+ }
+ override protected function updateDisplayList(w:Number, h:Number):void {
+ super.updateDisplayList(w,h);
+ resizer.y = h - resizer.height;
+ resizer.x = w - resizer.width;
+ }
+ private function resizeDown(e:MouseEvent):void {
+ stage.addEventListener(MouseEvent.MOUSE_MOVE, scalePanel);
+ stage.addEventListener(MouseEvent.MOUSE_UP, stopScale);
+ }
+ private function scalePanel(e:MouseEvent):void{
+ if((stage.mouseX - x)>50) width = (stage.mouseX-x);
+ if((stage.mouseY - y)>50) height = (stage.mouseY-y);
+ }
+ private function stopScale(e:MouseEvent):void{
+ stage.removeEventListener(MouseEvent.MOUSE_MOVE, scalePanel);
+ stage.removeEventListener(MouseEvent.MOUSE_UP, stopScale);
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--- The skin class for a Spark Panel container that supports resizing the panel.
+
+ @see spark.components.Panel
+-->
+<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
+ xmlns:s="library://ns.adobe.com/flex/spark"
+ xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
+ xmlns:controls="net.systemeD.controls.*"
+ minHeight="127"
+ minWidth="131"
+ creationComplete="created(event)"
+ alpha.disabled="0.5"
+ alpha.disabledWithControlBar="0.5"
+ blendMode="normal"
+ mouseEnabled="false">
+
+ <fx:Metadata>
+ <![CDATA[
+ /**
+ * @copy spark.skins.spark.ApplicationSkin#hostComponent
+ */
+ [HostComponent("spark.components.Panel")]
+ ]]>
+ </fx:Metadata>
+
+ <fx:Script fb:purpose="styling">
+ /* Define the skin elements that should not be colorized.
+ For panel, border and title background are skinned, but the content area and title text are not. */
+ static private const exclusions:Array = ["background", "titleDisplay", "contentGroup", "controlBarGroup"];
+
+ /**
+ * @private
+ */
+ override public function get colorizeExclusions():Array {
+ return exclusions;
+ }
+
+ /**
+ * @private
+ */
+ override protected function initializationComplete():void {
+ useChromeColor = true;
+ super.initializationComplete();
+ }
+
+ /**
+ * @private
+ */
+ override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
+ if (getStyle("borderVisible") == true) {
+ border.visible = true;
+ background.left = background.top = background.right = background.bottom = 1;
+ contents.left = contents.top = contents.right = contents.bottom = 1;
+ } else {
+ border.visible = false;
+ background.left = background.top = background.right = background.bottom = 0;
+ contents.left = contents.top = contents.right = contents.bottom = 0;
+ }
+
+ dropShadow.visible = getStyle("dropShadowVisible");
+
+ var cr:Number = getStyle("cornerRadius");
+ var withControls:Boolean =
+ (currentState == "disabledWithControlBar" ||
+ currentState == "normalWithControlBar");
+
+ if (cornerRadius != cr) {
+ cornerRadius = cr;
+
+ dropShadow.tlRadius = cornerRadius;
+ dropShadow.trRadius = cornerRadius;
+ dropShadow.blRadius = withControls ? cornerRadius : 0;
+ dropShadow.brRadius = withControls ? cornerRadius : 0;
+
+ setPartCornerRadii(topMaskRect, withControls);
+ setPartCornerRadii(border, withControls);
+ setPartCornerRadii(background, withControls);
+ }
+
+ if (bottomMaskRect)
+ setPartCornerRadii(bottomMaskRect, withControls);
+
+ borderStroke.color = getStyle("borderColor");
+ borderStroke.alpha = getStyle("borderAlpha");
+ backgroundFill.color = getStyle("backgroundColor");
+ backgroundFill.alpha = getStyle("backgroundAlpha");
+
+ super.updateDisplayList(unscaledWidth, unscaledHeight);
+ }
+
+ /**
+ * @private
+ */
+ private function setPartCornerRadii(target:Rect, includeBottom:Boolean):void {
+ target.topLeftRadiusX = cornerRadius;
+ target.topRightRadiusX = cornerRadius;
+ target.bottomLeftRadiusX = includeBottom ? cornerRadius : 0;
+ target.bottomRightRadiusX = includeBottom ? cornerRadius : 0;
+ }
+
+ private var cornerRadius:Number;
+ </fx:Script>
+
+ <fx:Script>
+ <![CDATA[
+ import mx.events.FlexEvent;
+
+ [Bindable]public var resizeManager:ResizeManager;
+
+ private function created(event:FlexEvent):void {
+ if (hostComponent.minWidth == 0) {
+ hostComponent.minWidth = minWidth;
+ }
+ if (hostComponent.minHeight == 0) {
+ hostComponent.minHeight = minHeight;
+ }
+ resizeManager = new ResizeManager(hostComponent, resizeHandle);
+ }
+ ]]>
+ </fx:Script>
+
+ <s:states>
+ <s:State name="normal"/>
+ <s:State name="disabled"/>
+ <s:State name="normalWithControlBar"
+ stateGroups="withControls"/>
+ <s:State name="disabledWithControlBar"
+ stateGroups="withControls"/>
+ </s:states>
+
+ <!-- drop shadow can't be hittable so it stays sibling of other graphics -->
+ <!--- @private -->
+ <s:RectangularDropShadow id="dropShadow"
+ bottom="0"
+ color="#000000"
+ left="0"
+ right="0"
+ top="0"
+ alpha="0.32"
+ angle="90"
+ blurX="20"
+ blurY="20"
+ distance="11"/>
+
+ <!-- drop shadow can't be hittable so all other graphics go in this group -->
+ <s:Group bottom="0"
+ left="0"
+ right="0"
+ top="0">
+
+ <!-- top group mask -->
+ <!--- @private -->
+ <s:Group id="topGroupMask"
+ bottom="1"
+ left="1"
+ right="1"
+ top="1">
+ <!--- @private -->
+ <s:Rect id="topMaskRect"
+ bottom="0"
+ left="0"
+ right="0"
+ top="0">
+ <s:fill>
+ <s:SolidColor alpha="0"/>
+ </s:fill>
+ </s:Rect>
+ </s:Group>
+
+ <!-- bottom group mask -->
+ <!--- @private -->
+ <s:Group id="bottomGroupMask"
+ includeIn="normalWithControlBar, disabledWithControlBar"
+ bottom="1"
+ left="1"
+ right="1"
+ top="1">
+ <!--- @private -->
+ <s:Rect id="bottomMaskRect"
+ bottom="0"
+ left="0"
+ right="0"
+ top="0">
+ <s:fill>
+ <s:SolidColor alpha="0"/>
+ </s:fill>
+ </s:Rect>
+ </s:Group>
+
+ <!-- layer 1: border -->
+ <!--- @private -->
+ <s:Rect id="border"
+ bottom="0"
+ left="0"
+ right="0"
+ top="0">
+ <s:stroke>
+ <!--- @private -->
+ <s:SolidColorStroke id="borderStroke"
+ weight="1"/>
+ </s:stroke>
+ </s:Rect>
+
+ <!-- layer 2: background fill -->
+ <!--- Defines the appearance of the PanelSkin class's background. -->
+ <s:Rect id="background"
+ bottom="1"
+ left="1"
+ right="1"
+ top="1">
+ <s:fill>
+ <!--- @private
+ Defines the PanelSkin class's background fill. The default color is 0xFFFFFF. -->
+ <s:SolidColor id="backgroundFill"
+ color="#FFFFFF"/>
+ </s:fill>
+ </s:Rect>
+
+ <!-- layer 3: contents -->
+ <!--- Contains the vertical stack of titlebar content and controlbar. -->
+ <s:Group id="contents"
+ bottom="1"
+ left="1"
+ right="1"
+ top="1">
+ <s:layout>
+ <s:VerticalLayout horizontalAlign="justify"
+ gap="0"/>
+ </s:layout>
+
+ <!--- @private -->
+ <s:Group id="topGroup"
+ mask="{topGroupMask}">
+
+ <!-- layer 0: title bar fill -->
+ <!--- @private -->
+ <s:Rect id="tbFill"
+ bottom="1"
+ left="0"
+ right="0"
+ top="0">
+ <s:fill>
+ <s:LinearGradient rotation="90">
+ <s:GradientEntry color="0xE2E2E2"/>
+ <s:GradientEntry color="0xD9D9D9"/>
+ </s:LinearGradient>
+ </s:fill>
+ </s:Rect>
+
+ <!-- layer 1: title bar highlight -->
+ <!--- @private -->
+ <s:Rect id="tbHilite"
+ bottom="0"
+ left="0"
+ right="0"
+ top="0">
+ <s:stroke>
+ <s:LinearGradientStroke rotation="90"
+ weight="1">
+ <s:GradientEntry color="0xEAEAEA"/>
+ <s:GradientEntry color="0xD9D9D9"/>
+ </s:LinearGradientStroke>
+ </s:stroke>
+ </s:Rect>
+
+ <!-- layer 2: title bar divider -->
+ <!--- @private -->
+ <s:Rect id="tbDiv"
+ height="1"
+ bottom="0"
+ left="0"
+ right="0">
+ <s:fill>
+ <s:SolidColor color="0xC0C0C0"/>
+ </s:fill>
+ </s:Rect>
+
+ <!-- layer 3: text -->
+ <!--- @copy spark.components.Panel#titleDisplay -->
+ <s:Label id="titleDisplay"
+ minHeight="30"
+ bottom="0"
+ fontWeight="bold"
+ left="9"
+ right="3"
+ top="1"
+ verticalAlign="middle"
+ maxDisplayedLines="1">
+ </s:Label>
+ </s:Group>
+
+ <!--
+ Note: setting the minimum size to 0 here so that changes to the host component's
+ size will not be thwarted by this skin part's minimum size. This is a compromise,
+ more about it here: http://bugs.adobe.com/jira/browse/SDK-21143
+ -->
+ <!--- @copy spark.components.SkinnableContainer#contentGroup -->
+ <s:Group id="contentGroup"
+ height="100%"
+ minHeight="0"
+ minWidth="0"
+ width="100%">
+ </s:Group>
+
+ <!--- @private -->
+ <s:Group id="bottomGroup"
+ includeIn="normalWithControlBar, disabledWithControlBar"
+ minHeight="0"
+ minWidth="0">
+
+ <s:Group bottom="0"
+ left="0"
+ right="0"
+ top="0"
+ mask="{bottomGroupMask}">
+
+ <!-- layer 0: control bar divider line -->
+ <s:Rect height="1"
+ left="0"
+ right="0"
+ top="0"
+ alpha="0.22">
+ <s:fill>
+ <s:SolidColor color="0x000000"/>
+ </s:fill>
+ </s:Rect>
+
+ <!-- layer 1: control bar highlight -->
+ <s:Rect bottom="0"
+ left="0"
+ right="0"
+ top="1">
+ <s:stroke>
+ <s:LinearGradientStroke rotation="90"
+ weight="1">
+ <s:GradientEntry color="0xE5E5E5"/>
+ <s:GradientEntry color="0xD8D8D8"/>
+ </s:LinearGradientStroke>
+ </s:stroke>
+ </s:Rect>
+
+ <!-- layer 2: control bar fill -->
+ <s:Rect bottom="1"
+ left="1"
+ right="1"
+ top="2">
+ <s:fill>
+ <s:LinearGradient rotation="90">
+ <s:GradientEntry color="0xDADADA"/>
+ <s:GradientEntry color="0xC5C5C5"/>
+ </s:LinearGradient>
+ </s:fill>
+ </s:Rect>
+ </s:Group>
+ <!-- layer 3: control bar -->
+ <!--- @copy spark.components.Panel#controlBarGroup -->
+ <s:Group id="controlBarGroup"
+ minHeight="0"
+ minWidth="0"
+ bottom="1"
+ left="0"
+ right="0"
+ top="1">
+ <s:layout>
+ <s:HorizontalLayout horizontalAlign="center"
+ paddingBottom="7"
+ paddingLeft="10"
+ paddingRight="10"
+ paddingTop="7"
+ gap="10"/>
+ </s:layout>
+ </s:Group>
+ </s:Group>
+ </s:Group>
+ </s:Group>
+
+ <controls:ResizeHandleLines id="resizeHandle"
+ enabled="{resizeManager.enabled}"
+ bottom="1"
+ right="1"
+ visible="{resizeManager.enabled}"/>
+
+</s:SparkSkin>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
+ xmlns:s="library://ns.adobe.com/flex/spark"
+ xmlns:mx="library://ns.adobe.com/flex/mx"
+ height="13"
+ width="13">
+
+ <!-- fill a rectangle:
+ <s:Rect height="100%"
+ width="100%">
+ <s:fill>
+ <s:SolidColor color="#ffffff"
+ alpha="0.2"/>
+ </s:fill>
+ </s:Rect>
+ -->
+ <!-- fill a triangle: -->
+ <s:Path data="M 0 {height} L {width} 0 V {height} H {0} Z">
+ <s:fill>
+ <s:SolidColor color="#ffffff"
+ alpha="0.2"/>
+ </s:fill>
+ </s:Path>
+
+ <!-- draw the resize lines handle 13x13 -->
+ <!-- / -->
+ <!-- // -->
+ <!-- /// -->
+ <s:Line xFrom="1"
+ xTo="12"
+ yFrom="12"
+ yTo="1">
+ <s:stroke>
+ <s:SolidColorStroke color="#8B8B8B"/>
+ </s:stroke>
+ </s:Line>
+ <s:Line xFrom="2"
+ xTo="12"
+ yFrom="12"
+ yTo="2">
+ <s:stroke>
+ <s:SolidColorStroke color="#DADADA"/>
+ </s:stroke>
+ </s:Line>
+
+ <s:Line xFrom="5"
+ xTo="12"
+ yFrom="12"
+ yTo="5">
+ <s:stroke>
+ <s:SolidColorStroke color="#8B8B8B"/>
+ </s:stroke>
+ </s:Line>
+ <s:Line xFrom="6"
+ xTo="12"
+ yFrom="12"
+ yTo="6">
+ <s:stroke>
+ <s:SolidColorStroke color="#DADADA"/>
+ </s:stroke>
+ </s:Line>
+
+ <s:Line xFrom="9"
+ xTo="12"
+ yFrom="12"
+ yTo="9">
+ <s:stroke>
+ <s:SolidColorStroke color="#8B8B8B"/>
+ </s:stroke>
+ </s:Line>
+ <s:Line xFrom="10"
+ xTo="12"
+ yFrom="12"
+ yTo="10">
+ <s:stroke>
+ <s:SolidColorStroke color="#DADADA"/>
+ </s:stroke>
+ </s:Line>
+
+</s:Group>
--- /dev/null
+package net.systemeD.controls {\r
+ import flash.events.Event;\r
+ import flash.events.EventDispatcher;\r
+ import flash.events.MouseEvent;\r
+ import flash.geom.Point;\r
+ import flash.geom.Rectangle;\r
+ import flash.utils.Dictionary;\r
+\r
+ import mx.core.FlexGlobals;\r
+ import mx.core.UIComponent;\r
+ import mx.events.ResizeEvent;\r
+ import mx.managers.CursorManager;\r
+\r
+ import spark.primitives.Rect;\r
+\r
+ /**\r
+ * This is the style direction that can be set on the resize component.\r
+ * Defaults to "both" which means the component can be resized horizontally and vertically.\r
+ */\r
+ [Style(name="resizeDirection", type="String", enumeration="both,vertical,horizontal", inherit="no")]\r
+\r
+ /**\r
+ * Utility class for allowing containers to be resized by a resize handle.\r
+ * The resize handle will cause the UIComponent to be resized when the user drags the handle.\r
+ * It also supports showing a custom cursor while the resizing is occurring.\r
+ * The resize component can also be restricted to only allow resizing in the horizontal\r
+ * or vertical direction.\r
+ *\r
+ * @author Chris Callendar\r
+ * @date March 17th, 2009\r
+ */\r
+ public class ResizeManager extends EventDispatcher {\r
+\r
+ public static const RESIZE_START:String = "resizeStart";\r
+\r
+ public static const RESIZE_END:String = "resizeEnd";\r
+\r
+ public static const RESIZING:String = "resizing";\r
+\r
+ public static const STYLE_RESIZE_DIRECTION:String = "resizeDirection";\r
+\r
+ public static const DIRECTION_BOTH:String = "both";\r
+\r
+ public static const DIRECTION_HORIZONTAL:String = "horizontal";\r
+\r
+ public static const DIRECTION_VERTICAL:String = "vertical";\r
+\r
+ private static const resizeDirections:Dictionary = new Dictionary(true);\r
+\r
+ private const RESIZE_HANDLE_SIZE:int = 16;\r
+\r
+ private var resizeInitX:Number = 0;\r
+\r
+ private var resizeInitY:Number = 0;\r
+\r
+ private var _resizeHandle:UIComponent;\r
+\r
+ private var _enabled:Boolean;\r
+\r
+ private var _bringToFrontOnResize:Boolean;\r
+\r
+ private var _resizeDirection:String;\r
+\r
+ private var _resizeComponent:UIComponent;\r
+\r
+ private var _constrainToParentBounds:Boolean;\r
+\r
+ private var isResizing:Boolean;\r
+\r
+ private var startWidth:Number;\r
+\r
+ private var startHeight:Number;\r
+\r
+ [Embed(source="../../../embedded/cursor_resize.gif")]\r
+ public var resizeCursorIcon:Class;\r
+\r
+ private var resizeCursorID:int;\r
+\r
+\r
+ public function ResizeManager(resizeComponent:UIComponent = null, resizeHandle:UIComponent = null, resizeDirection:String = "both") {\r
+ this._enabled = true;\r
+ this.resizeComponent = resizeComponent;\r
+ this.resizeHandle = resizeHandle;\r
+ this._bringToFrontOnResize = false;\r
+ this._resizeDirection = resizeDirection;\r
+ resizeCursorID = 0;\r
+ }\r
+\r
+ [Bindable("enabledChanged")]\r
+ public function get enabled():Boolean {\r
+ return _enabled && (resizeComponent != null) && resizeComponent.enabled;\r
+ }\r
+\r
+ public function set enabled(en:Boolean):void {\r
+ if (en != _enabled) {\r
+ _enabled = en;\r
+ dispatchEvent(new Event("enabledChanged"));\r
+ }\r
+ }\r
+\r
+ [Bindable("resizeComponentChanged")]\r
+ public function get resizeComponent():UIComponent {\r
+ return _resizeComponent;\r
+ }\r
+\r
+ public function set resizeComponent(value:UIComponent):void {\r
+ if (value != _resizeComponent) {\r
+ _resizeComponent = value;\r
+ dispatchEvent(new Event("resizeComponentChanged"));\r
+ }\r
+ }\r
+\r
+ [Bindable("bringToFrontOnResizeChanged")]\r
+ public function get bringToFrontOnResize():Boolean {\r
+ return _bringToFrontOnResize;\r
+ }\r
+\r
+ public function set bringToFrontOnResize(value:Boolean):void {\r
+ if (value != _bringToFrontOnResize) {\r
+ _bringToFrontOnResize = value;\r
+ dispatchEvent(new Event("bringToFrontOnResizeChanged"));\r
+ }\r
+ }\r
+\r
+ [Bindable("resizeDirectionChanged")]\r
+ /**\r
+ * Sets the resize direction.\r
+ * Defaults to both, meaning that the component can be resized in the horizontal\r
+ * and the vertical directions.\r
+ * If the direction is set to "horizontal", then the component can only be resized\r
+ * in the horizontal direction.\r
+ * Similarily when the direction is "vertical" only vertical resizing is allowed.\r
+ */\r
+ public function get resizeDirection():String {\r
+ var direction:String = DIRECTION_BOTH;\r
+ if (_resizeDirection == DIRECTION_BOTH) {\r
+ // first check if a style was set on the resize component\r
+ var style:Object = resizeComponent.getStyle(STYLE_RESIZE_DIRECTION);\r
+ if (style != null) {\r
+ direction = String(style);\r
+ } else {\r
+ direction = resizeDirections[resizeComponent];\r
+ }\r
+ if ((direction != DIRECTION_HORIZONTAL) && (direction != DIRECTION_VERTICAL)) {\r
+ direction = DIRECTION_BOTH;\r
+ }\r
+ }\r
+ return direction;\r
+ }\r
+\r
+ public function set resizeDirection(value:String):void {\r
+ if (value != _resizeDirection) {\r
+ _resizeDirection = value;\r
+ dispatchEvent(new Event("resizeDirectionChanged"));\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns the resizeHandle UIComponent.\r
+ */\r
+ [Bindable("resizeHandleChanged")]\r
+ public function get resizeHandle():UIComponent {\r
+ return _resizeHandle;\r
+ }\r
+\r
+ public function set resizeHandle(value:UIComponent):void {\r
+ if (value != _resizeHandle) {\r
+ if (_resizeHandle) {\r
+ _resizeHandle.removeEventListener(MouseEvent.MOUSE_DOWN, resizeHandler);\r
+ _resizeHandle.removeEventListener(MouseEvent.MOUSE_OVER, mouseOverResizeHandler);\r
+ _resizeHandle.removeEventListener(MouseEvent.MOUSE_OUT, mouseOutResizeHandler);\r
+ }\r
+ this._resizeHandle = value;\r
+ if (_resizeHandle) {\r
+ _resizeHandle.addEventListener(MouseEvent.MOUSE_DOWN, resizeHandler, false, 0, true);\r
+ _resizeHandle.addEventListener(MouseEvent.MOUSE_OVER, mouseOverResizeHandler, false, 0, true);\r
+ _resizeHandle.addEventListener(MouseEvent.MOUSE_OUT, mouseOutResizeHandler, false, 0, true);\r
+ if (!_resizeHandle.toolTip) {\r
+ _resizeHandle.toolTip = "Drag this handle to resize the component";\r
+ }\r
+ }\r
+ dispatchEvent(new Event("resizeHandleChanged"));\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns true if the resizing should be constrained to keep the resizeComponent from going outside the parent bounds.\r
+ */\r
+ public function get constrainToParentBounds():Boolean {\r
+ return _constrainToParentBounds;\r
+ }\r
+\r
+ /**\r
+ * Set to true to constrain the resizing to keep the resize component inside the parent bounds.\r
+ */\r
+ public function set constrainToParentBounds(value:Boolean):void {\r
+ _constrainToParentBounds = value;\r
+ }\r
+\r
+\r
+ // Resize event handler\r
+ private function resizeHandler(event:MouseEvent):void {\r
+ if (enabled) {\r
+ event.stopImmediatePropagation();\r
+ startResize(event.stageX, event.stageY);\r
+ }\r
+ }\r
+\r
+ private function startResize(globalX:Number, globalY:Number):void {\r
+ // dispatch a resizeStart event - can be cancelled!\r
+ var event:ResizeEvent = new ResizeEvent(RESIZE_START, false, true, resizeComponent.width, resizeComponent.height);\r
+ var okay:Boolean = resizeComponent.dispatchEvent(event);\r
+ if (okay) {\r
+ isResizing = true;\r
+\r
+ // move above all others\r
+ if (bringToFrontOnResize && resizeComponent.parent) {\r
+ var index:int = resizeComponent.parent.getChildIndex(resizeComponent);\r
+ var last:int = resizeComponent.parent.numChildren - 1;\r
+ if (index != last) {\r
+ resizeComponent.parent.setChildIndex(resizeComponent, last);\r
+ }\r
+ }\r
+\r
+ resizeInitX = globalX;\r
+ resizeInitY = globalY;\r
+ startWidth = resizeComponent.width;\r
+ startHeight = resizeComponent.height;\r
+ // Add event handlers so that the SystemManager handles the mouseMove and mouseUp events. \r
+ // Set useCapure flag to true to handle these events \r
+ // during the capture phase so no other component tries to handle them.\r
+ resizeComponent.systemManager.addEventListener(MouseEvent.MOUSE_MOVE, resizeMouseMoveHandler, true, 0, true);\r
+ resizeComponent.systemManager.addEventListener(MouseEvent.MOUSE_UP, resizeMouseUpHandler, true, 0, true);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Resizes this panel as the user moves the mouse with the mouse button down.\r
+ * Also restricts the width and height based on the resizeComponent's minWidth, maxWidth, minHeight, and\r
+ * maxHeight properties.\r
+ */\r
+ private function resizeMouseMoveHandler(event:MouseEvent):void {\r
+ event.stopImmediatePropagation();\r
+\r
+ var oldWidth:Number = resizeComponent.width;\r
+ var oldHeight:Number = resizeComponent.height;\r
+ var newWidth:Number = oldWidth + event.stageX - resizeInitX;\r
+ var newHeight:Number = oldHeight + event.stageY - resizeInitY;\r
+ //trace("Changing size from " + oldWidth + "x" + oldHeight + " to " + newWidth + "x" + newHeight);\r
+\r
+ var resizeH:Boolean = (resizeDirection != DIRECTION_VERTICAL);\r
+ var resizeV:Boolean = (resizeDirection != DIRECTION_HORIZONTAL);\r
+\r
+ // constrain the size to keep the resize component inside the parent bounds\r
+ if (constrainToParentBounds && resizeComponent.parent) {\r
+ var parentWidth:Number = resizeComponent.parent.width;\r
+ var parentHeight:Number = resizeComponent.parent.height;\r
+ if ((resizeComponent.x + newWidth) > parentWidth) {\r
+ newWidth = parentWidth - resizeComponent.x;\r
+ }\r
+ if ((resizeComponent.y + newHeight) > parentHeight) {\r
+ newHeight = parentHeight - resizeComponent.y;\r
+ }\r
+ }\r
+ // restrict the width/height\r
+ if ((newWidth >= resizeComponent.minWidth) && (newWidth <= resizeComponent.maxWidth) && resizeH) {\r
+ resizeComponent.width = newWidth;\r
+ }\r
+ if ((newHeight >= resizeComponent.minHeight) && (newHeight <= resizeComponent.maxHeight) && resizeV) {\r
+ resizeComponent.height = newHeight;\r
+ }\r
+\r
+\r
+ resizeInitX = event.stageX;\r
+ resizeInitY = event.stageY;\r
+\r
+ // Update the scrollRect property (this is used by the PopUpManager)\r
+ // will usually be null\r
+ if (resizeComponent.scrollRect) {\r
+ var rect:Rectangle = resizeComponent.scrollRect;\r
+ rect.width = resizeComponent.width;\r
+ rect.height = resizeComponent.height;\r
+ resizeComponent.scrollRect = rect;\r
+ }\r
+\r
+ resizeComponent.dispatchEvent(new ResizeEvent(RESIZING, false, false, oldWidth, oldHeight));\r
+ }\r
+\r
+ /**\r
+ * Removes the event handlers from the SystemManager.\r
+ */\r
+ private function resizeMouseUpHandler(event:MouseEvent):void {\r
+ event.stopImmediatePropagation();\r
+ resizeComponent.systemManager.removeEventListener(MouseEvent.MOUSE_MOVE, resizeMouseMoveHandler, true);\r
+ resizeComponent.systemManager.removeEventListener(MouseEvent.MOUSE_UP, resizeMouseUpHandler, true);\r
+ if (isResizing) {\r
+ isResizing = false;\r
+ resizeComponent.dispatchEvent(new ResizeEvent(RESIZE_END, false, false, startWidth, startHeight));\r
+ }\r
+\r
+ // check if the mouse is outside the resize handle\r
+ var pt:Point = resizeHandle.globalToLocal(new Point(event.stageX, event.stageY));\r
+ var bounds:Rectangle = new Rectangle(0, 0, resizeHandle.width, resizeHandle.height);\r
+ var isOver:Boolean = bounds.containsPoint(pt);\r
+ if (!isOver) {\r
+ removeResizeCursor();\r
+ }\r
+ }\r
+\r
+ private function mouseOverResizeHandler(event:MouseEvent):void {\r
+ setResizeCursor();\r
+ FlexGlobals.topLevelApplication.systemManager.addEventListener(MouseEvent.MOUSE_OUT, mouseOutResizeHandler, true, 0, true);\r
+ }\r
+\r
+ private function mouseOutResizeHandler(event:MouseEvent):void {\r
+ if (!isResizing) {\r
+ removeResizeCursor();\r
+ FlexGlobals.topLevelApplication.systemManager.removeEventListener(MouseEvent.MOUSE_OUT, mouseOutResizeHandler, true);\r
+ }\r
+ }\r
+\r
+ private function setResizeCursor():void {\r
+ if ((resizeCursorID == 0) && (resizeCursorIcon != null)) {\r
+ resizeCursorID = CursorManager.setCursor(resizeCursorIcon);\r
+ }\r
+ }\r
+\r
+ private function removeResizeCursor():void {\r
+ if (resizeCursorID != 0) {\r
+ CursorManager.removeCursor(resizeCursorID);\r
+ resizeCursorID = 0;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Sets which direction the component can be resized - "horizontal", "vertical", or "both" (default).\r
+ */\r
+ public static function setResizeDirection(resizeComponent:UIComponent, direction:String = "both"):void {\r
+ if (resizeComponent != null) {\r
+ if ((direction == DIRECTION_HORIZONTAL) || (direction == DIRECTION_VERTICAL)) {\r
+ resizeDirections[resizeComponent] = direction;\r
+ } else if (resizeDirections[resizeComponent] != null) {\r
+ delete resizeDirections[resizeComponent];\r
+ }\r
+ }\r
+ }\r
+\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<s:TitleWindow
+ xmlns:fx="http://ns.adobe.com/mxml/2009"
+ xmlns:mx="library://ns.adobe.com/flex/mx"
+ xmlns:s="library://ns.adobe.com/flex/spark"
+ xmlns:potlatch2="net.systemeD.potlatch2.*"
+ xmlns:controls="net.systemeD.controls.*"
+ skinClass="net.systemeD.controls.ResizableDraggableTitleWindowSkin"
+ title="Potlatch 2"
+ height="400" width="400"
+ close="setFloatingMapVisible(false);"
+ styleName="theFloatingMap">
+
+ <mx:UIComponent id='container' includeInLayout='false' depth='1' />
+
+ <mx:PopUpMenuButton id='imageryMenu' label='Imagery' x='5' y='5' depth='2' labelField='name'
+ dataProvider="{Imagery.instance().getAvailableImagery(map)}"
+ itemClick="itemClickHandler(event)"
+ />
+
+ <s:CheckBox label="Lock zoom" selected="{zoomLocked}" id="lockZoom" x='5' y='30' depth='3'
+ change="setLockZoom(lockZoom.selected)" />
+
+ <fx:Script><![CDATA[
+
+ import net.systemeD.halcyon.Map;
+ import net.systemeD.halcyon.MapEvent;
+ import net.systemeD.halcyon.TileSet;
+ import net.systemeD.potlatch2.collections.Imagery;
+ import mx.core.UIComponent;
+ import mx.events.ResizeEvent;
+ import mx.events.ListEvent;
+ import mx.events.MenuEvent;
+ import mx.collections.ArrayCollection;
+
+ private var controller:EditController;
+ [Bindable] private var map:Map;
+ [Bindable] private var zoomLocked:Boolean=false;
+ private var maxZoom:uint=50;
+ private var crosshair:Sprite=new Sprite();
+
+ /* FloatingMap still to do:
+ - selection UI
+ - zoom lock button
+ - show/hide (and close box)
+ - auto position (top RH corner?)
+ - crosshair
+ - why does the main imagery change?
+ - credit
+ */
+
+ public function init(controller:EditController):void {
+ this.controller=controller;
+ addElement(container);
+
+ // Attribution and terms
+ var overlay:Sprite=TileSet.overlaySprite();
+ crosshair.graphics.lineStyle(1,0);
+ crosshair.graphics.moveTo(-10, 0);
+ crosshair.graphics.lineTo( 10, 0);
+ crosshair.graphics.moveTo( 0,-10);
+ crosshair.graphics.lineTo( 0, 10);
+
+ // Create map
+ map = new Map(overlay);
+ updateSize();
+ container.addChild(map);
+ container.addChild(overlay);
+ container.addChild(crosshair);
+
+ // Imagery collection
+ var imagery:Imagery = Imagery.instance();
+ imagery.addEventListener('imageryLoaded',function(e:Event):void {
+ var bg:Object=imagery.findBackgroundWithName("Bing aerial imagery");
+ map.tileset.setBackgroundFromImagery(bg,false);
+ imageryMenu.label=bg.name;
+ if (visible) map.tileset.update();
+ controller.map.addEventListener(MapEvent.MOUSE_MOVE,function(e:MapEvent):void {
+ if (visible) map.updateCoordsFromLatLon(e.params.y,e.params.x);
+ });
+ controller.map.addEventListener(MapEvent.SCALE,changeZoom);
+ addEventListener(ResizeEvent.RESIZE,function(e:ResizeEvent):void { updateSize(); });
+ ArrayCollection(imageryMenu.dataProvider).refresh();
+ });
+ imagery.addEventListener('refreshAttribution',function(e:Event):void {
+ if (visible) {
+ map.tileset.setLogo(); map.tileset.setAttribution(); map.tileset.setTerms();
+ }
+ });
+
+ // Initialise map and tileset
+ map.init(controller.map.centre_lat || 51,
+ controller.map.centre_lon || 0.1,
+ controller.map.scale || 16);
+ }
+
+ protected function itemClickHandler(event:MenuEvent):void {
+ map.tileset.setBackgroundFromImagery(event.item,false);
+ imageryMenu.label=event.item.name;
+ maxZoom=(event.item.extent && event.item.extent.max_zoom) ? event.item.extent.max_zoom : 50;
+ map.changeScale(Math.min(controller.map.scale,maxZoom));
+ }
+
+ public function setFloatingMapVisible(v:Boolean):void {
+ visible=v;
+ if (v) {
+ map.updateCoordsFromLatLon(controller.map.centre_lat,controller.map.centre_lon);
+ if (!zoomLocked) map.changeScale(Math.min(controller.map.scale,maxZoom));
+ map.tileset.update();
+ map.tileset.setLogo(); map.tileset.setAttribution(); map.tileset.setTerms();
+ }
+ }
+
+ public function setLockZoom(v:Boolean):void {
+ zoomLocked=v;
+ if (!v && map.scale!=controller.map.scale) map.changeScale(Math.min(controller.map.scale,maxZoom));
+ }
+
+ public function changeZoom(e:MapEvent):void {
+ if (zoomLocked || !visible) return;
+ map.changeScale(Math.min(e.params.scale,maxZoom));
+ }
+
+ public function updateSize():void {
+ map.updateSize(width-2,height-34);
+ crosshair.x=(width-2)/2; crosshair.y=(height-34)/2;
+ map.tileset.setLogo(); map.tileset.setAttribution(); map.tileset.setTerms();
+ }
+
+ ]]>
+ </fx:Script>
+</s:TitleWindow>