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 / Fireworks Developer Center /

Creating Fireworks Panels – Part 2: Advanced Custom Panel Development

by Trevor McCauley

Trevor McCauley
  • Adobe

Content

  • The Annotations Panel
  • Sizing, Positioning, and Scaling Panels
  • Using System Colors in Panels
  • Getting Values from Fireworks JavaScript
  • Storing Data as URL-Encoded Strings
  • Using Fireworks Events in Flash Panels
  • Preventing Commands from Disrupting the Selection
  • Saving Panel Preferences
  • Tips for Finishing Your Panel

Created

14 November 2005

Page tools

Share on Facebook
Share on Twitter
Share on LinkedIn
Bookmark
Print
design extensibility Fireworks 8

Requirements

Prerequisite knowledge

ActionScript and a basic understanding of the Fireworks DOM and working with Fireworks JavaScript.

User level

Advanced

Sample files

  • custom_fw_panels_pt2.zip (336 KB)

Custom panels in Fireworks 8 allow you to unlock hidden functionality in the product, introduce new functionality to the product, or simply improve your workflow. In Part 1 of this series, I showed you how to make your own custom panels for Fireworks using Macromedia Flash.

Creating Fireworks Panels – Part 1: An Introduction to Custom Panels ›

In the custom panel examples in Part 1, I paid little attention to their interfaces—which consisted mainly of simple buttons within a relatively small, static work area. Although such panels are fully functional, more attention could be given to their interface design and usability.

I also covered only basic panel functionality. Both the Create Ellipse and Mirror panels did nothing more than call basic Fireworks JavaScript commands, which were initiated by interacting with the interface. Custom Fireworks panels, however, are capable of much more than that.

Part 2 covers more advanced panel development, including interface design, working with the exchange of information between a custom panel and Fireworks, and taking advantage of additional features, such as Fireworks events.

I address each of these topics by working through a single panel example: the Annotations panel.

The Annotations Panel

The Annotations panel is a custom panel in Fireworks that allows you to leave notes or annotations in a Fireworks document, either for the document itself or for individual elements within that document (see Figure 1).

Annotations panel in action
Figure 1. Annotations panel in action

The current user's name appears at the top of the panel. This identifies who edits or creates the annotations. (Basically, this means you.) Next to the user name is a button that allows you to change the annotation. Below that is the main annotation text area. This is where you create, edit, and view annotations for your document and those elements within it. The Save button saves the current annotation to the current selection.

Each element in a Fireworks document—path, bitmap, or even a slice—can have its own annotations, and they appear in this panel just by selecting the element. If no elements are selected, the annotations displayed will represent those for the entire Fireworks document. The status bar indicates who last edited the current annotation and when.

The Annotations panel template FLA (see Figure 2) is provided in the source files you downloaded at the beginning of this tutorial.

Annotations panel template FLA
Figure 2. Annotations panel template FLA

You can find it here in the sample download:

Source Files/Templates/Annotations.fla

Open it in Flash, publish the SWF to the Fireworks Command Panels folder, and then restart Fireworks to make sure Fireworks recognizes Annotations as a panel.

Note: The Annotations panel I discuss here is not compatible with my original Annotations panel. If you have been using the original panel, use the Convert Annotations command provided with the source files to convert older annotations in a Fireworks document into the format that's compatible with this newer panel.

Sizing, Positioning, and Scaling Panels

When you first open a panel, Fireworks displays it at the size specified by the SWF document that makes up the interface. Users can resize custom panels all they want in Fireworks, but not smaller than the original size of the SWF. By default, when a panel is scaled, Flash Player scales the SWF to match the dimensions of the panel window. As a result, your panel interface may grow unattractively beyond its designed size. At times this may be desirable, but often it is not.

Luckily, Flash allows you to prevent a SWF scaling with the player area by using ActionScript. You can achieve this by setting the scaleMode property of the Stage object to "noScale", as follows:

Stage.scaleMode = "noScale";

A panel SWF with a scale mode of "noScale" will retain its original size despite the size of the panel window, centering itself in whatever area the panel provides.

However, it is not typical that a panel will center itself within the area of the panel. As you may notice with the Align or Auto Shape Properties custom panels, they are positioned instead at the top left of the panel area. Again, using the Stage object in ActionScript, you can allow for this by setting the align property to "TL" (for top left):

Stage.align = "TL";

Something else you may notice about most panels is that they are the same width—around 200 pixels or so. This allows them to fit alongside other docked panels at the side of the Fireworks workspace. If any panel were too wide, the other panels would have to stretch to match its width. When creating your own panels, keep your panel's width at around 200 pixels.

The Annotations panel was designed to be as small as possible, while still being functional. It uses scaleMode and align to make sure it remains fixed to the top left of Flash Player and does not scale. Add the scaleMode and align property definitions to the ActionScript layer in the Annotations FLA and publish a SWF to test it in Fireworks (see Figure 3).

Annotations panel elements positioned at the top left and unscaled
Figure 3. Annotations panel elements positioned at the top left and unscaled

Top-left alignment and no scaling may become your preference for panel interfaces, but there are additional options available to you. I like to think that a well designed panel makes full use of the available Flash Player space provided by the panel window. For example, the contents of the Layers panel resizes horizontally with the size of the panel window and can even scale down vertically to be smaller than its contents. Although the Layers panel is not itself a custom SWF panel, its behavior can mimic your custom panels.

Scaling panels relies on the ActionScript Stage.onResize event to detect when the available size of the player has changed. When that event is called, the SWF moves and scales the elements in the interface to match the new size:

Stage.addListener(this); function onResize(){ // resize your movie }

The more elements within your Flash interface, the more complex the onResize event handler because it needs to take the scaling of most, if not all, of those elements into consideration.

There are seven elements in the Annotations panel that are each going to be sized with the interface (see Figure 4):

  1. User name label (user_label)
  2. Edit user name button (edituser_button)
  3. Annotations text area (annotations_ta)
  4. Save button (save_button)
  5. User last edited label (editeduser_label)
  6. Time last edited label (editedtime_label)
  7. Face movie clip (face_mc)
Elements of the Annotations panel
Figure 4. Elements of the Annotations panel

Each element moves or scales based on either the size of Flash Player or another element within the interface. For example, the annotations text area scales horizontally to the right based on the player's width but scales vertically based on the location of the Save button. The Save button moves vertically based on the position of the last user's edited label, which is based on the position of the date-last-edited label, which is based on the position of the bottom of Flash Player.

You could base the annotations text area off of the height of Flash Player. However, if an element between the annotations text area and the player's edge changes in size, the annotations text area would not be able to compensate for that, and there might be an overlap. Because some elements are based on the size of others, you need to make sure to adjust elements with dependencies last. That means positioning and sizing the Save button before the annotations text area.

Because of the not-so-robust nature of the UI components in Flash, an additional check is needed within the onResize event. Despite the fact that the user cannot manually scale a panel window to be smaller than the dimensions of the SWF it's playing, that does not mean that the panel won't ever be smaller than those dimensions. In fact, there are certain conditions in Fireworks where panels are resized to unexpected sizes internally when collapsed. Although this is not visible to the user, it can wreak havoc on your Flash components because many UI components will break if they are inappropriately sized. To prevent this from happening, include a condition in your onResize event handler that makes sure the scaling size does not fall below that of the movie at its smallest size. For the Annotations panel, the sizes for the height and width are 150 and 160 pixels, respectively.

Also, when a SWF is loaded into a Fireworks panel, the onResize event is not immediately handled. You may want to force a call to onResize when the movie starts so that it can display the panel interface correctly when opened:

Stage.addListener(this); function onResize(){ var PADDING = 5; var width = Math.max(150, Stage.width); var height = Math.max(160, Stage.height); face_mc._width = width; face_mc._height = height; edituser_button.move(width - edituser_button.width - PADDING, PADDING); user_label.move(PADDING, PADDING); user_label.setSize(edituser_button.x - PADDING*2, null); editedtime_label.setSize(width - PADDING*2, null); editedtime_label.move(PADDING, height - editedtime_label.height); editeduser_label.setSize(width - PADDING*2, null); editeduser_label.move(PADDING, height - editedtime_label.height - editeduser_label.height); save_button.move(width - save_button.width - PADDING, editeduser_label.y - save_button.height - PADDING); annotations_ta.move(PADDING, user_label.y + user_label.height + PADDING); annotations_ta.setSize(width - PADDING*2, save_button.y - (edituser_button.y + edituser_button.height) - PADDING*2); } onResize();

Notice that a PADDING variable is used to help control padding within the interface. Using a variable like this makes it easier to perform adjustments in spacing elements. Add this code to the ActionScript layer in the Annotations FLA, publish the SWF, and then test the panel in Fireworks. The interface now stretches to meet the size of the panel (see Figure 5).

Annotations panel elements scaled to fit the panel width
Figure 5. Annotations panel elements scaled to fit the panel width

Using System Colors in Panels

Fireworks 8 introduces a new core object for Fireworks JavaScript called the System object. This object provides information about the system that the current version of Fireworks is running on. More specifically, it provides the name of the operating system and system colors if the operating system is Microsoft Windows. You can use this object to help you develop panels whose colors match the color scheme of the user's computer (but only if it's Windows).

Table 1 lists the 10 System object properties, mostly related to colors associated with part of a Windows color scheme (see Figure 6).

Table 1. System Object Properties in Fireworks JavaScript
Property Description Windows Color
osName Returns the name of the current operating system (e.g., “Windows XP” or “Macintosh 10.3.9”) N/A
controlDarkShadowColor Returns the system color used for control dark shadows 3D Objects (auto)
controlFaceColor Returns the system color used for control and panel faces 3D Objects
controlHighlightColor Returns the system color used for control highlights 3D Objects (auto)
controlShadowColor Returns the system color used for control shadows 3D Objects (auto)
highlightItemColor Returns the system color used for highlighting selections Selected Items
highlightTextColor Returns the system color used for highlighting selected text Selected Items: Font
menuColor Returns the system color used for menu backgrounds Menu
menuTextColor Returns the system color used for text in menus Menu: Font
textColor Returns the system color used for text Window/Message Box: Font
Adjusting the Windows color scheme
Figure 6. Adjusting the Windows color scheme

Because these colors are specific to the Windows operating system, Mac OS users should stick to the default colors of your panel. A good choice is white, as used by the Annotations panel.

For Windows users, the Annotations panel uses the System object to determine the panel's face color using menuColor. However, menuColor is a property in Fireworks JavaScript, not ActionScript. To get the value of that property into Flash, use MMExecute as described in the next section.

Getting Values from Fireworks JavaScript

Part 1 of this series used the ActionScript command MMExecute to run Fireworks JavaScript from a Flash panel in Fireworks. Passing a string into MMExecute executes it as a Fireworks JavaScript command in Fireworks. MMExecute doesn't just execute a command string; it also returns the result of that command back to Flash.

Running MMExecute

MMExecute uses the value of the last code line in a JavaScript command to be sent back to Flash. This value is returned in Flash as a string, no matter what type it was in the command as JavaScript. This is important to remember. For example, if a command returns either true or false, MMExecute would return either the strings “true” or “false” when running the command, not the values true or false. If there is no value to be returned, the value given to Flash is an empty string.

For the Annotations panel, MMExecute simply runs the string “System.menuColor;” in order to get the value of menuColor sent to Flash as a string:

var faceColor = MMExecute('System.menuColor;');

The faceColor variable in Flash is then assigned a string in the form of “#RRGGBB”, depending on the user's system color for the menu. Assuming the user is running Windows, this can be used to give the face movie clip—properly formatted to a usable Flash color, of course. This is defined in a function called setFaceColor which is run when the movie starts:

function setFaceColor(){ if (MMExecute('System.osName;') == "Windows XP"){ var faceColor = MMExecute('System.menuColor;'); faceColor = parseInt(faceColor.substr(1), 16); var faceColorTransform = face_mc.transform.colorTransform; faceColorTransform.rgb = faceColor; face_mc.transform.colorTransform = faceColorTransform; } } setFaceColor();

Add this code to the Annotations FLA and then publish it for Fireworks to see the results (see Figure 7).

Annotations panel now using Windows system coloring
Figure 7. Annotations panel now using Windows system coloring

Saving Values with customData and pngText

The purpose of the Annotations panel is to save text for a Fireworks document, whether it relates to elements within the document or the document itself. For this information to be retained within the document, the text has to be stored in such a way that will let it remain with that document even after it's closed and reopened later (see Figure 8). Doing this requires making use of Fireworks JavaScript objects like customData and pngText.

Panel storing information within a circle element
Figure 8. Panel storing information within a circle element

Each element in a Fireworks document has a persistent data structure in JavaScript called customData. In this object you can store variables specific to that element that will retain their values even if the file is closed and reopened at a later time. The customData object of the current selection would be accessed using the following:

fw.selection[0].customData;

The document itself doesn't have a customData object. The closest thing the document has is something called pngText, an object that stores the document creation time and the software used to create the document. The pngText object, however, is also capable of storing additional data. In fact, you can assign any number of additional properties to pngText (creation time and the software used are already stored, respectively, as CreationTime and Software). The only downside is that unlike customData, which can store just about anything, the values of pngText properties are limited to strings. Luckily, all that the Annotations panel requires is a string, so pngText works as a suitable alternative to customData for saving document-based annotations. You can access the pngText object for the current document using the following:

fw.getDocumentDOM().pngText;

For the document and any element in the document, the Annotations panel will need to store three kinds of textual information: annotation text provided by the user, user's name as indicated in the panel (also provided by the user), and time of the last edit. Each is stored as strings in either the pngText or customData objects. This information is accessed and read when the panel updates to display annotation information for the current selection and is saved back to that selection when the user clicks the Save button.

To make sure this data doesn't conflict with other panels or commands that use these objects, it's prudent to store information in new variables in pngText or customData that are named after your panel. In the case of the Annotations panel, an Annotations property is assigned to selected pngText or customData objects during the save:

fw.getDocumentDOM().pngText.Annotations = "some string value"; fw.selection[0].customData.Annotations = "some string value";

The saved information, however, consists of three values (annotation text, user name, and edit time), not just one. Two additional variables could be added to the customData and pngText objects but this could become confusing and cumbersome, especially when you make panels that use more than just three values. Also, don't forget that these values need to make their way into Flash. That could require a call to MMExecute for each variable used. As an alternative, you can use a single string to contain all three variable values, and then store it in the form of a URL-encoded variable string.

Storing Data as URL-Encoded Strings

A URL-encoded variable string lets you store values for multiple variables in one string. If you are unfamiliar with them, chances are you've seen them in URLs on the Internet. They have the following form:

variable1=value1&variable2=value2&variablen=valuen

Equal signs (=) separate a variable name from its value and each variable is separated by an ampersand (&). When it's decoded, you get separate variables each with their separate values.

Flash can handle URL-encoded variable strings with the LoadVars class, which is usually used to obtain information from external URLs but can also be used to encode and decode URL-encoded variable strings. Because the Annotations panel handles all saved and retrieved content within Flash, this makes URL-encoded variable strings a great way to store the annotation text, user name, and last edited values all in one string with minimal hassle.

Now, you can store annotation information like the following:

fw.getDocumentDOM().pngText.Annotations = "text=Hello%20World&user=Trevor&time=9%3A06%3A11am%20-%20Tue%20Oct%2025%202005";

This definition contains three variables: text, user, and time. Each contains a value that is URL encoded (or “escaped”) within the string.

The getAnnotation function retrieves an annotation's variable string. When obtaining the value, however, you will need to figure out if you're dealing with pngText or a customData object, and check to make sure the Annotations property actually exists. This is all handled in a JavaScript command that is executed ultimately with MMExecute in Flash:

function getAnnotation(){ var data = {}; if (fw.selection.length) data = fw.selection[0].customData; else if (fw.getDocumentDOM()) data = fw.getDocumentDOM().pngText; return (data.Annotations != undefined) ? data.Annotations : ""; }

In Flash the recovered string is sent to a LoadVars instance that can parse the string into separate variables. You can call this LoadVars instance FWVariables. A function in Flash calls the JavaScript command and sends the results to FWVariables. Then, the interface is updated with the new content:

var FWVariables = new LoadVars(); function getAnnotation(){ var cmd = 'function getAnnotation(){' +' var data = {};' +' if (fw.selection.length) data = fw.selection[0].customData;' +' else if (fw.getDocumentDOM()) data = fw.getDocumentDOM().pngText;' +' return (data.Annotations != undefined) ? data.Annotations : "";' +'}' +'getAnnotation();'; var variable_str = MMExecute(cmd); FWVariables = new LoadVars(); FWVariables.decode( variable_str ); update(); }

The Update function simply takes the variables in FWVariables and applies them to the affected places within the interface—the annotation's text area and the two labels in the status bar indicating when the annotation was last edited (and by whom). If no variables for those values exist, you can set the text to be an empty string or use default text in its place:

function update(){ if (FWVariables.text){ annotations_ta.text = FWVariables.text; }else{ annotations_ta.text = ""; } if (FWVariables.user){ editeduser_label.text = "<b>Last edited by:</b> " + FWVariables.user; }else{ editeduser_label.text = "---"; } if (FWVariables.time){ editedtime_label.text = FWVariables.time; }else{ editedtime_label.text = "---"; } }

When you save an annotation from the panel, these variables have to be updated and saved back to the object to which they relate—either a customData object or pngText depending on the current selection. As with what was done with getAnnotation, a setAnnotation in JavaScript is used to do this:

function setAnnotation(str){ if (fw.selection.length){ fw.selection[0].customData.Annotations = str; }else{ fw.getDocumentDOM().pngText.Annotations = str; } }

When you save an annotation, the annotation's text value is taken directly from its respective text in the panel. The user value is taken from the name set by the user. This is retrieved by the getUser() function, which I will cover later. The remaining variable, time, has the only dynamically generated value. The Date() function in Flash is used for this to provide a default output. If you want a different format, you could use a separate function for a custom date output in its place.

However, each of these values, when added to the variable string, needs to be properly encoded. This allows you not only to retrieve the values again later using a LoadVars object, but it also helps prevent complications when quote characters mess with the MMExecute command string by sending values from Flash ActionScript to Fireworks JavaScript. You could do this manually using the escape() function in Flash but it is much easier just to use the LoadVars instance FWVariables and have it URL-encode the variables for you using its toString() method.

After you save the annotation, the interface is updated with update to reflect the new values. The addEventListener method is used to associate the setAnnotation function with the clicking of the Save button:

function setAnnotation(){ var cmd = 'function setAnnotation(str){' +' if (fw.selection.length){' +' fw.selection[0].customData.Annotations = str;' +' }else{' +' fw.getDocumentDOM().pngText.Annotations = str;' +' }' +'}'; FWVariables.text = annotations_ta.text; FWVariables.user = getUser(); FWVariables.time = Date(); MMExecute(cmd); MMExecute('setAnnotation("' + FWVariables.toString() + '");'); update(); } save_button.addEventListener("click", setAnnotation);

Add the update, getAnnotation (ActionScript version), and setAnnotation (ActionScript version) functions to the Annotations FLA. You can publish and test it now in Fireworks but you won't see much of a result. This is because getAnnotation is not yet being called, so there is no way to see the annotations for any of your selected objects (or the document). At this point, about the best you can do is use the Command Prompt panel to check whether setAnnotation is, in fact, working (see Figure 9).

Using the Command Prompt panel to check annotations
Figure 9. Using the Command Prompt panel to check annotations

The setAnnotation function has a button that calls it. It's a little different with getAnnotation because it needs to be called whenever the selection changes in Fireworks. For that, you need to take advantage of Fireworks events.

Using Fireworks Events in Flash Panels

Panels in Fireworks are capable of receiving events from the Fireworks application indicating when certain things happen within the Fireworks application. These operate much in the same way as Stage.onResize, except that these events are specific to SWFs being used as Fireworks panels. Table 2 lists all events that are available to custom SWF panels in Fireworks 8.

Table 2. Custom SWF Panels in Fireworks 8
Property Description
onFwStartMovie Sent to the SWF file right after Fireworks starts (or restarts) the SWF file
onFwStopMovie Sent to the SWF file right before Fireworks stops the file (and possibly unloads it)
onFwUnitsChange Sent when the user changes the type of units (inches, pixels, centimeters) in the Info panel
onFwPICollapseOrExpand Sent when the user switches the Property inspector between two rows high and four rows high
onFwDocumentNameChange Sent when the name of the current document changes (for example, when the user performs a save)
onFwCurrentFrameChange Sent when the user selects a different frame
onFwCurrentLayerChange Sent when the user selects a different layer
onFwHistoryChange Sent when the user creates an non-scriptable history step
onFwIdle0 Sent when Fireworks is in the first of a sequence of idle states (because Fireworks may often go through a sequence of idle states, triggering functions by this event may impair application performance)
onFwIdle1 Sent when Fireworks is in the second of a sequence of idle states (because Fireworks may often go through a sequence of idle states, triggering functions by this event may impair application performance)
onFWIdle2 Sent when Fireworks is in the third of a sequence of idle states (because Fireworks may often go through a sequence of idle states, triggering functions by this event may impair application performance)
onFwApplicationDeactivate Sent when the Fireworks application loses focus
onFwApplicationActivate Sent when the Fireworks application gains focus
onFwSymbolLibraryChange Sent when the symbol library changes in some way
onFwURLListChange Sent when a new URL is added to the document
onFwFavoritesChange Sent when the favorite URLs list is modified
onFwPreferencesChange Sent when the preferences are changed (called when the user clicks OK in the Preferences dialog box)
onFwDocumentOpen Sent when the document is opened
onFwDocumentClosed Sent when the document is closed
onFwDocumentSave Sent when a save action is performed in the document
onFwDocumentSizeChange Sent when the document is resized
onFwActiveViewChange Sent when the active view changes (when the user changes focus in 2-Up or 4-Up view)
onFwPixelSelectionChange Sent when the pixel selection changes
onFwActiveSelectionChange Sent when the selection changes in a document
onFwActiveDocumentChange Sent when the user creates a new document, closes a document, opens a document, or switches between open documents
onFwActiveToolParamsChange Sent when the user changes the tool stroke or fill attributes
onFwActiveToolChange Sent when the user changes tools (a fwActiveToolForSWFs property is added to _root indicating the current tool when this event is used)
onFwZoomChange Sent when the zoom setting for the current document changes
onFwObjectSettingChange Sent when a stroke or fill setting is changed for the selected object

Note: Some bugs still exist with a few of these events. The onFwHistoryChange, onFwObjectSettingChange, and onFwPixelSelectionChange events, for example, are unreliable. Also be aware that certain events like onFwURLListChange and onFwFavoritesChange often fire twice in a row when they respond to the event in which they are associated.

A SWF panel does not automatically receive all of these events; it needs to register for the events it intends to use. This mostly automatic process simply requires you to create an event handler for each event desired in first frame of the main Timeline, defined either in the _root or the _global objects. Fireworks scans the SWF when it is first loaded looking at all the functions in _root and _global. When it finds functions it recognizes as being event handlers, it registers the panel to receive those events. For example, if you wanted a custom panel to play a sound whenever you close a document, you might define the following in the main Timeline of your custom panel movie:

function onFwDocumentClose(){ var vo = new Sound(this); vo.attachSound("IHopeYouSaved.wav"); vo.start(); }

The Annotations panel uses events to recognize when a selection has changed so it can display annotations that relate to the current selection (or the main document if there is no selection). For this, the onFwActiveSelectionChange event is used because it indicates when the selection changes in Fireworks. When it's called, the Annotations panel simply needs to retrieve the annotation based on the current selection.

There is a catch, however. Certain operations in Fireworks—namely editing text and using the transform tools—continuously update the selection, invoking frequent onFwActiveSelectionChange events. The problem with this is that executing any kind of JavaScript command during these particular operations prevents those operations from working correctly.

Preventing Commands from Disrupting the Selection

Fireworks requires a JavaScript command's full attention when it is being executed. This means that Fireworks may drop whatever it's currently doing and change its focus to the command you're executing. This fact becomes important in two cases: when editing a text object and using the transform tool.

Calling a command while editing a text object can result in prematurely deselecting the text. Calling a command while using a transform tool (scale, skew, or distort) will lose the transformation selection, preventing additional transformations from occurring. These are obviously undesirable effects. Given that editing text and transforming a selection invokes the onFwActiveSelectionChange event, steps are required to prevent commands from being executed during these circumstances.

So what can you do? How about checking to see which tool is being used and then preventing commands from being called whenever it's the text tool or a transform tool? Although this is a great idea, the conventional means for obtaining the active tool in Fireworks is by none other than a command:

var activeTool = MMExecute("fw.activeTool");

And yet the whole point is not to run any commands at all.

Thankfully there is a workaround for this issue. When Fireworks recognizes an onFwActiveToolChange event handler defined for a SWF panel, it sets a variable in the main Timeline called onFwActiveToolChange, which Fireworks updates automatically as tools in Fireworks change:

var onFwActiveToolChange; onFwActiveToolChange = function(){}

No JavaScript code is required in onFwActiveToolChange to make this work because it's all handled internally. The automatic fwActiveToolForSWFs variable provides the current tool's name as a string for you. Those relating to the text and transform tools in the English version of Fireworks include: "Text", "Scale", "Skew", and "Distort".

Bear in mind that these do change depending on the language of your Fireworks installation. You may need to take that into consideration when developing your panel. You can determine the current language using Files.getLanguageDirectory().

Now, to assure that the Annotations panel updates its selection without interrupting element transformations or text editing (assuming an English installation of Fireworks), you can use the following:

function onFwActiveSelectionChange(){ if (fwActiveToolForSWFs != "Text" && fwActiveToolForSWFs != "Scale" && fwActiveToolForSWFs != "Skew" && fwActiveToolForSWFs != "Distort"){ getAnnotation(); } }

Some other events might be useful for checking for a change in selection. One would be the onFwActiveDocumentChange event. This event is fired when you switch the view in Fireworks to another document.

Instead of repeating the code used in onFwActiveSelectionChange, however, you can just call onFwActiveSelectionChange within onFwActiveDocumentChange:

var fwActiveToolForSWFs; function onFwActiveToolChange(){} function onFwActiveDocumentChange(){ onFwActiveSelectionChange(); }

Another event, onFwStartMovie, can be added to the list but can also include other startup functions such as onResize and setFaceColor:

function onFwStartMovie(){ onFwActiveSelectionChange(); setFaceColor(); onResize(); }

Include the new event handlers with the rest of the ActionScript for the panel, remembering to move onResize and setFaceColor into onFwStartMovie. Then publish it and test it in Fireworks. You should now be able to see the panel update with the correctly saved annotations text as you change selections within your Fireworks document (see Figure 10).

Annotations panel functioning with events
Figure 10. Annotations panel functioning with events

Saving Panel Preferences

Often a panel requires that data specific to the panel itself, such as panel preferences, be saved and accessible for later use. Unlike annotation text, this cannot be saved to a specific Fireworks document because documents come and go. You need to save it instead to something more concrete like Fireworks itself. The problem is that you cannot save anything to Fireworks as you can to a Fireworks document. You can, however, save files to a user's hard drive and store the information there (see Figure 11).

Fireworks panel using a text file to store data
Figure 11. Fireworks panel using a text file to store data

The Annotations panel does this for the user name. It allows the user name to be set just once, preventing the user from having to reset it each time the panel is reopened or Fireworks is restarted. Although this is the only information required by the Annotations panel, any number of preferences may be required for other panels you may decide to develop.

The easiest way to save data for a panel is to save a text file from a panel using the Fireworks JavaScript command fw.saveJsCommand(). This saves a JSF file with the content you specify in a location you specify.

You could also use the Files object in Fireworks to write to a text file. However, this can be a little more complicated to deal with; and you get mostly the same effect with saveJsCommand. You also have more control over the extension (saveJsCommand forces you to save a file with a JSF extension). In either case, you get a text file saved with a string of data of your choice.

You can save such a data file in just about any format you want: XML, URL-encoded variable strings, or even JavaScript commands. If you are saving for the purpose of retrieving through Flash later—as is the case with most custom panels—then using XML or a URL-encoded variable string is usually the way to go. Saving as a JavaScript command would be useful if you were actually saving a command—something that would use Fireworks JavaScript to execute (for example, the fw.runScript() command can be used to run external JSF files).

The format for the Annotations panel is just a URL-encoded variable string. Because a single, simple name is being stored, using XML would be overkill. There's no good reason why anyone would want to edit this file manually (an advantage of using XML) so a variable string will work just fine.

Note: Even though saveJsCommand saves text as a JSF file, Flash can still load and interpret the file as XML.

As the panel developer, you would want to create an initial data file that provides default values. You can place it in the same folder as the panel SWF. For the Annotations panel, call it Annotations_user.jsf. Its initial contents will be the variable string for the user value:

user=Anonymous

Where you decide to save this file is actually up to you; it doesn't have to exist with the SWF, but it's usually easier that way. Just bear in mind that if you are dealing with JSF or SWF files in either the Commands or Command Panels folders in Fireworks, they may be interpreted as real commands or panels.

In Flash, this variable is accessed whenever the panel starts. This would be handled within an onFwStartMovie event. A new LoadVars instance, FWUser, can then load the file and retrieve the user name, adding it to the panel interface. It is from this instance that the user name will also be retrieved when using getUser as seen previously in setAnnotation. Complimenting getUser and setUser functions are defined as well:

var FWUser = new LoadVars(); function setUser(name){ FWUser.user = name; user_label.text = "<b>User:</b> " + name; } function getUser(){ return FWUser.user; } FWUser.onLoad = function(success){ if (success && this.user){ setUser(this.user); }else{ setUser("Unknown"); } delete this.onLoad; } function onFwStartMovie(){ onFwActiveSelectionChange(); setFaceColor(); onResize(); FWUser.load("Annotations_user.jsf"); }

Create a Annotations_user.jsf file, if you haven't already, and update the Annotations FLA with the new code. When you publish it for Fireworks and test it, you should now see that the user indicates a name of "Anonymous" (see Figure 12). If there is a problem with the loading process, you might see "Unknown" instead.

Annotations panel loading the user name from a file
Figure 12. Annotations panel loading the user name from a file

To get the desired user name value from the actual Fireworks user, you can provide an input area in Flash. To make things easier, though, you can use a JavaScript prompt dialog box. The JavaScript prompt() command opens an input dialog box, which allows users to input a line of text that is then returned to the script as a string. For Flash, this can be easily accomplished using MMExecute. The Annotations panel uses prompt to get a name. When that name is retrieved, it is added to the interface and saved using saveJsCommand.

One thing about saveJsCommand is that, unlike the load method in the LoadVars class in Flash, it requires an absolute file path when saving. If none is provided, the file will be saved in the Fireworks Commands folder and misinterpreted as a usable, Fireworks command. Luckily, Fireworks provides variables in the fireworks (fw) object that specify folder locations within the Fireworks installation folder. The folder where the Annotations panel resides is the Command Panels folder. You can get its path using fw.appSwfCommandsDir.

Now you can make an editUser function that sets the user name and updates Annotations_user.jsf when the Edit button is clicked in the panel:

function editUser(){ var input = MMExecute('prompt("Set User Name:", unescape("' + escape(FWUser.user) + '"));'); if (input){ setUser(input); MMExecute('fw.saveJsCommand("' + FWUser.toString() + '", fw.appSwfCommandsDir + "/Annotations_user");'); } } edituser_button.addEventListener("click", editUser);

Take note how escape and unescape are used with prompt. This is necessary when dealing with user input and values being sent from Flash into a MMExecute command. This is because you can't be entirely sure what the user has provided. For example, adding a quote in a user name will break the command when it is added to the MMExecute string. Using escape in ActionScript gets rid of these problematic characters, while unescape in JavaScript restores the string to its original state so that it is presented to the user properly in the prompt dialog box.

With that, the Annotations panel should be basically complete. Save your file and publish it to generate the completed panel SWF for Fireworks (see Figure 13).

Annotations panel using a prompt dialog box to set the user name
Figure 13. Annotations panel using a prompt dialog box to set the user name

Tips for Finishing Your Panel

Once you finish developing your panel, you still have one more task to complete: testing. Hopefully you've been testing while you were working with the panel, but it doesn't hurt to give it one more solid run-through before submitting to absolute completion. Also, as you use the panel in practice, you may find the need for additional features. For example, the Annotations panel could benefit from a new label that indicates what element the current annotation is being displayed for. This would be especially useful when multiple elements are selected even though only one annotation is being displayed (the first in the selection). Are you up to implementing that?

The following section provide additional suggestions to help with your panel development, which were not relevant to the Annotations example.

Use the Style Guide for Panel Design

Macromedia provides a page for suggested Extension User Interface Guidelines. Although it's antiquated, it may be useful when designing your panels. It covers some useful guidelines, such as including a help button and brand placement or inserting a company logo.

Handle Large Fireworks JavaScript Commands in Flash

As you begin to deal with larger Fireworks JavaScript commands within Flash, commands can become increasingly harder to add or edit. Commands used throughout this tutorial were fairly small. They were added line by line as strings to a single ActionScript variable. That variable was then used with MMExecute. This can get cumbersome when you deal with larger scripts. There are a couple of alternatives, however.

One alternative is to keep your scripts in an external JSF file. That way when you use fw.runScript(), you can run that script as you would any other command. You just have to be sure to correctly reference your file.

If you don't like the dependency on external files, you can also keep your scripts in Flash in the form of text within a text field. This way, you can edit your script more easily without worrying about defining it to a variable, because it will be accessible from the text field's text property.

Use Flash Dialog Boxes

We used a JavaScript prompt to request a string from the user and set the user name in the Annotations panel. Other JavaScript dialog boxes like alerts, confirmations, and even a yes/no dialog box are also at your disposal. Sometimes, though, you may want more functionality out of a dialog box. You can create a custom dialog box using Flash.

Fireworks commands can consist of simple Fireworks JavaScript commands or Flash SWF commands. When a command is a SWF, it plays the SWF in a pop-up dialog box that acts much like a JavaScript prompt. From a panel, you can launch a SWF command using fw.runScript. Unlike dialog boxes like prompts, however, SWF commands (or should I say fw.runScript) will not provide a return value when they are called. Instead, you need to create a variable in Fireworks that provides a means for the SWF command to obtain information and return that information back to the calling script. For example:

dialogObject = "value"; fw.runScript("mydialog.swf"); returnValue = dialogObject;

When mydialog.swf runs, it accesses the values provided in the dialogObject property through JavaScript. It then alters that variable to provide what will be assigned to returnValue. Its value reflects all choices made by the user while the dialog box is active.

Note: SWF commands called in this manner do not receive Fireworks events like panels do.

Use a Shared Directory

For external files that act as panel resources, you may want to add them to a Shared folder within the Fireworks Configuration folder:

Fireworks 8/Configuration/Shared/[your name]/[panel name]/

For example, if I didn't include the Annotations_user.jsf file with the Annotations SWF file, I would put it in the following folder:

Fireworks 8/Configuration/Shared/senocular/Annotations/

Doing so makes sure that these files are out of the way and not interpreted as additional commands or panels.

Decode URL-Encoded Strings in JavaScript

Flash can easily decode URL-encoded strings with the LoadVars class. Fireworks JavaScript has no such class, however. If you need to encoded or decode variables in Fireworks, you can use something like the following code, which recreates the LoadVars object within JavaScript (not including the loading capabilities):

function LoadVars(){} LoadVars.prototype.decode = function(str){ var parts = str.split("&"); var sides; for (var prop in parts){ sides = parts[prop].split("="); if (sides.length > 1 && sides[0] != "encode" && sides[0] != "decode"){ this[sides[0]] = unescape(sides[1]); } } } LoadVars.prototype.encode = function(){ var str = ""; for (var prop in this){ if (prop != "encode" && prop != "decode"){ if (str) str += "&"; str += prop + "=" + this[prop]; } } return str; }

Where to Go from Here

Once you have successfully completed a panel and you're happy with what you got and want to share it with the world, the only thing left to do is distribute it. The best way to distribute an extension for Macromedia products, such as a Fireworks custom panel, is by distributing an MXP file to the Macromedia Extension Manager. An MXP file contains all the components of your extension along with instructions for the Extension Manager on how and where to install it.

More Like This

  • Industry trends in prototyping
  • Foundation Fireworks excerpts: Visual effects and extending Fireworks
  • Developing an effective Fireworks workflow
  • Prebuilt CSS templates in Fireworks
  • Exporting CSS with Fireworks CS4
  • Exploring the Demo Current Document command in Fireworks CS3
  • Designing for mobile devices using Fireworks CS4
  • Creating standards-compliant web designs with Fireworks CS4
  • Designing and prototyping Flex applications using Fireworks
  • Creating an icon in Fireworks

Tutorials & Samples

Tutorials

  • Creating jQuery Mobile website themes in Fireworks
  • Extracting CSS properties from Fireworks design objects
  • Working with CSS sprites in Fireworks CS6

Samples

  • Twitter Trends
  • Flex 4.5 reference applications
  • Mobile Trader Flex app on Android Market

Fireworks Forum

More
04/19/2012 How to center multiple text in a button
04/22/2012 What exactly needs to be done to have my browser output text into a path that the user cannot type..
04/21/2012 Website Ranking
04/20/2012 Link problem with Fireworks CS5 - net::ERR_FILE_NOT_FOUND

Fireworks Cookbooks

More
09/07/2011 How do I use FXG XML markup in Shape subclasses?
10/15/2010 Flex4 Dotted Line
06/25/2010 ComboBox that uses a NativeMenu (Air API)
05/21/2010 Localizing a Creative Suite 5 extension

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