Category archive ‘flex‘

 
 

Flex4 Arc class (for Beta 2)

The Wedge FilledElement for Flex4 previously posted is not compatible with Flex4 Beta2.

The updated class (called Arc) is as follows.

package 
{
	import flash.display.Graphics;
	
	import spark.primitives.Ellipse;
	
	public class Arc extends Ellipse
	{
		public function Arc()
		{
			super();
		}
		
		private var _angle:Number = 0;
		
		[Inspectable(category="General")]
		/**
		 * Start angle for the wedge, in degrees. Zero degrees is 3 O'clock, or East.
		 */
		public function get angle():Number
		{
			return _angle;
		}
		
		public function set angle(value:Number):void
		{
			if (value != _angle)
			{
				_angle = value;
				invalidateSize();
				invalidateDisplayList();
				invalidateParentSizeAndDisplayList();
			}
		}
		
		private var _arc:Number = 0;
		
		[Inspectable(category="General")]
		/**
		 * Arc angle for the wedge, in degrees.
		 */
		public function get arc():Number
		{
			return _arc;
		}
		
		public function set arc(value:Number):void
		{
			if (value != _arc)
			{
				_arc = value;
				invalidateSize();
				invalidateDisplayList();
				invalidateParentSizeAndDisplayList();
			}
		}
		private var _thickness:Number = 0;
		
		[Inspectable(category="General")]
		/**
		 * Thickness of the wedge, measured inward from radius. 
		 */
		public function get thickness():Number
		{
			return _thickness;
		}
		
		public function set thickness(value:Number):void
		{
			if (value != _thickness)
			{
				_thickness = value;
				invalidateSize();
				invalidateDisplayList();
				invalidateParentSizeAndDisplayList();
			}
		}
		
		private var _radius:Number = 0;
		
		[Inspectable(category="General")]
		/**
		 * Exterior radius of the wedge
		 */
		public function get radius():Number
		{
			return _radius;
		}
		
		public function set radius(value:Number):void
		{
			if (value != _radius)
			{
				_radius = value;
				invalidateSize();
				invalidateDisplayList();
				invalidateParentSizeAndDisplayList();
			}
		}
		
		
		override protected function draw(g:Graphics):void
		{
			var xo:Number = drawX + (width/2);
			var yo:Number = drawY + (width/2);
			
			var workingArc:Number = _arc;
			// limit sweep to reasonable numbers
			if (Math.abs(workingArc) > 360)
				workingArc = 360;
			
			// Flash uses 8 segments per circle, to match that, we draw in a maximum
			// of 45 degree segments. First we calculate how many segments are needed
			// for our arc.
			var segs:Number = Math.ceil(Math.abs(workingArc) / 45);
			
			// Now calculate the sweep of each segment.
			var segAngle_a:Number = workingArc / segs
			var segAngle_b:Number = -workingArc / segs;
			
			// The math requires radians rather than degrees. To convert from degrees
			// use the formula (degrees/180)*Math.PI to get radians.
			var theta_a:Number = -(segAngle_a / 180) * Math.PI;
			var theta_b:Number = -(segAngle_b / 180) * Math.PI;
			
			// convert angle workingAngle to radians
			var workingAngle:Number = _angle;
			var angle:Number = -(workingAngle / 180) * Math.PI;
			
			// draw the curve in segments no larger than 45 degrees.
			if (segs > 0)
			{
				// draw a line from the end of the interior curve to the start of the exterior curve
				var workingRadius:Number = _radius;
				var ax:Number = xo + Math.cos(workingAngle / 180 * Math.PI) * workingRadius;
				var ay:Number = yo + Math.sin(-workingAngle / 180 * Math.PI) * workingRadius;
				g.moveTo(ax, ay);
				
				// Loop for drawing exterior  curve segments
				for (var i:int = 0; i < segs; i++)
				{
					angle += theta_a;
					var angleMid:Number;
					angleMid = angle - (theta_a / 2);
					var bx:Number = xo + Math.cos(angle) * workingRadius;
					var by:Number = yo + Math.sin(angle) * workingRadius;
					var cx:Number = xo + Math.cos(angleMid) * (workingRadius / Math.cos(theta_a / 2));
					var cy:Number = yo + Math.sin(angleMid) * (workingRadius / Math.cos(theta_a / 2));
					g.curveTo(cx, cy, bx, by);
				}
				
				// draw a line from the end of the exterior curve to the start of the interior curve
				workingAngle += workingArc;
				angle = -(workingAngle / 180) * Math.PI;
				
				// draw the interior (subtractive) wedge
				// draw a line from the center to the start of the interior curve
				var interiorRadius:Number = workingRadius - _thickness;
				var dx:Number = xo + Math.cos(workingAngle / 180 * Math.PI) * interiorRadius;
				var dy:Number = yo + Math.sin(-workingAngle / 180 * Math.PI) * interiorRadius;
				g.lineTo(dx, dy);
				
				// Loop for drawing interior curve segments
				for (i = 0; i < segs; i++)
				{
					angle += theta_b;
					angleMid = angle - (theta_b / 2);
					bx = xo + Math.cos(angle) * interiorRadius;
					by = yo + Math.sin(angle) * interiorRadius;
					cx = xo + Math.cos(angleMid) * (interiorRadius / Math.cos(theta_b / 2));
					cy = yo + Math.sin(angleMid) * (interiorRadius / Math.cos(theta_b / 2));
					g.curveTo(cx, cy, bx, by);
				}
				g.lineTo(ax, ay);
			}
		}
		
	}
}

Re-Blog: You don’t know jack about software maintenance.

I strikes me that, while not 100% relevant to Flex/RIA development, much of what Paul Stachour & David Collier-Brown dig up here from the history of software development, is little known to the current breed of web and Flex developers, I am sure though, that all understand the problem of software maintenance first hand…

Link to full article…

Flex 4 Wedge

I’ve created a wedge element for Flex4 which you may like to use for your projects, it’s a subclass of FilledElement from the new Spark framework, which already provides Ellipse and Rect primitives. The wedge will draw pie wedges of any radius, arc and start angle, you can also set thickness to create ring wedges, as you can see here.

Wedge Demo screen

You can download the code and the wedge demo application from the View Source panel on the demo page.

The Wedge class code is as follows.

package com.mentalaxis.view.draw
{
	
	import flash.display.Graphics;
	import flash.geom.Matrix;
	import flash.geom.Point;
	
	import mx.utils.MatrixUtil;
	
	import spark.primitives.supportClasses.FilledElement;
	
	/**
	 * <p>Draws a wedge shape using these parameters</p> 
	 * 
	 * <li>angle (degrees, 0 = 3O'Clock or Compass East)</li> 
	 * <li>arc (degrees)</li>
	 * <li>thickness (pixels)</li>
	 * <li>radius (pixels)</li>
	 * 
	 * <p>position, width and height determine the bounding area of the wedge 
	 * the wedge radius is measured from the center of this bounding area.</p> 
	 */
	public class Wedge extends FilledElement
	{
		
		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------
		
		/**
		 *  Wedge Constructor
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10
		 *  @playerversion AIR 1.5
		 *  @productversion Flex 4
		 */
		public function Wedge()
		{
			super();
		}
		
		//--------------------------------------------------------------------------
		//
		//  Properties
		//
		//--------------------------------------------------------------------------
		private var _angle:Number = 0;
		
		[Inspectable(category="General")]
		/**
		 * Start angle for the wedge, in degrees. Zero degrees is 3 O'clock, or East.
		 */
		public function get angle():Number
		{
			return _angle;
		}
		
		public function set angle(value:Number):void
		{
			if (value != _angle)
			{
				_angle = value;
				invalidateSize();
				invalidateDisplayList();
				invalidateParentSizeAndDisplayList();
			}
		}
		
		private var _arc:Number = 0;
		
		[Inspectable(category="General")]
		/**
		 * Arc angle for the wedge, in degrees.
		 */
		public function get arc():Number
		{
			return _arc;
		}
		
		public function set arc(value:Number):void
		{
			if (value != _arc)
			{
				_arc = value;
				invalidateSize();
				invalidateDisplayList();
				invalidateParentSizeAndDisplayList();
			}
		}
		private var _thickness:Number = 0;
		
		[Inspectable(category="General")]
		/**
		 * Thickness of the wedge, measured inward from radius. 
		 */
		public function get thickness():Number
		{
			return _thickness;
		}
		
		public function set thickness(value:Number):void
		{
			if (value != _thickness)
			{
				_thickness = value;
				invalidateSize();
				invalidateDisplayList();
				invalidateParentSizeAndDisplayList();
			}
		}
		
		private var _radius:Number = 0;
		
		[Inspectable(category="General")]
		/**
		 * Exterior radius of the wedge
		 */
		public function get radius():Number
		{
			return _radius;
		}
		
		public function set radius(value:Number):void
		{
			if (value != _radius)
			{
				_radius = value;
				invalidateSize();
				invalidateDisplayList();
				invalidateParentSizeAndDisplayList();
			}
		}
		
		//--------------------------------------------------------------------------
		//
		//  Overridden methods
		//
		//--------------------------------------------------------------------------
		
		/**
		 *  @private
		 */
		override protected function transformWidthForLayout(width:Number, height:Number, postLayoutTransform:Boolean = true):Number
		{
			if (postLayoutTransform)
			{
				var m:Matrix = computeMatrix();
				if (m)
					width = MatrixUtil.getEllipseBoundingBox(width / 2, height / 2, width / 2, height / 2, m).width;
			}
			
			// Take stroke into account
			return width + getStrokeExtents().x;
		}
		
		/**
		 *  @private
		 */
		override protected function transformHeightForLayout(width:Number, height:Number, postLayoutTransform:Boolean = true):Number
		{
			if (postLayoutTransform)
			{
				var m:Matrix = computeMatrix();
				if (m)
					height = MatrixUtil.getEllipseBoundingBox(width / 2, height / 2, width / 2, height / 2, m).height;
			}
			
			// Take stroke into account
			return height + getStrokeExtents().y;
		}
		
		/**
		 *  @inheritDoc
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 9
		 *  @playerversion AIR 1.1
		 *  @productversion Flex 3
		 */
		override public function getBoundsXAtSize(width:Number, height:Number, postLayoutTransform:Boolean = true):Number
		{
			var strokeExtents:Point = getStrokeExtents(postLayoutTransform);
			var m:Matrix = postLayoutTransform ? computeMatrix() : null;
			if (!m)
				return strokeExtents.x * -0.5 + this.x;
			
			if (!isNaN(width))
				width -= strokeExtents.x;
			if (!isNaN(height))
				height -= strokeExtents.y;
			
			// Calculate the width and height pre-transform:
			var newSize:Point = MatrixUtil.fitBounds(width, height, m, preferredWidthPreTransform(), preferredHeightPreTransform(), minWidth, minHeight, maxWidth, maxHeight);
			if (!newSize)
				newSize = new Point(minWidth, minHeight);
			
			return strokeExtents.x * -0.5 + MatrixUtil.getEllipseBoundingBox(newSize.x / 2, newSize.y / 2, newSize.x / 2, newSize.y / 2, m).x;
		}
		
		/**
		 *  @inheritDoc
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 9
		 *  @playerversion AIR 1.1
		 *  @productversion Flex 3
		 */
		override public function getBoundsYAtSize(width:Number, height:Number, postLayoutTransform:Boolean = true):Number
		{
			var strokeExtents:Point = getStrokeExtents(postLayoutTransform);
			var m:Matrix = postLayoutTransform ? computeMatrix() : null;
			if (!m)
				return strokeExtents.y * -0.5 + this.y;
			
			if (!isNaN(width))
				width -= strokeExtents.x;
			if (!isNaN(height))
				height -= strokeExtents.y;
			
			// Calculate the width and height pre-transform:
			var newSize:Point = MatrixUtil.fitBounds(width, height, m, preferredWidthPreTransform(), preferredHeightPreTransform(), minWidth, minHeight, maxWidth, maxHeight);
			if (!newSize)
				newSize = new Point(minWidth, minHeight);
			
			return strokeExtents.y * -0.5 + MatrixUtil.getEllipseBoundingBox(newSize.x / 2, newSize.y / 2, newSize.x / 2, newSize.y / 2, m).y;
		}
		
		/**
		 *  @private
		 */
		override public function getLayoutBoundsX(postLayoutTransform:Boolean = true):Number
		{
			var stroke:Number = -getStrokeExtents(postLayoutTransform).x * 0.5;
			
			if (postLayoutTransform)
			{
				var m:Matrix = computeMatrix();
				if (m)
					return stroke + MatrixUtil.getEllipseBoundingBox(width / 2, height / 2, width / 2, height / 2, m).x;
			}
			
			return stroke + this.x;
		}
		
		/**
		 *  @private
		 */
		override public function getLayoutBoundsY(postLayoutTransform:Boolean = true):Number
		{
			var stroke:Number = -getStrokeExtents(postLayoutTransform).y * 0.5;
			
			if (postLayoutTransform)
			{
				var m:Matrix = computeMatrix();
				if (m)
					return stroke + MatrixUtil.getEllipseBoundingBox(width / 2, height / 2, width / 2, height / 2, m).y;
			}
			
			return stroke + this.y;
		}
		
		/**
		 * @private 
		 */
		override protected function drawElement(g:Graphics):void
		{
			var xo:Number = drawX + (width/2);
			var yo:Number = drawY + (width/2);
			
			var workingArc:Number = _arc;
			// limit sweep to reasonable numbers
			if (Math.abs(workingArc) > 360)
				workingArc = 360;
			
			// Flash uses 8 segments per circle, to match that, we draw in a maximum
			// of 45 degree segments. First we calculate how many segments are needed
			// for our arc.
			var segs:Number = Math.ceil(Math.abs(workingArc) / 45);
			
			// Now calculate the sweep of each segment.
			var segAngle_a:Number = workingArc / segs
			var segAngle_b:Number = -workingArc / segs;
			
			// The math requires radians rather than degrees. To convert from degrees
			// use the formula (degrees/180)*Math.PI to get radians.
			var theta_a:Number = -(segAngle_a / 180) * Math.PI;
			var theta_b:Number = -(segAngle_b / 180) * Math.PI;
			
			// convert angle workingAngle to radians
			var workingAngle:Number = _angle;
			var angle:Number = -(workingAngle / 180) * Math.PI;
			
			// draw the curve in segments no larger than 45 degrees.
			if (segs > 0)
			{
				// draw a line from the end of the interior curve to the start of the exterior curve
				var workingRadius:Number = _radius;
				var ax:Number = xo + Math.cos(workingAngle / 180 * Math.PI) * workingRadius;
				var ay:Number = yo + Math.sin(-workingAngle / 180 * Math.PI) * workingRadius;
				g.moveTo(ax, ay);
				
				// Loop for drawing exterior  curve segments
				for (var i:int = 0; i < segs; i++)
				{
					angle += theta_a;
					var angleMid:Number;
					angleMid = angle - (theta_a / 2);
					var bx:Number = xo + Math.cos(angle) * workingRadius;
					var by:Number = yo + Math.sin(angle) * workingRadius;
					var cx:Number = xo + Math.cos(angleMid) * (workingRadius / Math.cos(theta_a / 2));
					var cy:Number = yo + Math.sin(angleMid) * (workingRadius / Math.cos(theta_a / 2));
					g.curveTo(cx, cy, bx, by);
				}
				
				// draw a line from the end of the exterior curve to the start of the interior curve
				workingAngle += workingArc;
				angle = -(workingAngle / 180) * Math.PI;
				
				// draw the interior (subtractive) wedge
				// draw a line from the center to the start of the interior curve
				var interiorRadius:Number = workingRadius - _thickness;
				var dx:Number = xo + Math.cos(workingAngle / 180 * Math.PI) * interiorRadius;
				var dy:Number = yo + Math.sin(-workingAngle / 180 * Math.PI) * interiorRadius;
				g.lineTo(dx, dy);
				
				// Loop for drawing interior curve segments
				for (i = 0; i < segs; i++)
				{
					angle += theta_b;
					angleMid = angle - (theta_b / 2);
					bx = xo + Math.cos(angle) * interiorRadius;
					by = yo + Math.sin(angle) * interiorRadius;
					cx = xo + Math.cos(angleMid) * (interiorRadius / Math.cos(theta_b / 2));
					cy = yo + Math.sin(angleMid) * (interiorRadius / Math.cos(theta_b / 2));
					g.curveTo(cx, cy, bx, by);
				}
				g.lineTo(ax, ay);
			}
		}
	}
}

Ocodo’s™ happy happy™ brainwash machine™

The happy happy brainwash machine. - http://ocodo.id.au/screensaver/lab

Flex Formatter Update available.

Flex Formatter Version 0.6.24 is now available. http://sourceforge.net/projects/flexformatter/

Flex Tools on Del.icio.us

I’m collecting useful links for flex developers on del.icio.us/flextools

If you want to send any useful flex development tools or info to the list, add them with your own del.icio.us account and tag them with for:flextools (and anything else useful.)

Thanks.

FlexFormatter

If you are looking for code formatting tools for Flex Builder, scoot over to https://sourceforge.net/projects/flexformatter/ Ernest Pasour has built an excellent set of source code tools for Flex Builder.

  • Code Formatter
  • Auto Commenting
  • Source Code Reordering

The downloaded zip file can be extracted into the eclipse/dropins folder, and it’ll just work when you restart eclipse. Ernest was also kind enough to provide instructions for source formatting from the command line, so you can format a whole tree of source code at once.

Great for getting your code painlessly adhering to the Flex Coding Conventions.

FlexFormatter also provides a tool for adding asdoc stub comments, (much like my as3dac tool) and should be easy to use for anyone, (admittedly my scripts aren’t for the faint hearted.)

The source code re-ordering tool allows you to re sort the appearance of various parts of a class automatically, constant, constructor, class fields, accessors, mutators and methods all sorted for you effortlessly.

It’s some really great work, and a useful addition to your flex tool set.

(Ernest’s Flex Formatting command line usage guide is here)

AS3 Documentation, Auto Commenting

Some time ago I scripted an auto commenting system for ActionScript 2.0, I’d long planned to upgrade it to ActionScript 3.0, but things tended to get in the way of that, and I kept putting it off.

I began working on a project recently which needed half a dozen AS3 class libraries to be documented, as luck would have it. So I spent some time updating the scripts from AS2 with NaturalDocs & Doxygen to AS3 with AsDoc.

In a nutshell, the script will parse an AS3 class or interface file and add asdoc comment blocks, it will also adhere to the Flex SDK coding conventions, where there are special cases for doc comments.

Go over to the google code page http://as3dac.googlecode.com and check it out.

as3dac-pageview

If you are using Windows, you’ll need to install Cygwin (with Perl.) You should be able to get going on a Mac, Linux or other *nix. See the code project page for details.

Flex Coding Conventions

Back in April last year I blogged about coding standards in AS3, I wrote a protracted post covering just naming conventions, and of course there have been numerous posts covering this topic, unfortunately the community rarely agrees on such things, and in particular the genetic strain that builds Flash coders seems to be of a particularly stubborn variety. Of course, I’m just kidding, all developers are stubborn.

Finally, (well back in March, it seems I’m fashionably late to this party.) The Adobe Flex team introduced a set of standards that should be adhered to for contributions to the Flex SDK.

There are a few points which will make widespread adoption of the standards (for use in general.) a little problematic for some developers. The 2 most significant points are these.

The odd Inconsistency.

For a one line if statement, the guidelines stipulate that the following line, after the if, else, elseif, should not be enclosed in { .. } - see below.

// Single command if
if (myCondition)
    trace(myCondition);

// if else with 1 and 2 line commands
if (myCondition)
{
    trace(myCondition);
}
else
{
    i++;
    trace(myCondition);
}

// Single command for loop
for (var i:int = 0; i &lt; n; i++)
{
    trace(i);
}

// Single command while loop
while ( !flag )
{
    trace(flag);
}

Since this pattern doesn’t apply to any other structure, (e.g. for, while etc.) and since it is inconsistency we are fighting when we use code standards, this really shouldn’t be a convention.

Brace wars…

The strategy that must be followed for bracing blocks is aligned braces. For example…

for (var i:int = 0; i &lt; n; i++)
{
    trace(i);
}

This strategy has caused a few AS3 developers to turn a slight shade of blue, I won’t repeat the complaints, they are, I’m sorry to say, redundant. The braces war has raged for far longer than the history of actionscript, and there isn’t a true and right way, both methods have benefits. The Flex team has chosen this strategy, as a professional developer, you should, no, actually, you must follow it.

Just incase you need a bit of rationale, (and trust me, I generally adopted the compressed format prior to the standards announcement.) The opened brace format or BSD style, is beneficial for the following reasons.

  • Generally improved readability due to the additional white space.
  • Block start and end points, are specifically easier to see due to the uniform alignment of braces with their partner.

There are other benefits but these are the primary ones. Of course you may have contrary opinions about brace style, and of course, so could I, but so what? Follow the standard kiddo.

Notable omission.

There is only one omission that I can think is worth mentioning, it also covers a variety of cases, this is the stipulation that 80 columns should be the maximum line length, it creates a few situations where we have to line break a single statement. The conventions supply a solution to object and array assignment. However, there are a couple of other cases where this could be a problem, method signatures and complex conditional expressions. Without an adequate strategy to cover these cases, we have to rely on the Java standard, which has strategies for handling these cases. It would be better for the Flex conventions to provide a solution.

In conclusion.

The release of a set of comprehensive standards is a necessary move by Adobe, and long overdue, adoption for the wider community is of course not mandatory, but I would expect developers who consider themselves professional to understand the value of adhering to the standards on all but the most trivial of code.

For the developers who wish to contribute to the Flex SDK, it is of course mandatory to follow the standards of the project. I hope that work continues on them at some pace, and that we have a complete and clear set of standards to adhere to in the professional development community.