How We Did It
We built the Solar-Viewer widget using the Widget Creation Script for Photoshop CS. Our designer Kemper created the look for the widget in Photoshop. He then used the Widget Creation Script(a plugin for Photoshop) to convert the .PSD into a widget. Yep, it actually converts your photoshop file into a working widget. So we took this:
And we got this:
The really cool thing is that it scrapes your layers and converts them to PNGs and it also creates a .kon file with all of the elements defined. For those new to widgets a .kon contains the main code for the widget. It is an xml file that looks like this:
<?xml version="1.0" encoding="macintosh"?> <widget version="1.0" minimumVersion="2.0"> <debug>off</debug> <!-- Solar-Viewer Written by: Ideum Generated by Photoshop Widget Generator Script Copyright (C) 2004 - 2005 Pixoria, Inc. All Rights Reserved. Any modifications will be lost if the generation script is run again. --> <window title="Solar Viewer"> <name>mainWindow</name> <width>616</width> <height>404</height> <visible>1</visible> <shadow>1</shadow> </window> <image xsrc="Resources/aurora.png" mce_src="Resources/aurora.png"> <name>aurora</name> <hOffset>3</hOffset> <vOffset>3</vOffset> <width>609</width> <height>397</height> <opacity>100%</opacity> </image>
Note: A widget is simply a group of files saved as a package. You can easily look at the source code of widgets by either right clicking on them and selecting “Show Package Contents”? (OSX) or by changing the file extension to .zip and then opening the zip file (Windows).
After the conversion, each layer of the photoshop is referenced in the .kon file as an xml element. The script correctly placed and sized the layer in the widget using <hOffset>, <vOffset>, <width>, and <height> properties of the <image> element — again, too cool!
<image xsrc="resources/full_image.png" mce_src="resources/full_image.png"> <name>fullimage</name> <hOffset>286</hOffset> <vOffset>58</vOffset> <width>314</width> <height>315</height> <opacity>100%</opacity> </image>
The source of the image is also defined. The sources for the images were placed in a folder called resources. One thing we learned is to be careful with your naming conventions. The script will name the widget elements just as you have your layers named, so make sure you name your layers in a meaningful manner.
fullimage.src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_eit_171_512.jpg" mce_src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_eit_171_512.jpg";
So all I did was set the source of the placeholder image to the url of the image. I used the “onload”? trigger of the element to trigger the load all of the images. To load the images I simply changed the source of their respected placeholder:
<action trigger="onload"> img01.src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_eit_171_65.jpg" mce_src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_eit_171_65.jpg"; img02.src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_eit_195_65.jpg" mce_src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_eit_195_65.jpg"; img03.src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_eit_284_65.jpg" mce_src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_eit_284_65.jpg"; img04.src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_eit_304_65.jpg" mce_src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_eit_304_65.jpg"; img05.src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_LASCOc2_65.jpg" mce_src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_LASCOc2_65.jpg"; img06.src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_LASCOc3_65.jpg" mce_src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_LASCOc3_65.jpg"; img07.src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_trace_171_65.jpg" mce_src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_trace_171_65.jpg"; img08.src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_bbso_white_65.jpg" mce_src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_bbso_white_65.jpg"; img09.src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_bbso_halpha_65.jpg" mce_src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_bbso_halpha_65.jpg"; </action>
Next, we needed to allow the users to select a thumbnail image and have a larger version of the thumbnail be displayed. At the same time a description of the image needed to be displayed. We used the <onMouseUp> event for the image element to trigger a change in the source of the full size image.
<image xsrc="Resources/img09.png" mce_src="Resources/img09.png" > <name>img09</name> <hOffset>198</hOffset> <vOffset>208</vOffset> <width>66</width> <height>66</height> <opacity>100%</opacity> <onMouseUp> fullimage.src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_bbso_halpha_512.jpg"; description.data = filesystem.readFile("Resources/ image09.txt"); </onMouseUp> </image>
To display the text we created a <textarea> element and placed it over a graphical placeholder. The data property of the <textarea> element was changed on the same event that triggered the main image change. The data is pulled from text files located in the resources folder using the filesystem.readFile() function. We included the text files with in the widget because the original files had HTML in them and, unless you do some scripting a widget can not render HTML.
Along the same lines we used two other mouse events, <onMouseEnter> and <onMouseExit> to turn on and off an image that creates the rollover state:
<image xsrc="Resources/img09.png" mce_src="Resources/img09.png"> <name>img09</name> <hOffset>198</hOffset> <vOffset>208</vOffset> <width>66</width> <height>66</height> <opacity>100%</opacity> <onMouseEnter> glow09.visible = true; </onMouseEnter> <onMouseUp> fullimage.src="http://ds9.ssl.berkeley.edu/imageviewer/ images/images2/latest_bbso_halpha_512.jpg"; description.data = filesystem.readFile("Resources/image09.txt"); </onMouseUp> <onMouseExit> glow09.visible = false; </onMouseExit> </image>
The last major piece of functionality was to have the widget update the images every hour and display when the last update was. We used another element called <timer> to accomplish this. The <timer> was set to run every 3600 seconds (60 minutes) and when it ran, it triggered the <onTimerFired> element nested with the <timer>. On that trigger all of the code was run within the <onTimerFired> element:
<timer name="mainTimer" interval="3600" ticking="true"> <onTimerFired> theHour = String(theDate.getHours()); time.data = "Reloading images..."; img01.reload(); img02.reload(); img03.reload(); img04.reload(); img05.reload(); img06.reload(); img07.reload(); img08.reload(); img09.reload(); fullimage.reload(); time.data = "Updated today at: " + theHour + ":00"; </onTimerFired> </timer>
The code reloads the images (you can not just change their source, they have to be reloaded) and sets the data of an additional <text> element that displays our last update message.
I hope this gives you a good overview of how we built the Solar-Viewer widget. We will be making a Mac widget version of this soon and I will write up a description of how we built that as soon as we are done.