When someone asks you 'How did you do that?', you know you've done something right :)
This article will show you how to:
If you have to make a visual simulation of something in your gadget, you
probably need a lot of elements. To make it realistic, they're also
likely to disappear at some point (only to realize that sometimes new
ones will appear). Now how should you cope with that? In a gadget i
needed 30 small images to be able to generate a nice looking wave signal
(like in the image).
The final effect would have to be that of 30 lines of code, each of them
creating an <img> object, as shown in the first column.
Final effect, but not necessarily what you have to type:
<img name ="point1" src="point.png" /> <img name ="point2" src="point.png" /> ... <img name ="point30" src="point.png" />
An easier way to do it..
for (i=1;i<=30;i++)
view.appendElement("<img name='point"+i+"' src='point.png' />");
Other cool things the appendElement method opens up:
for (i=1;i<=30;i++)
view.appendElement("<img name='point"+i+"' src='point.png' x='50+"+(5*i)+"' y='"+(i%2==0)?"1":"-1"+"'>
//The (i%2==0)?"1":"-1" part just returns the character "1"
//if the condition is true (i is even) and "-1" if it's false.
var points=new Array();
for (i=1;i<=30;i++)
points[i]=view.appendElement("<img name='point"+i+"' src='point.png' x='50' y='"+(i%2==0)?"1":"-1"+"'>/");
Now you can read/write all the
properties and call all the element's methods, like this:
alert(points[3].y);
insertElement (which enables you to choose the
actual place in the XML you want new stuff to be added) and
removeElement. Also, all the presented methods are supported by the
<div> object as well, so the XML shouldn't keep any more
secrets :)
You have a lot of events at your disposal in the Google Desktop API.
Among them : onclick, onmouseover, onmouseout
etc., relative to the mouse, and onkeypress, onkeydown,
onkeyup etc., relative to the keyboard. These are triggered
when and where something happens, but sometimes we also need to know
exactly what happened :)
The event object is there precisely to give us such information.
It doesn't seem seem very important at a first glance, but it's a tool
which enables a natural response from a gadget. Sometimes we don't
realize how fond we are on pressing the Return key after we enter a
query in a search box (because something sets the search button as
default so we don't have to click it) or on dragging things on a virtual
surface just as we would in reality.
Have a look at how i made the run box from the gadget in the image. It
basically involves assigning a function to the onkeypress event
of the <edit> object and then just using the data provided
by event:
//in main.js
function KeyPressed(){
if (event.keyCode==13) ReturnKey()
}
function ReturnKey(){
if (runBox.value=="")
runBox.value="Type here to run";
else
o.Run(runBox.value)
}
//in main.xml <edit name="runBox" x="44" y="198" width="108" height="13" font="Arial" size="7" value="Type here to run" onkeypress="KeyPressed();" />
As i'm writing this, i'm also working on a gadget which lets you drag stuff
over a map. All i needed to do was assign the function below to a div's
onmousemove event.
function UpdateMapUI(){
if (ActiveBall!=null) {
ActiveBall.x=event.x;
ActiveBall.y=event.y;
}
}
Also, event.button and event.srcElement can prove to be very
useful. The first returns which mouse button has been (or is being) pressed,
and the second returns the actual element on which the function was triggered
(so you can do, for example, alert(event.srcElement.x+'
'+event.srcElement.y) to find out the element's
position). So the event object is definitely worth taking a look
at.
Space can become a problem if you keep adding features, especially if they're closely related to the gadget's main feature. For example, gadgets which have to do with time have some features that come hand in hand, like time and date.
A good way to deal with this issue (besides using different faces depending on whether the gadget is in the sidebar or not) is a menu, like shown below in the Ticker for Trekkers gadget:
Here's a snippet of the code used to generate this menu (some of the objects and variables had been previously defined, but it's important to notice the types of menu items you can create):
// Custom plugin context menu
pluginHelper.onAddCustomMenuItems = MAIN_menuAddCustomItems;
...
/*
* Handler that generates the gadget's context menu.
*
* @param {Object} menu Menu object provided by Google Desktop
*/
function MAIN_menuAddCustomItems(menu) {
var menuDateType = menu.AddPopup(strings.MENU_DATE_TYPE);
var sd_type = options.GetValue('sd_type');
for(var i = 0; i < STARDATE_TRAITS.length; i++) {
menuDateType.AddItem(STARDATE_TRAITS[i].name,
(sd_type == i) ? gddMenuItemFlagChecked : 0,
// Force closure to reference a copy of the _current_ i
MAIN_createOptionSetter('sd_type', i));
}
menu.AddItem('', 0x800 /* MF_SEPARATOR */, null);
menu.AddItem(strings.MENU_WITH_ISSUE,
options.GetValue('sd_with_issue') ? gddMenuItemFlagChecked : 0,
MAIN_createOptionSetter('sd_with_issue',
!options.GetValue('sd_with_issue')));
menu.AddItem(strings.MENU_WITH_TIME,
options.GetValue('sd_with_time') ? gddMenuItemFlagChecked : 0,
MAIN_createOptionSetter('sd_with_time',
!options.GetValue('sd_with_time')));
menu.AddItem('', 0x800 /* MF_SEPARATOR */, null);
menu.AddItem(strings.MENU_GOOGLE_SEARCH, 0, function () {
new ActiveXObject('WScript.Shell').
Run('http://www.google.com/intl/xx-klingon/');
} );
}
So, you can create normal menu items (with menu.AddItem(...) ), checked
items (in conjunction with the gddMenuItemFlagChecked flag), disabled items (in conjunction with the
gddMenuItemFlagGrayed flag) and submenus (with menu.AddPopup(...) )
Another way to keep the interface uncluttered is to consider 2 possible
scenarios: the user is happy with the present settings, or he/she wants to
change them. In order to do that the mouse has to be moved over the gadget but
with the help of the onmouseover and onmouseout events we can
make the gadget sensitive to that.
You can see that my DigiWatch gadget shows the time and the date all the
time. That's its main function (first image). But when the mouse hovers over
it (second image), it chooses to make the date invisible since it's less
likely to change when you're looking at it :) and shows several other
controls to help you customize the gadget, like a 24h/AmPm button, Help,
Alarm and others.. That's why it's also very important not to forget about
tooltips. It's a great way to give information about an element in the
gadget - it has the advantage of appearing only when the user expects it.
All these things aren't mandatory for a gadget, but they have the rare
quality of improving the program behavior while making the developer's life
easier :) So that's why, if you find yourself in one of these situations, i
kindly recommend the presented solutions. I'm a natural born programmer. My first contact with a techno-gadget was Star Trek. Remember those cool sensors?
I used to fill up a whole room with drawings of them when i was only 3 years old.
Generally, i could find a lot of inspiration for intuitive interfaces (to keep the article in mind) in other things which have 'star' in their names too (like Star Wars, Stargate :-) .
I like that border between interface and functionality - it's what makes most of a program, i think.
Anyway, i'm a software engineering student now, and you can see more of what i'm up to, thoughts or new gadgets at my website.
Many gadgets, everyone!
Resources
Author Bio