Adobe
Products
Acrobat
Creative Cloud
Creative Suite
Digital Marketing Suite
Digital Publishing Suite
Elements
Photoshop
Touch Apps
Student and Teacher Editions
More products
Solutions
Creative tools for business
Digital marketing
Digital media
Education
Financial services
Government
Web Experience Management
More solutions
Learning Help Downloads Company
Buy
Home use for personal and home office
Education for students, educators, and staff
Business for small and medium businesses
Licensing programs for businesses, schools, and government
Special offers
Search
 
Info Sign in
Welcome,
My cart
My orders My Adobe
My Adobe
My orders
My information
My preferences
My products and services
Sign out
Why sign in? Sign in to manage your account and access trial downloads, product extensions, community areas, and more.
Adobe
Products Sections Buy   Search  
Solutions Company
Help Learning
Sign in Sign out My orders My Adobe
Preorder Estimated Availability Date. Your credit card will not be charged until the product is shipped. Estimated availability date is subject to change. Preorder Estimated Availability Date. Your credit card will not be charged until the product is ready to download. Estimated availability date is subject to change.
Qty:
Purchase requires verification of academic eligibility
Subtotal
Review and Checkout
Adobe Developer Connection / Adobe AIR Developer Center / AIR Quick Starts for ActionScript developers /

Creating resizable, non-rectangular windows

by Joe Ward

Joe Ward

Modified

9 June 2010

Page tools

Share on Facebook
Share on Twitter
Share on LinkedIn
Bookmark
Print
Adobe AIR

Requirements

Prerequisite knowledge

General experience of building applications with Flex Builder is suggested. For more details on getting started with this Quick Start, refer to Building the Quick Start sample applications with Flex.

User level

Intermediate

Required products

  • Adobe AIR
  • Flash Builder (Download trial)

Sample files

  • !Square.zip
  • !Square.air

Rectangular windows are fine, and appropriate for most applications. However, just because they are the easiest to draw doesn't mean that all your windows have to be curve impoverished. The !Square sample application, shown in Figure 1, creates a window based on the ellipse, rather than the rectangle. The window uses vector graphics for most of its chrome, so there are no issues with bitmap scaling to limit the window size or aspect ratio.

The !Square sample application illustrates how to extend the NativeWindow class to create windows with alternative visuals and behavior using the Adobe AIR APIs and the rich Flash graphics capabilities.

The !Square sample application demonstrates how to create windows with alternative visuals.
Figure 1. The !Square sample application demonstrates how to create windows with alternative visuals.

Note: This is a sample application provided, as is, for instructional purposes.

Testing the application

Download and launch the !Square installer (!Square.air) file. Resize the window using any of the eight grippers along the window drag bar. Move the window using the drag bar. Drag the white disk to the edge of the window to observe that any part of the disk which is outside the window client area is properly clipped.

Understanding the code

The !Square application uses several graphics functions not specific to AIR. For more information about these functions, see the ActionScript 3 Reference for the Adobe Flash Platform.

Extending the NativeWindow class

The RoundWindow class extends the AIR NativeWindow class to specialize the constructor and to define the methods and properties to draw its window chrome. Because you cannot use a custom class for the initial application window, the !Square example uses the initial window primarily to launch an instance of the RoundWindow class to serve as the main application window. The initial window created by AIR is never made visible and is closed once initialization is complete.

The constructor of the RoundWindow class creates its own NativeWindowInitOptions object and uses it to create the underlying native window. The constructor then creates the window chrome elements and activates the window to make it visible and active.

public function RoundWindow(title:String=""){ var initOptions:NativeWindowInitOptions = new NativeWindowInitOptions(); initOptions.systemChrome = NativeWindowSystemChrome.NONE; initOptions.transparent = true; super(initOptions); this.minSize = new Point(350,350); bounds = new Rectangle(0,0,viewWidth,viewHeight); this.title = title; stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; stage.addChild(clippedStage); //Put buttons on conventional side of window if(isWindows()){ closeButton = new CloseButton(287); minRestoreButton = new MinRestoreButton(283.5); maxButton = new MaxButton(280); } else { closeButton = new CloseButton(252); minRestoreButton = new MinRestoreButton(255.5); maxButton = new MaxButton(259); } addWindowDressing(); addEventListener(NativeWindowBoundsEvent.RESIZE,onBoundsChange); draw(viewWidth,viewHeight); activate(); }

Drawing elliptical borders

The border of the window is drawn using standard Flash drawing functions provided by the Graphics class, which can be accessed through the graphics property of any display object. The border is composed of three rings. When you draw overlapping figures between the calls to beginFill() and endFill(), only the difference between the figures, in this case ellipses, are filled. The following function draws the three rings by drawing two ellipses for each ring:

with(border.graphics){ clear(); beginFill(bevelColor,1); drawEllipse(0,0,viewWidth,viewHeight); drawEllipse(4,4,viewWidth-8,viewHeight-8); endFill(); beginFill(borderColor,1); drawEllipse(4,4,viewWidth-8,viewHeight-8); drawEllipse(16,16,viewWidth-32,viewHeight-32); endFill(); beginFill(bevelColor,1); drawEllipse(16,16,viewWidth-32,viewHeight-32); drawEllipse(20,20,viewWidth-40,viewHeight-40); endFill(); }

Drawing a section of an ellipse

Because the Graphics class does not have a function for drawing just a piece of an elliptical arc, drawing the resizing gripper onto the border is more challenging than drawing the border itself. You could use the curveTo() method, but calculating the proper control point locations to match the elliptical border has its own mathematical challenges. For this task, !Square uses a simpler polyline technique based on the parametric equation of the ellipse. A point on the border is calculated based on the height and width and angle from the midpoint of the ellipse. Then the next point is calculated by increasing the angle a small amount and a line is drawn between them. This process is repeated until the desired arc is drawn.

Figure 2 shows the formula that can be used to calculate a point along the ellipse, given the angle, and the width and the height of the ellipse.

Use this formula to calculate a point along the ellipsis.
Figure 2. Use this formula to calculate a point along the ellipsis.

The grippers are arranged around the border at preset angles, so the angle is known. The width and height of the ellipse are the width and height of the window for the outer edge of the window border (viewWidth and viewHeight), and the width and height of the window minus the thickness of the border for the inner edge of the window border.

The drawing routine uses the following formula to calculate the x and y coordinates of the four corners of the gripper, points A, B, C, and D:

var A:Point = new Point(); A.x = Math.cos(startAngle) * viewWidth/2; A.y = Math.sin(startAngle) * viewHeight/2; var B:Point = new Point(); B.x = Math.cos(startAngle) * (viewWidth-40)/2; B.y = Math.sin(startAngle) * (viewHeight-40)/2; var C:Point = new Point(); C.x = Math.cos(stopAngle) * (viewWidth-40)/2; C.y = Math.sin(stopAngle) * (viewHeight-40)/2; var D:Point = new Point(); D.x = Math.cos(stopAngle) * viewWidth/2; D.y = Math.sin(stopAngle) * viewHeight/2;

The start and stop angles are calculated by adding and subtracting half the angular width of the gripper from the preset gripper angle. Defining the length with angles rather than a distance makes the math a bit easier and also provides a more pleasing effect when the window is resized since the gripper length stays proportional to the border diameter.

var startAngle:Number = (angleRadians - spreadRadians); var stopAngle:Number = (angleRadians + spreadRadians);

The routine next draws the shape of the gripper between the four points (see Figure 3).

The shape of the gripper as drawn by the routine described below.
Figure 3.The shape of the gripper as drawn by the routine described below.

First, a straight line is drawn from A to B:

moveTo(A.x,A.y); lineTo(B.x,B.y);

Next, a series of line segments is drawn between B and C. If enough segments are used, then the visual effect is indistinguishable from an actual curve. !Square uses ten segments, which seems sufficient.

for(var i:int = 1; i < 10; i++){ lineTo(Math.cos(startAngle + i * incAngle) * (viewWidth-40)/2, Math.sin(startAngle + i * incAngle) * (viewHeight-40)/2); }

Another straight line is drawn from C to D and the shape is closed by drawing a polyline segment from D back to A. The shape is started with the beginBitmapFill() method so when endFill() is called the area defined by the drawing commands is filled with a bitmap texture.

Clipping the client area

The RoundWindow class uses a sprite with a clipping mask applied as the container for its contents. Any content objects that are drawn outside the border of the window are clipped. Window chrome elements are added directly to the stage so that they are not clipped.

Clipping can be implemented in Flash by setting the mask property of a Sprite object with another Sprite object. The masking sprite is not drawn, but only the parts in the first sprite that fall under the shape defined by the mask's graphics commands are visible.

In !Square, the clipped sprite is defined by the ClippedStage class. This class creates a clipping mask using the familiar commands for drawing an ellipse based on the width and height of the window. Any part of an object added as a child of the ClippedStage object that falls outside the ellipse are clipped.

private function setClipMask(bounds:Rectangle):void{ ellipticalMask.graphics.clear(); ellipticalMask.graphics.beginFill(0xffffff,1); ellipticalMask.graphics.drawEllipse(0,0,bounds.width,bounds.height); ellipticalMask.graphics.endFill(); }

The class also listens for resize events from the parent window and responds by redrawing the clipping mask based on the new window dimensions.

private function onResize(event:NativeWindowBoundsEvent):void{ setClipMask(event.afterBounds); }

This type of clipping is not limited to simple shapes, so the technique can be used for any window that has areas which should be masked.

Resizing an elliptical window

To resize the window, the border and grippers must be redrawn based on the new width and height of the window. The resize event object includes an afterBounds property that reports the new dimensions. The width and height from this property are passed to the window draw() method.

private function onBoundsChange(boundsEvent:NativeWindowBoundsEvent):void{ draw(boundsEvent.afterBounds.width, boundsEvent.afterBounds.height); }

Handling content in an elliptical window

Because the content in the !Square window is aware of its container (the springs are attached to the border), it must react to changes in window size and shape. It does this by listening for the window resize event and recalculating the dependent variables.

private function onResize(event:NativeWindowBoundsEvent):void{ center.x = event.afterBounds.width/2; center.y = event.afterBounds.height/2; eye.x -= event.afterBounds.x - event.beforeBounds.x; eye.y -= event.afterBounds.y - event.beforeBounds.y; for each (var spring:Spring in springs){ spring.outerEnd = calculateSpringAnchorPoint(spring.anchorAngle); } }

Since the content is always animated, it does not need to be redrawn by the resize listener. Redrawing occurs on the next frame event anyway. For non-animated content, you may need to resize or reposition the window content objects directly.

Products

  • Acrobat
  • Creative Cloud
  • Creative Suite
  • Digital Marketing Suite
  • Digital Publishing Suite
  • Elements
  • Mobile Apps
  • Photoshop
  • Touch Apps
  • Student and Teacher Editions

Solutions

  • Digital marketing
  • Digital media
  • Web Experience Management

Industries

  • Education
  • Financial services
  • Government

Help

  • Product help centers
  • Orders and returns
  • Downloading and installing
  • My Adobe

Learning

  • Adobe Developer Connection
  • Adobe TV
  • Training and certification
  • Forums
  • Design Center

Ways to buy

  • For personal and home office
  • For students, educators, and staff
  • For small and medium businesses
  • For businesses, schools, and government
  • Special offers

Downloads

  • Adobe Reader
  • Adobe Flash Player
  • Adobe AIR
  • Adobe Shockwave Player

Company

  • News room
  • Partner programs
  • Corporate social responsibility
  • Career opportunities
  • Investor Relations
  • Events
  • Legal
  • Security
  • Contact Adobe
Choose your region United States (Change)
Choose your region Close

North America

Europe, Middle East and Africa

Asia Pacific

  • Canada - English
  • Canada - Français
  • Latinoamérica
  • México
  • United States

South America

  • Brasil
  • Africa - English
  • Österreich - Deutsch
  • Belgium - English
  • Belgique - Français
  • België - Nederlands
  • България
  • Hrvatska
  • Česká republika
  • Danmark
  • Eastern Europe - English
  • Eesti
  • Suomi
  • France
  • Deutschland
  • Magyarország
  • Ireland
  • Israel - English
  • ישראל - עברית
  • Italia
  • Latvija
  • Lietuva
  • Luxembourg - Deutsch
  • Luxembourg - English
  • Luxembourg - Français
  • الشرق الأوسط وشمال أفريقيا - اللغة العربية
  • Middle East and North Africa - English
  • Moyen-Orient et Afrique du Nord - Français
  • Nederland
  • Norge
  • Polska
  • Portugal
  • România
  • Россия
  • Srbija
  • Slovensko
  • Slovenija
  • España
  • Sverige
  • Schweiz - Deutsch
  • Suisse - Français
  • Svizzera - Italiano
  • Türkiye
  • Україна
  • United Kingdom
  • Australia
  • 中国
  • 中國香港特別行政區
  • Hong Kong S.A.R. of China
  • India - English
  • 日本
  • 한국
  • New Zealand
  • 台灣

Southeast Asia

  • Includes Indonesia, Malaysia, Philippines, Singapore, Thailand, and Vietnam - English

Copyright © 2012 Adobe Systems Incorporated. All rights reserved.

Terms of Use | Privacy Policy and Cookies (Updated)

Ad Choices

Reviewed by TRUSTe: site privacy statement