Been meaning to post this for a while now. Here's a version of Andrew Spaulding's resizable TitleWindow with quite a few enhancements. You'll need to get the buttons.swf and wedge.png resources from the download at www.flexdaddy.info. Also, create your own arrow*.* drag cursor images yourself, which should be easy enough to do.
Here's the updated code, along with supporting mxml and a sample app. Feel free to use and/or modify as you see fit. And if you make any useful enahncements to it, please post! :) - Doug PopupWindow.as: -------------------------- /*------------------------------------------------------------------- ----------------- RESIZABLE AND COLLAPSABLE TitleWindow (6/3/05 Andrew Spaulding) - Original Updated by Doug Lowder, 2/27/2006 Ported from - Manish Jethani's ResizableTitleWindow http://manish.revise.org/archives/2005/01/09/resizable-titlewindow- in-flex/ Jesse Warden's CollapsablePanel mixin. http://dev.jessewarden.com/flex/collapsablepanel/ Other concepts taken from Christophe Coenraets Pod implementation. http://www.coenraets.com/viewarticle.jsp?articleId=89 This Class is a mixture of all the above implementations. Unlike the Pod implementation this component will move the buttons to the right when other buttons are disabled. This is a quick fix and could be written much smarter. PLEASE NOTE - This is a work in progress. You may use and modify this code wherever you wish. Please check back at www.flexdaddy.info for any future updates on this component. TO DO - 1. Combine all assets into one .swf 2. Anything else that needs fixing :-p --------------------------------------------------------------------- ---------------*/ import mx.core.UIComponent; import mx.containers.TitleWindow; import mx.controls.SimpleButton; import mx.controls.Image; import mx.effects.Resize; import mx.managers.CursorManager; import mx.managers.DepthManager; import mx.utils.Delegate; import fast.echo.Echo; [Event("WND_CREATE")] [Event("WND_CLOSE")] [Event("WND_EDIT")] [Event("WND_MAXIMIZE")] [Event("WND_MINIMIZE")] [Event("WND_FOCUS")] [Event("WND_RESIZE_START")] [Event("WND_RESIZE")] [Event("WND_RESIZE_END")] [Event("WND_BLUR")] [Event("WND_MOVE")] class PopupWindow extends TitleWindow { // Skins [Embed("/WEB- INF/flex/user_classes/info/flexdaddy/utils/buttons.swf#minibutton_dow n")] var buttonDownSkin:String; [Embed("/WEB- INF/flex/user_classes/info/flexdaddy/utils/buttons.swf#minibutton_ove r")] var buttonOverSkin:String; [Embed("/WEB- INF/flex/user_classes/info/flexdaddy/utils/buttons.swf#minibutton_emp ty")] var buttonEmptySkin:String; [Embed("/WEB- INF/flex/user_classes/info/flexdaddy/utils/arrowDiag2.gif")] var diagonalResizeSkinRight : String; [Embed("/WEB- INF/flex/user_classes/info/flexdaddy/utils/arrowDiag1.gif")] var diagonalResizeSkinLeft : String; [Embed("/WEB- INF/flex/user_classes/info/flexdaddy/utils/arrowLeftRight.gif")] var horizontalResizeSkin : String; [Embed("/WEB- INF/flex/user_classes/info/flexdaddy/utils/arrowUpDown.gif")] var verticalResizeSkin : String; [Embed("/WEB- INF/flex/user_classes/info/flexdaddy/utils/wedge.png")] var resizeHandleSkin : String; // Icons [Embed("/WEB- INF/flex/user_classes/info/flexdaddy/utils/buttons.swf#edit_icon")] var buttonEditIcon:String; [Embed("/WEB- INF/flex/user_classes/info/flexdaddy/utils/buttons.swf#down_icon")] var buttonUpIcon:String; [Embed("/WEB- INF/flex/user_classes/info/flexdaddy/utils/buttons.swf#up_icon")] var buttonDownIcon:String; // Cursor vars var cursorId : Number = null; var isHandleDragging : Boolean = false; var handleEdge : Number = EDGE_NONE; // Constants for window edges (see 'handleEdge') static var EDGE_NONE : Number = 0; static var EDGE_RIGHT : Number = 1; static var EDGE_LEFT : Number = 2; static var EDGE_TOP : Number = 3; static var EDGE_BOTTOM : Number = 4; static var EDGE_TOP_RIGHT : Number = 5; static var EDGE_TOP_LEFT : Number = 6; static var EDGE_BOTTOM_RIGHT : Number = 7; static var EDGE_BOTTOM_LEFT : Number = 8; // Define which buttons are available in the PopupWindow header // var closeButton inherited from TitleWindow var editButton : Boolean = false; var stateButton : Boolean = false; // Opacity of window when being moved by the user var dragAlpha : Number = 100; // Effect to play when window is created // Currently supports "Zoom", "Fade", "Dissolve", and "none" var popupEffect : String = "Zoom"; // Original window title var windowTitle:String; // Header Buttons private var sbEdit : SimpleButton; private var sbStateUp : SimpleButton; private var sbStateDown : SimpleButton; private var numButtons : Number; private var buttonWidth : Number = 14; private var buttonHeight : Number = 14; private var buttonGap : Number = 4; // Header button offsets for manipulation by parent public var buttonXOffset: Number = 0; public var buttonYOffset: Number = 0; private var iResize : Image; private var resizeEffect = null; private var effectInProgress: Boolean = false; private var eventHandlerDelegate : Function; // The current state of the window (minimized/maximized) private var __state : Number = 1; //0=Minimized 1=Maximized // Used to store the window height for restoration from a minimize private var originalWindowHeight : Number; // Used to store original values when resizing window private var originalWidth : Number; private var originalHeight : Number; private var originalX : Number; private var originalY : Number; private var originalMouseDownX : Number; private var originalMouseDownY : Number; private var originalAlpha : Number; private var headerHeight : Number = 28; private var isCreated = false; private var componentsFinalized = false; // Change the size of the window function set state( _state ) { if (!effectInProgress) { effectInProgress = true; __state = _state; var isMinimized = (_state == 0); iResize.visible = !isMinimized; hScrollPolicy = vScrollPolicy = "off"; resizeEffect = new Resize(this); resizeEffect.duration = 400; resizeEffect.suspendBackgroundProcessing = true; resizeEffect.hideChildren = [this]; resizeEffect.listener = this; if (isMinimized) { //Minimized originalWindowHeight = height; resizeEffect.heightTo = headerHeight + 3; this.toolTip = windowTitle; sbStateDown.visible = false; sbStateUp.visible = true; } else { resizeEffect.heightTo = originalWindowHeight-1; this.toolTip = null; sbStateUp.visible = false; sbStateDown.visible = true; } resizeEffect.playEffect(); dispatchEvent({type: (isMinimized? "WND_MINIMIZE" : "WND_MAXIMIZE"), target: this}); } } // Return the value of __state function get state() : Number { return __state; } public function onEffectEnd(event: Object) : Void { doLater(this, "doEndResizeEffect", []); } public function doEndResizeEffect() : Void { effectInProgress = false; if (__state == 1) { hScrollPolicy = vScrollPolicy = "auto"; // alter the size to reset scrollbars setSize(width, height+1); } } // Init method. Be sure to call super.init() function init():Void { super.init(); setStyle("creationCompleteEffect", popupEffect); if (popupEffect == "Zoom") creationPolicy = "none"; componentsFinalized = (creationPolicy != "none"); setVisible(componentsFinalized); eventHandlerDelegate = Delegate.create(this, eventHandler); addEventListener("creationComplete", eventHandlerDelegate); } // Create the components that are children of this Container. function createChildren() : Void { super.createChildren(); windowTitle = title; //Add the controls to the header bar var initObj = { falseUpSkin : buttonEmptySkin, falseOverSkin : buttonOverSkin, falseDownSkin : buttonDownSkin, falseDisabledSkin : buttonEmptySkin, falseUpIcon : null, falseOverIcon : null, falseDownIcon : null, btnOffset : 0 }; initObj.falseUpIcon = initObj.falseOverIcon = initObj.falseDownIcon = buttonEditIcon; SimpleButton(createClassObject(SimpleButton, "sbEdit", 20200, initObj)); sbEdit.addEventListener("click", Delegate.create(this, handleEditButton)); sbEdit.toolTip = "Edit"; initObj.falseUpIcon = initObj.falseOverIcon = initObj.falseDownIcon = buttonUpIcon; SimpleButton(createClassObject(SimpleButton, "sbStateUp", 20201, initObj)); sbStateUp.addEventListener("click", Delegate.create(this, handleStateUpButton)); sbStateUp.toolTip = "Restore"; initObj.falseUpIcon = initObj.falseOverIcon = initObj.falseDownIcon = buttonDownIcon; SimpleButton(createClassObject(SimpleButton, "sbStateDown", 20202, initObj)); sbStateDown.addEventListener("click", Delegate.create(this, handleStateDownButton)); sbStateDown.toolTip = "Minimize"; initObj = { source: resizeHandleSkin, toolTip: "Click and drag to resize this window", alpha: 30 }; Image(createClassObject(Image, "iResize", 20203, initObj)); originalAlpha = alpha; headerHeight = getStyle("headerHeight"); } // Respond to size changes by setting the positions and sizes of this container's children function layoutChildren() : Void { super.layoutChildren(); var bIncr:Boolean = false; if (closeButton && stateButton && editButton) { numButtons = 3; bIncr = true; } else if (closeButton && (stateButton ^ editButton)) { numButtons = 2; } else if (!closeButton && (stateButton && editButton)) { numButtons = 2; bIncr = true; } else if (!closeButton && (stateButton ^ editButton)) { numButtons = 1; } else { numButtons = 0; } moveButtons(numButtons, bIncr); setTitleString(); } // Move the buttons into position function moveButtons(increment, increaseX) { var vm = border_mc.borderMetrics; var increment; var x = layoutWidth - vm.right - (buttonWidth + buttonGap) * increment + buttonXOffset; var y = Math.round((headerHeight - buttonHeight) / 2) + vm.top + buttonYOffset; sbEdit.move(x, y); if (increaseX) { x += buttonWidth + buttonGap; } sbStateUp.move(x, y); sbStateDown.move(x, y); sbEdit.visible = editButton; sbStateUp.visible = stateButton && state == 0; sbStateDown.visible = stateButton && state == 1; iResize.move(layoutWidth - vm.right - 15, layoutHeight + vm.top - 19); } // Edit Button - click function handleEditButton() { dispatchEvent({type: "WND_EDIT", target: this}); } // State Up - click function handleStateUpButton() { state = 1; } // State Down - click function handleStateDownButton() { state = 0; } // Event Handler function eventHandler(event) : Void { switch (event.type) { case "click": dispatchEvent({type: "WND_CLOSE", target: event.target}); break; case "creationComplete": isCreated = true; alpha = originalAlpha; addEventListener("mouseUp", eventHandlerDelegate); addEventListener("mouseDown", eventHandlerDelegate); addEventListener("mouseMove", eventHandlerDelegate); addEventListener("click", eventHandlerDelegate); addEventListener("move", eventHandlerDelegate); addEventListener("focusOut", eventHandlerDelegate); addEventListener("mouseDownOutside", eventHandlerDelegate); addEventListener("effectStart", eventHandlerDelegate); addEventListener("effectEnd", eventHandlerDelegate); dispatchEvent({type: "WND_CREATE", target: event.target}); break; case "focusOut": case "mouseDownOutside": dispatchEvent({type: "WND_BLUR", target: event.target}); break; case "move": if (!isHandleDragging && componentsFinalized) { alpha = dragAlpha; } dispatchEvent({type: "WND_MOVE", target: event.target, oldX: event.oldX, oldY: event.oldY}); break; case "mouseUp": alpha = originalAlpha; if (handleEdge != EDGE_NONE) hideResizeHandle(); onMouseUp(event); break; case "mouseDown": onMouseDown(event); break; case "mouseMove": onMouseMove(event); break; case "effectStart": setVisible(true); break; case "effectEnd": doLater(this, "finalizeComponents", []); break; } } function finalizeComponents() { if (!componentsFinalized) { componentsFinalized = true; createComponents(); layoutChildren(); // Fix for bug Flex 1.5 where titlebar elements aren't shown at // their proper locations after a Zoom effect; just call the // chrome layout function an ample number of times to reset them. // This could stand some improvements. for (var i = 0; i < 8; i++) layoutChrome(); } } // Mouse Up Handler function onMouseUp(event) : Void { if (isHandleDragging) { isHandleDragging = false; hideResizeHandle(); dispatchEvent({type: "WND_RESIZE_END", target: this}); } } // Mouse Down Handler function onMouseDown(event) : Void { if (event.target == this) { if (cursorId != null && handleEdge != EDGE_NONE) { isHandleDragging = true; originalX = x; originalY = y; originalWidth = layoutWidth; originalHeight = layoutHeight; originalMouseDownX = parentApplication.mouseX; originalMouseDownY = parentApplication.mouseY; dispatchEvent({type: "WND_RESIZE_START", target: this}); } dispatchEvent({type: "WND_FOCUS", target: this}); } } // Mouse Move Handler function onMouseMove(event) : Void { if (isHandleDragging) { if (event.target != this && handleEdge != EDGE_NONE) { var newWidth = layoutWidth, newHeight = layoutHeight; var minWidth = 100, minHeight = 52; var xOffset: Number = parentApplication.mouseX - originalMouseDownX; var yOffset: Number = parentApplication.mouseY - originalMouseDownY; switch (handleEdge) { case EDGE_BOTTOM_RIGHT: newHeight = Math.max(originalHeight + yOffset, minHeight); case EDGE_RIGHT: newWidth = Math.max(originalWidth + xOffset, minWidth); break; case EDGE_BOTTOM_LEFT: newHeight = Math.max(originalHeight + yOffset, minHeight); case EDGE_LEFT: x = Math.min(originalX + xOffset, originalX + originalWidth - minWidth); newWidth = Math.max(originalWidth - xOffset, minWidth); break; case EDGE_BOTTOM: newHeight = Math.max(originalHeight + yOffset, minHeight); break; case EDGE_TOP_LEFT: x = Math.min(originalX + xOffset, originalX + originalWidth - minWidth); case EDGE_TOP_RIGHT: newWidth = Math.max(originalWidth + (handleEdge == EDGE_TOP_LEFT? -xOffset : xOffset), minWidth); case EDGE_TOP: y = Math.min(originalY + yOffset, originalY + originalHeight - minHeight); newHeight = Math.max(originalHeight - yOffset, minHeight); break; } setSize(newWidth, newHeight); dispatchEvent({type: "WND_RESIZE", target: this}); } } else { if (event.target == this && state == 1) { if (isMouseBottomRight()) { showResizeHandle(EDGE_BOTTOM_RIGHT); } else if (isMouseBottomLeft()) { showResizeHandle(EDGE_BOTTOM_LEFT); } else if (isMouseTopRight()) { showResizeHandle(EDGE_TOP_RIGHT); } else if (isMouseTopLeft()) { showResizeHandle(EDGE_TOP_LEFT); } else if (isMouseOnRightEdge()) { showResizeHandle(EDGE_RIGHT); } else if (isMouseOnLeftEdge()) { showResizeHandle(EDGE_LEFT); } else if (isMouseOnBottomEdge()) { showResizeHandle(EDGE_BOTTOM); } else if (isMouseOnTopEdge()) { showResizeHandle(EDGE_TOP); } } else { hideResizeHandle(); } } } // Reset the window title text to fit within the available width function setTitleString() : Void { var availableWidth:Number = width - 20 - Math.max(0, (numButtons * buttonWidth + (numButtons-1) * buttonGap)); var tf = new TextFormat(); tf.font = "Verdana"; tf.size = 10; tf.bold = true; var newTitle:String = windowTitle; if (tf.getTextExtent(newTitle).width > availableWidth) { while (newTitle.length > 0 && tf.getTextExtent(newTitle + "...").width > availableWidth) { newTitle = newTitle.substring(0, newTitle.length-1); } newTitle += "..."; } if (title != newTitle) { title = newTitle; } } // Check whether the mouse is at the left edge function isMouseOnLeftEdge() : Boolean { return mouseX > (-buttonWidth/2) && mouseX <= buttonWidth/2 && mouseY > (headerHeight + border_mc.borderMetrics.top) && mouseY <= layoutHeight; } // Check whether the mouse is at the right edge function isMouseOnRightEdge() : Boolean { var x1: Number = mouseX - layoutWidth; return x1 < buttonWidth/2 && x1 >= (-buttonWidth/2) && mouseY > (headerHeight + border_mc.borderMetrics.top) && mouseY <= layoutHeight; } // Check whether the mouse is at the top edge function isMouseOnTopEdge() : Boolean { // strict mouseY for top edge to differentiate from window move event return mouseY == 0 && mouseX >= 0 && mouseX <= layoutWidth; } // Check whether the mouse is at the bottom edge function isMouseOnBottomEdge() : Boolean { var y1: Number = mouseY - layoutHeight; return y1 < buttonWidth/2 && y1 >= (-buttonWidth/2) && mouseX >= 0 && mouseX <= layoutWidth; } // Check whether the mouse is at the top left corner function isMouseTopLeft() : Boolean { return isMouseOnTopEdge() && mouseX < buttonWidth/2; } // Check whether the mouse is at the top right corner function isMouseTopRight() : Boolean { return isMouseOnTopEdge() && mouseX >= layoutWidth - buttonWidth/2; } // Check whether the mouse is at the bottom right corner function isMouseBottomRight() : Boolean { return isMouseWithin(mouseX - layoutWidth, mouseY - layoutHeight); } // Check whether the mouse is at the bottom left corner function isMouseBottomLeft() : Boolean { return isMouseWithin(mouseX, mouseY - layoutHeight); } // Check whether the mouse is near a specific point function isMouseWithin(x : Number, y : Number) : Boolean { var range : Number = buttonWidth; // Number of pixels to extend cursor hotspot return x < range && x >= (-range) && y < range && y >= (- range); } // Show the resize cursor function showResizeHandle(edgePos:Number) : Void { if (handleEdge != edgePos && isCreated) { handleEdge = edgePos; if (cursorId == null) { var edgeSkin; switch (handleEdge) { case EDGE_LEFT: case EDGE_RIGHT: edgeSkin = horizontalResizeSkin; break; case EDGE_TOP: case EDGE_BOTTOM: edgeSkin = verticalResizeSkin; break; case EDGE_TOP_LEFT: case EDGE_BOTTOM_RIGHT: edgeSkin = diagonalResizeSkinRight; break; case EDGE_TOP_RIGHT: case EDGE_BOTTOM_LEFT: edgeSkin = diagonalResizeSkinLeft; break; } cursorId = setCursor(edgeSkin); } } } // Call the Cursor Manager to set the resize cursor function setCursor(cursorSkin:String) : Number { return CursorManager.setCursor(cursorSkin, CursorManager.HIGHPRIORITY, -10, -10); } // Hide the resize cursor function hideResizeHandle():Void { if (cursorId != null) { removeCursor(cursorId); } handleEdge = EDGE_NONE; } // Remove the cursor function removeCursor(id:Number):Void { CursorManager.removeCursor(id); cursorId = null; } } // Class PopupWindow MyPopup.mxml (defines the contents of a popup window for the sample) --------------------------------- <?xml version="1.0" encoding="utf-8"?> <PopupWindow xmlns:mx="http://www.macromedia.com/2003/mxml" xmlns="*"> <mx:Label text="The contents of your popup window would be defined here (MyPopup.mxml)"/> </PopupWindow> App.mxml (sample app and bare-bones window manager) ---------------------------------- <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml" pageTitle="Resizable Title Window Example" marginTop="0" marginBottom="0" marginLeft="0" marginRight="0" verticalGap="0" horizontalGap="0" verticalAlign="top" horizontalAlign="left" initialize="initApp()"> <mx:Script> <![CDATA[ var eventHandlerDelegate: Function; var xOrigin: Number = 50; var yOrigin: Number = 75; function initApp() : Void { // Application initialization eventHandlerDelegate = mx.utils.Delegate.create(this, eventHandler); } function showPopupWindow() : MovieClip { var initObj:Object = { title: titleInput.text, editButton: true, stateButton: true, closeButton: true, cornerRadius: 2, panelBorderStyle: "roundCorners", alpha: 90, dragAlpha: 40, buttonXOffset: 2, buttonYOffset: 0, width: 480, height: 250, x: xOrigin, y: yOrigin }; var popup: MovieClip = mx.managers.PopUpManager.createPopUp(this, MyPopup, false, initObj, false); // Add the CREATE event listener. Other listeners get added after creation. popup.addEventListener("WND_CREATE", eventHandlerDelegate); xOrigin += 30; if (xOrigin > (width - popup.width)) { xOrigin = 50; } yOrigin += 30; if (yOrigin > (height - popup.height)) { yOrigin = 75; } return popup; } function eventHandler(event:Object) : Void { switch (event.type) { case "WND_CREATE": onPopUpCreated(event); break; case "WND_CLOSE": onPopUpClosed(event); break; // Other events the popup window might send case "WND_FOCUS": event.target.setDepthTo (mx.managers.DepthManager.kTop); break; case "WND_BLUR": case "WND_RESIZE_END": case "WND_MOVE": case "WND_MINIMIZE": case "WND_MAXIMIZE": break; } } function onPopUpCreated(event:Object) : Void { // Now that the window has been created, we can register for other events. event.target.addEventListener("WND_CLOSE", eventHandlerDelegate); event.target.addEventListener("WND_FOCUS", eventHandlerDelegate); } function onPopUpClosed(event:Object) : Void { event.target.deletePopUp(); } ]]> </mx:Script> <mx:HBox width="100%" height="80" horizontalAlign="center" verticalAlign="middle"> <mx:Label text="Title of new window:" /> <mx:TextInput id="titleInput" text="Window Name" /> <mx:Button label="Open the window!" click="showPopupWindow ()" /> </mx:HBox> </mx:Application> --- In [email protected], "jgraham_us" <[EMAIL PROTECTED]> wrote: > > Check here. I don't think it's complete, but you might be able to > finish it with a little work. > > http://www.flexdaddy.info/2005/03/06/resizable-and-collapsable- > titlewindow-flex-15/ > > > > --- In [email protected], "sigges25" <sascha.sigges@> > wrote: > > > > Hi! > > > > Does anybody know how to add a size-grip to Title-Windows? > > I want the user to be able to resize a window like in other > > windowing-systems. > > > > > > Regards > > Sascha Sigges > > > -- Flexcoders Mailing List FAQ: http://groups.yahoo.com/group/flexcoders/files/flexcodersFAQ.txt Search Archives: http://www.mail-archive.com/flexcoders%40yahoogroups.com Yahoo! Groups Links <*> To visit your group on the web, go to: http://groups.yahoo.com/group/flexcoders/ <*> To unsubscribe from this group, send an email to: [EMAIL PROTECTED] <*> Your use of Yahoo! Groups is subject to: http://docs.yahoo.com/info/terms/

