Friday, September 7, 2012

How to embed assets in Flash Builder 4.7 Actionscript Projects

In Flash builder 4.7, [Embed] metadata tags are handled differently depending on whether you're working on a Flex-based project, or a pure actionscript one.  One difference has to do with how the path in a source attribute is looked up.

In a Flex project if you create a tag like this:
 [ Embed(source="myAsset.png") ]
the compiler will look for a file called myAsset.png in the root project folder.  This is the behavior Flash Builder users are accustomed to.

But in an actionscript project, the compiler will search for it relative to whatever folder the actionscript file is in. So let's say I have an actionscript class in package com.dougmccluer.controls.customList.as.  And in that class, I embed a graphic like so:
[ Embed(source="myAsset.png") ]
I will need to place my graphic file at [project root]/src/com/dougmccluer/controls/myAsset.png

OR, if I want to place my graphics in a folder called "embeds", I can change my metadata tag to look like this:
 [ Embed(source="../../../embeds/myAsset.png") ]
Absolute paths are also acceptable, for example:
/Users/doug/projects/testProject/embeds/myAsset.png
C:/Users/doug/Documents/projects/testProject/embeds/myAsset.png
but keep in mind absolute paths are not very friendly for collaborative projects.

If you use relative paths, you must update the paths any time you move the actionscript file.

Hopefully, by the time this product leaves beta, the actionscript compiler will be brought back in line with the Flex compiler so that they both interpret Embed paths as relative to the project folder.  

Wednesday, April 25, 2012

How to Make Flash Builder Start When it Won't Start



 Recently I've been working with Flash Builder 4.6 on Mac OSX 10.7 a.k.a. Lion.  A couple times now I've encountered a problem where Flash Builder just won't start.  It just hangs at the splash screen and the little beachball spins away.

Through Googling, I learned that other people have encountered the same behavior and they fixed it by deleting a .metadata file in their workspace. Supposedly the issue was that the workspace had become corrupted.

I could not find a .metadata file, but I was able to get running again by doing the following:

  1. Shut down (force quit) Flash Builder.
  2. Rename the workspace folder.
  3. Start up Flash Builder.  Behold!  It starts!  All the projects are now broken because the paths are now incorrect.
  4. Shut down Flash Builder.
  5. Rename the workspace folder back to what it was.
  6. Start up Flash Builder.
  7. Breathe a sigh of relief.

Hope this helps someone out.



Sunday, April 22, 2012

How to get scale9 images into Flex from Photoshop a little easier

Really getting into Flex skinning for the first time, and having been a Flash Professional guy for years, I'm  unenthused by what a cumbersome, non-visual process it is.

Case in point: the scale9 grid.

To use a scale9 grid on an embedded image you manually enter the pixel locations of the edges of the grid, like so:

<s:Image source="@Embed(source='embeds/myImage.png' scaleGridLeft='12', scaleGridTop='9', scaleGridRight='550', scaleGridBottom='63' )"/>

Much less convenient than the GUI that Flash Pro provides.  So I wrote a little extendScript to reduce the amount of time I spend measuring pixels in Photoshop.  It works like this:

1. Draw a selection box to define the area that should be the middle box in the scale9 grid.
2. Run the script.
3. Copy the text from the popup window and paste it into your Embed code

The code is below:

function getBounds(){}

getBounds.prototype.run = function()
{
 var selBounds;
 if(activeDocument.selection)
 {
  selBounds = activeDocument.selection.bounds;
 }
 else
 {
  alert("no selection");
 }
 var left = selBounds[0];
 var top = selBounds[1];
 var right = selBounds[2];
 var bottom = selBounds[3];
 
 // Create the palette-type window (a modeless dialog)
 var win = new Window('dialog', 'getBounds');
 this.windowRef = win;
 win.bounds = [100,100,760,260];
 
 // Create a container panel for the components
 win.pnl = win.add("panel", [5,5,650,150]);

 win.pnl.txt = win.pnl.add('edittext', [15,15,630,65], "scaleGridLeft='"+left.value+"', scaleGridTop='"+top.value+"', scaleGridRight='"+right.value+"', scaleGridBottom='"+bottom.value+"'");

 win.pnl.okBtn = win.pnl.add("button", [25,110,105,130], 'OK');

 // Define the behavior of the buttons
 win.pnl.okBtn.onClick = function()
 {
  win.close();
 }
 
 // Display the window
 win.show();
return true;
}

new getBounds().run();

Download the script file

To install the script, copy it into Photoshop's Scripts directory
Windows: C:\Program Files\Adobe\Adobe Photoshop CS4\Presets\Scripts\
Mac OSX: Applications/Adobe Photoshop CS4/Presets/Scripts/
After you restart Photoshop, it should appear under File > Scripts > GetScaleGridDimensions


I'm sure there's an even better solution out there, I'm just not aware of it.  If you are, let me know about it in the comments.  :)

Friday, April 20, 2012

Testing a Flex App for the iPad3 (part 2)



When testing a Flex app for the iPad3, you'll want to create a custom RuntimeDPIProvider so that the app scales to the correct size.  The Adobe docs describe how to subclass RuntimeDPIProvider at http://help.adobe.com/en_US/flex/mobileapps/WS19f279b149e7481c682e5a9412cf5976c17-8000.html#WS19f279b149e7481c-2a25e9b212d622ff5e8-8000

Using the following class will ensure the app is sized correctly on the device (using both slow and fast compile methods) and when previewing on the desktop.

package com.dougmccluer
{
 import flash.system.Capabilities;
 import mx.core.DPIClassification;
 import mx.core.RuntimeDPIProvider;
 
 public class CustomRuntimeDPIProvider extends RuntimeDPIProvider
 {
  public function CustomRuntimeDPIProvider()
  {
   super();
  }
  
  override public function get runtimeDPI():Number
  {
   if(Capabilities.os.indexOf("iPad")>-1)
   {
    if(Capabilities.screenResolutionX > 1500)
    {
     return DPIClassification.DPI_320;
    }
   }
   return DPIClassification.DPI_160;
  }
 }
}

You just need to tell the application to use the custom runtime provider and set the application dpi to 320.

s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
  xmlns:s="library://ns.adobe.com/flex/spark" 
  applicationDPI="320"
  runtimeDPIProvider="com.dougmccluer.CustomRuntimeDPIProvider">

Thursday, April 19, 2012

Testing a Flex app for iPad3

Testing a Flex app on the iPad3 (sorry, "The New iPad") isn't quite the no-thought-just-works proposition it is on the 2'nd gen device.  The 3rd gen iPad has a portrait resolution of1536x2048, which means it doesn't fit on my screen when I test on the desktop.
When testing on the device, you can get AIR to recognize the right resolution by pointing Flash Builder to the iOS 5.1 SDK, but that only works when you build an IPA using the "slow" method.  When I use the "fast" compile, the app treats the screen as 768x1024.  Meaning I only see the top left 1/4 of my app.

So in order to test I do the following:

1. I target the regular iPad in my debug configuration.  That sets the resolution to 768x1024 at a DPI of 132 (which Flash treats the same as 160).

2. I set applicationDPI="360" in the main application tag of my app.  Since the application DPI is double the screen DPI (which we set to 160 by choosing to target the original iPad), Flex scales everything down by 50%, even single-resolution bitmaps and hard-coded x and y values.  So I can run it on the desktop, or fast-publish to the device and everything fits and is in the proper proportions. ...except button text.  That doesn't get scaled down, so the buttons look weird.  But it's good enough to test against.

3. When I want to publish using the slow method, or do a release build, I remove the applicationDPI="360" from the Application tag.  Otherwise Flex would scale the app down to fit in a 768x1024 space in the top left hand corner of the screen, even though it sees the full 1536x2048 resolution.

Update:  A better solution is to create a custom RuntimeDPIProvider.

Thursday, March 29, 2012

How to Install Flash Player 11.2 on Ubuntu 64-bit ...like a noob

Today I installed flash player 11.2 on my Ubuntu box.  In the past when I've tried to install Flash Player it's been a huge mess because the instructions in the README don't work, or I don't know where the right plugins directory is so I end up copying files willy nilly into every location I find mentioned in my "flash player install linux ubuntu how to" google search until finally it works but I have no idea which was the right location.
So this time, I decided to clean up.  First I deleted every file I could find that had the words flash and player  in the name.  Also, to make sure I didn't have Gnash (a flash player alternative) installed, I typed the following into Terminal:

sudo apt-get remove gnash*

After confirming that Flash no longer worked in Firefox and Chrome I did the following:

1. Download Flash Player from http://get.adobe.com/flashplayer.  I chose the tar.gz option.
2. Extract the tar.gz package to ~/temp
3. in Terminal:
    sudo cp -r ~/temp/usr/* /usr
4. One by one, tried each directory that looked like it could be a firefox plugins directory until finally found the one that worked.  What finally worked was:
    sudo cp ~/temp/libflashplayer.so /usr/lib64/mozilla/plugins/libflashplayer.so

Now I've got 64-bit flash player running and my filesystem is much cleaner!

Wednesday, March 14, 2012

How to get Input From Entire Screen on Microsoft Surface

On Microsoft Surface, in order to detect TouchPoint input, you must create a new instance of the TouchTarget class (a.k.a. ContactTarget prior to v2.0)

The first parameter to the TouchTarget constructor is an IntPtr handle to an application window.  If you pass in a handle to a window running in a different process, you'll get an error.  This originally led me to believe that in order to detect touch input, you had to have a windowed application, and there was no option to detect touches occurring outside that window.

Fortunately, I was incorrect.

To use the whole screen as your TouchTarget, simply pass in IntPtr.Zero as your window handle, like so:


          new TouchTarget(IntPtr::Zero, Core::EventThreadChoice::OnBackgroundThread ); 
 

If you do this, keep in mind that TouchPoints you receive will have x and y coordinates relative to the screen, not your application window.