Le composant AIRResizePanel est un composant dérivé du composant Panel. Il hérite donc des propriétés et méthodes publiques de celui-ci. De plus, il permet les fonctions suivantes :

  • Redimensionnement du Panel grâce au coin inférieur droit.
  • Gestion d'une taille minimum et maximum pour le Panel en mode non-agrandi.
  • Gestion des boutons du Panel. 4 boutons au choix : réduire dans la Systray, réduire dans la barre des tâches, agrandir, et fermer
  • Agrandissement du Panel sur double-clic sur la barre de titre
  • Possibilité de rendre le Panel non-fermable et non-redimensionnable
  • Les actions sont gérées en dehors du composant. On peut donc tester un truc avant de fermer par exemple

Le composant se décompose en 2 classes :

  • la classe principale AIRResizePanel.as
  • la classe AIRMenuIcon.as (celle d'Adobe en fait...)

Voici le code :

la classe principale AIRResizePanel.as

package com.phiphou.application
{
 
import flash.display.NativeMenu;
import flash.display.NativeMenuItem;
import flash.display.SystemTrayIcon;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.system.Capabilities;
import flash.system.Shell;
	
import mx.containers.Panel;
import mx.controls.Button;
import mx.core.Application;
import mx.events.FlexEvent;
import mx.events.MoveEvent;
import mx.managers.CursorManager;
import mx.managers.CursorManagerPriority;
import mx.styles.StyleManager;
 
 
[Event(name="closePanel", type="mx.events.FlexEvent")]
[Event(name="minimizePanel", type="mx.events.FlexEvent")]
[Event(name="maximizePanel", type="mx.events.FlexEvent")]
[Event(name="sendToSysTray", type="mx.events.FlexEvent")]
[Event(name="restoreFromSysTray", type="mx.events.FlexEvent")]
[Event(name="resizing", type="mx.events.FlexEvent")]
[Event(name="moving", type="mx.events.FlexEvent")]
		
	
public class AIRResizePanel extends Panel{
		
	[Embed(source="/assets/ResizeCursor.gif")]
	public static const LEFT_OBLIQUE_SIZE:Class;
		
	[Embed(source="/assets/CloseButton.gif")]
	public static const CLOSE_BUTTON:Class;
	[Embed(source="/assets/CloseButtonOver.gif")]
	public static const CLOSE_BUTTON_OVER:Class;
		
	[Embed(source="/assets/MinimizeButton.gif")]
	public static const MINIMIZE_BUTTON:Class;
	[Embed(source="/assets/MinimizeButtonOver.gif")]
	public static const MINIMIZE_BUTTON_OVER:Class;
		
	[Embed(source="/assets/SysTrayButton.gif")]
	public static const SYSTRAY_BUTTON:Class;
	[Embed(source="/assets/SysTrayButtonOver.gif")]
	public static const SYSTRAY_BUTTON_OVER:Class;
		
	[Embed(source="/assets/MaximizeButton.gif")]
	public static const MAXIMIZE_BUTTON:Class;
	[Embed(source="/assets/MaximizeButtonOver.gif")]
	public static const MAXIMIZE_BUTTON_OVER:Class;
 
	private var resizeObj:Object;
	private var dragEnabled:Boolean = false;
	private var mouseMargin:Number = 10;
 
        private var panelCloseButton:Button;
	private var panelMinButton:Button;
	private var panelMaxButton:Button;
	private var panelSysTrayButton:Button;
		
	private var pPoint:Point = new Point();
		
	public var maximized:Boolean = false;
		
	public var popPos:Point;
	public var popSize:Point = new Point();
	public var MaxSize:Point;
	public var MinSize:Point;
		
	private var _showPanelButtons:Array;	
		
	public var closable:Boolean = true;
	public var resizable:Boolean = true;
	public var isResizing:Boolean = false;
		
	public var SysTrayIcon:Array = new AIRMenuIcon().bitmaps;
		
		
	public function AIRResizePanel(){
			
		super();
		initPosition(this);
			
		this.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
		this.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
		this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
		Application.application.parent.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
		Application.application.parent.addEventListener(MouseEvent.MOUSE_MOVE, onResize);
		this.addEventListener(MouseEvent.DOUBLE_CLICK,DoubleClickMaximize);
	}
		
		
		
		
	public function setup(center:Boolean,maxSize:Point,minSize:Point,initSize:Point,showButtons:Array,doubleclickEnabled:Boolean):void{
			
		MinSize = minSize;
		MaxSize = maxSize;
		popSize = initSize;
			
		this.width = popSize.x;
		this.height = popSize.y;
			
		if(center){
			this.x = (Capabilities.screenResolutionX/2)-(this.width/2);
			this.y = (Capabilities.screenResolutionY/2)-(this.height/2);
		}
			
		if(showButtons != null)showPanelButtons = showButtons;
			
		if(doubleclickEnabled)this.doubleClickEnabled = true;
			
		}
		
	private function initPosition(obj:Object):void{
			
		popSize.x = obj.width;
		popSize.y = obj.height;
			
	}
		
		
	private function onMouseDown(event:MouseEvent):void{
		if(dragEnabled){
			resizeObj = event.currentTarget;
			initPosition(resizeObj);
			pPoint.x = resizeObj.mouseX;
			pPoint.y = resizeObj.mouseY;
			pPoint = this.localToGlobal(pPoint);
			isResizing = true;
		} else {
			dispatchEvent(new FlexEvent("moving"));
		}
	}
		
		
	private function onMouseUp(event:MouseEvent):void{
		if(resizeObj != null){
			initPosition(resizeObj);
				
		}
		resizeObj = null;
		isResizing = false;
	}
		
		
	private function onMouseMove(event:MouseEvent):void{
		if(resizeObj == null && resizable){
			var xPosition:Number = Application.application.parent.mouseX;
			var yPosition:Number = Application.application.parent.mouseY;
			if(xPosition >= (this.x + this.width - mouseMargin) && yPosition >= (this.y + this.height - mouseMargin)){
				
                                CursorManager.setCursor(LEFT_OBLIQUE_SIZE, CursorManagerPriority.MEDIUM, -6, -6);
				dragEnabled =  true;
			}else{
					
				dragEnabled =  false;
				CursorManager.removeAllCursors();
			}
		}
	}
		
		
	private function onMouseOut(event:MouseEvent):void{
		
                if(resizeObj == null){
			CursorManager.removeAllCursors();
		}
	}
		
		
	private function onResize(event:MouseEvent):void{
		
                  if(resizeObj != null){
					
			resizeObj.stopDragging();
				
			dispatchEvent(new FlexEvent("resizing"));
				
			var xPlus:Number = Application.application.parent.mouseX - resizeObj.pPoint.x;
			var yPlus:Number = Application.application.parent.mouseY - resizeObj.pPoint.y;
			
                        if(dragEnabled){
			    	
			    	if(popSize.x + xPlus < MinSize.x){
			    		resizeObj.width = MinSize.x;
			    	} else if(popSize.x + xPlus > MaxSize.x){
			    		resizeObj.width = MaxSize.x;
			    	} else {
			    		resizeObj.width = popSize.x + xPlus;
			    	}
			    		
			    	if(popSize.y + yPlus < MinSize.y){
			    		resizeObj.height = MinSize.y;
			    	} else if(popSize.y + yPlus > MaxSize.y){
			    		resizeObj.height = MaxSize.y;
			    	} else {
			    		resizeObj.height = popSize.y + yPlus;
			    	}
			    		
			}
		}
	}
		
		
	public function set showPanelButtons(show:Array):void{
		_showPanelButtons = show;
		if(titleBar != null){
			addButton(new FlexEvent(""));
		}
	}
			
	public function get showPanelButtons():Array{
			return _showPanelButtons;
	}
		
		
			
	private function addButton(event:FlexEvent):void{
		if(_showPanelButtons != null){
				
			if(panelMinButton == null && _showPanelButtons[0]){
				panelMinButton = new Button();
				panelMinButton.width=10;
				panelMinButton.height=10;
				panelMinButton.focusEnabled=false;
				panelMinButton.setStyle("upSkin", MINIMIZE_BUTTON);
				panelMinButton.setStyle("overSkin", MINIMIZE_BUTTON_OVER);
				panelMinButton.setStyle("downSkin", MINIMIZE_BUTTON_OVER);
				panelMinButton.addEventListener(MouseEvent.CLICK, panelMinButton_clickHandler);
				titleBar.addChild(panelMinButton);
			}
 
			if(panelMaxButton == null && _showPanelButtons[1]){
				panelMaxButton = new Button();
				panelMaxButton.width=10;
				panelMaxButton.height=10;
				panelMaxButton.focusEnabled=false;
				panelMaxButton.setStyle("upSkin", MAXIMIZE_BUTTON);
				panelMaxButton.setStyle("overSkin", MAXIMIZE_BUTTON_OVER);
				panelMaxButton.setStyle("downSkin", MAXIMIZE_BUTTON_OVER);
				panelMaxButton.addEventListener(MouseEvent.CLICK, panelMaxButton_clickHandler);
				titleBar.addChild(panelMaxButton);
			}
				
			if(panelCloseButton == null && _showPanelButtons[2]){
				panelCloseButton = new Button();
				panelCloseButton.width=10;
				panelCloseButton.height=10;
				panelCloseButton.focusEnabled=false;
				panelCloseButton.setStyle("upSkin", CLOSE_BUTTON);
				panelCloseButton.setStyle("overSkin", CLOSE_BUTTON_OVER);
				panelCloseButton.setStyle("downSkin", CLOSE_BUTTON_OVER);
				panelCloseButton.addEventListener(MouseEvent.CLICK, panelCloseButton_clickHandler);
				titleBar.addChild(panelCloseButton);
					
			} 
				
			if(panelSysTrayButton == null && _showPanelButtons[3]){
				panelSysTrayButton = new Button();
				panelSysTrayButton.width=10;
				panelSysTrayButton.height=10;
				panelSysTrayButton.focusEnabled=false;
				panelSysTrayButton.setStyle("upSkin", SYSTRAY_BUTTON);
				panelSysTrayButton.setStyle("overSkin", SYSTRAY_BUTTON_OVER);
				panelSysTrayButton.setStyle("downSkin", SYSTRAY_BUTTON_OVER);
				panelSysTrayButton.addEventListener(MouseEvent.CLICK, panelSysTrayButton_clickHandler);
				titleBar.addChild(panelSysTrayButton);
					
				} 
 
		layoutPanelButtons();
		
                }else{	
			   titleBar.removeChild(panelCloseButton);
			   panelCloseButton = null;	
		}
	}
			
	private function panelCloseButton_clickHandler(event:MouseEvent):void{
		if(closable){
			dispatchEvent(new FlexEvent("closePanel"));
		}
	}
		
	private function panelMinButton_clickHandler(event:MouseEvent):void{
		dispatchEvent(new FlexEvent("minimizePanel"));
	}
		
	private function panelMaxButton_clickHandler(event:MouseEvent):void{
		dispatchEvent(new FlexEvent("maximizePanel"));
	}
		
	private function panelSysTrayButton_clickHandler(event:MouseEvent):void{
		dispatchEvent(new FlexEvent("sendToSysTray"));
	}
			
	private function layoutPanelButtons():void{
				
		if(panelCloseButton != null){
			panelCloseButton.move(titleBar.width - 30, (titleBar.height - 10) / 2);
		}
		if(panelMinButton != null){
			panelMinButton.move(titleBar.width - 45 , (titleBar.height - 10) / 2);
		}
		if(panelMaxButton != null){
			panelMaxButton.move(titleBar.width - 60, (titleBar.height - 10) / 2);
		}
		if(panelSysTrayButton != null){
			panelSysTrayButton.move(titleBar.width - 75, (titleBar.height - 10) / 2);
		}
 
	}
		
		
	public function sendToSysTray():void{
		
		stage.nativeWindow.visible = false;
		Shell.shell.icon.bitmaps = SysTrayIcon;
		SystemTrayIcon(Shell.shell.icon).tooltip = "Phiphou_AIR_Test";
		SystemTrayIcon(Shell.shell.icon).addEventListener(MouseEvent.CLICK, onIconClick);
   		SystemTrayIcon(Shell.shell.icon).menu = createMenu();
   		
	}
		
	private function onIconClick(evt:MouseEvent):void{
		
		stage.nativeWindow.visible = true;
		Shell.shell.icon.bitmaps = [];
	}
		
 
	private function createMenu():NativeMenu{
	        var menu:NativeMenu = new NativeMenu();
		menu.addItem(new NativeMenuItem("New"));
		menu.addItem(new NativeMenuItem("Open"));
		menu.addItem(new NativeMenuItem("Save"));
		menu.addItem(new NativeMenuItem("",true));
		menu.addItem(new NativeMenuItem("Exit"));
		    
		for each (var item:NativeMenuItem in menu.items){
		      item.addEventListener(Event.SELECT,itemSelected);
		}
 
		return menu;
	}
		
	private function itemSelected(event:Event):void{
    		
    	        switch(event.target.label){
			    	
		        case "Exit" :
			    	dispatchEvent(new FlexEvent("closePanel"));
			break;
			    	
		}
	}
		
	public function maximize():void{
		if(maximized){
				
		StyleManager.getStyleDeclaration(".AIRResizePanel").setStyle("roundedBottomCorners",true);
                StyleManager.getStyleDeclaration(".AIRResizePanel").setStyle("cornerRadius","24");
		
			this.x = popPos.x;
			this.y = popPos.y;
			this.width = popSize.x;
			this.height = popSize.y;
			this.removeEventListener(MoveEvent.MOVE,noMoveHandler);
			this.maximized = false;	
			
			} else {
				
		StyleManager.getStyleDeclaration(".AIRResizePanel").setStyle("roundedBottomCorners",false);
            	StyleManager.getStyleDeclaration(".AIRResizePanel").setStyle("cornerRadius","0");
			
		popPos = new Point(this.x,this.y);
	        this.x = this.y = 0;
	        popSize = new Point(this.width,this.height);
	        this.width = Capabilities.screenResolutionX;
		this.height = Capabilities.screenResolutionY;
		this.addEventListener(MoveEvent.MOVE,noMoveHandler);
		this.maximized = true;	
	        }
				
	}
		
	private function DoubleClickMaximize(evt:MouseEvent):void{
		
		if(evt.localY < StyleManager.getStyleDeclaration(".AIRResizePanel").getStyle("headerHeight")){
		maximize();
		} 
	}
		
	private function noMoveHandler(event:MoveEvent):void{
		this.x = this.y = 0;
	}
		
	override protected function layoutChrome(unscaledWidth:Number, unscaledHeight:Number):void{
		super.layoutChrome(unscaledWidth, unscaledHeight);
		layoutPanelButtons();	
			
	}
}
 
}

la classe AIRMenuIcon

package com.phiphou.application
{
import flash.desktop.Icon;
      
public class AIRMenuIcon extends Icon
    {
        
        [Embed(source='assets/icons/logo128.png')]
        private var icon128:Class;
        
        [Embed(source='assets/icons/logo48.png')]
        private var icon48:Class;
        
        [Embed(source='assets/icons/logo32.png')]
        private var icon32:Class;       
 
        [Embed(source='assets/icons/logo16.png')]
        private var icon16:Class;           		
		
        public function AIRMenuIcon():void{
            var iconImages:Array = [(new icon16()).bitmapData];
            this.bitmaps = iconImages;
        }
    }
}

Et un exemple d'utilisation :

Le fichier principal main.mxml:

 
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*"
    usePreloader="false" creationComplete="initApp()"
    applicationComplete="appComplete()"
    layout="absolute" width="10" height="10"
    paddingRight="0" paddingLeft="0" >
    
<mx:Style source="assets/styles/messenger/messenger.css"/>
 
<mx:Script>
        <![CDATA[
 
import com.phiphou.application.*
import mx.events.*
import mx.managers.PopUpManager;
	
[Bindable]
public var pop:mainWindow;
	
public function appComplete():void{
		
	stage.nativeWindow.width = Capabilities.screenResolutionX;
	stage.nativeWindow.height = Capabilities.screenResolutionY;
	stage.nativeWindow.x = stage.nativeWindow.y = 0;
	
}
		
public function initApp():void{
	
pop = mainWindow(PopUpManager.createPopUp(this, mainWindow, false));		
	
pop.setup(true,new Point(600,500),new Point(300,200),new Point(470,370),[true,true,true,true],true);
	
pop.addEventListener("closePanel", onClose);
pop.addEventListener("minimizePanel", onMinimize);
pop.addEventListener("maximizePanel", onMaximize);
pop.addEventListener("sendToSysTray", onSendToSysTray);
	
}
	                       
private function onClose(event:FlexEvent):void{
                
        PopUpManager.removePopUp(AIRResizePanel(event.currentTarget));
	stage.nativeWindow.close();
		
}
  
private function onMinimize(evt:FlexEvent):void{
		
	stage.nativeWindow.minimize();
		
}
   
private function onMaximize(evt:FlexEvent):void{
            	
	pop.maximize();
		 
}	
	
private function onSendToSysTray(evt:FlexEvent):void{
		
	pop.sendToSysTray();
		
} 
 
	
   ]]>
</mx:Script>
</mx:Application>

Le fichier mainWindow.mxml qui contient le Panel :

 
<?xml version="1.0" encoding="utf-8"?>
<AIRResizePanel xmlns="com.phiphou.application.*" 
	xmlns:mx="http://www.adobe.com/2006/mxml"
	width="600" height="100%" layout="absolute" styleName="AIRResizePanel"
	verticalScrollPolicy="off" horizontalScrollPolicy="off">   
</AIRResizePanel>

Voilà. Je vais continuer à l'améliorer et je vous proposerai une nouvelle version dès que possible.