mac emulation resources
mac emulation forums

01
Jan

A Widget’s Tutorial

author alang

This tutorial will give you a kick start on creating and programming your own widgets – an idea that might occur to you once you have seen the variety of available widgets in action – either by alteration of existing widgets or by starting from scratch.

Getting Started

Tools needed:

  • A simple text editor – either Notepad or WordPad will suffice
  • A drawing program – the GIMP would be capable of creating PNG images with per pixel translucency
  • Acrobat Reader for reading the Konfabulator reference manual
  • Patience, and lots of it – I am starting with very low-level stuff and will be going into deep details so be patient with me

Prerequisites to understanding this tutorial:

  • Very basic programming experience; really, any language will do
  • Some very basic ability to understand how web pages are built
  • Some math, but nothing as complicated as sine and cosine stuff

XML

What is XML? XML is basically another SGML derived markup language like HTML. Markup languages aren’t programming languages but a convenient compromise between human and computer readable declarations: A human can read, understand and edit these files with simple tools because they are not binary, and a machine can parse and process them pretty quickly – so they are the ideal vessel to transport large descriptions like user interfaces, web pages and the like. XML is different from HTML and SGML in that it has to be well formed:

this is italic and italic bold.- well formed markup herethis is italic and italic bold.

- not well formed markup

The above could also be viewed as a tree structure like you would know of Windows Explorer’s folder view:

You see that the second line can’t possibly be represented as a tree since the opening and closing tags of bold and talics are intertwined; while this markup would be legal HTML, it would be rejected by any XML parser.

Look at this example:

Some content here

Here, we have three nodes that all have a name attribute; the node named “Wilma” even has “some content” and is together with its sibling “Barney” a child to “Fred.” It might not make sense at the moment, but from the perspective of a machine it is now very easy to fulfill user commands like: “get me the content of the node whose name attribute is ‘Wilma’ and whose parent node is named ‘Fred.’” Notice how Barney is self contained; Fred’s closing tag expands all the way around Barney and Wilma, who only spans around her “content”, which could also consist of more child nodes, have more uniquely named attributes… I hope you get the idea. XML is maintained by the W3C consortium and is still at version 1.0 and has seen three revisions since its first appearance back in November 1996. There is a lot more to know about XML but we’ll be covering the amount required by Konfabulator only and as soon as it comes in handy.

JavaScript

JavaScript is not Java scripted. Its actually a C/C++ based browser’s interpreter language invented by Netscape in the early days of the web and hence became a Standard at version 1.5, while a new version, 2.0, has been in the making for a very long time. Sometimes it is known as ECMA Script after the committee that now attends to it.

Konfabulator is frequently rumored to be built around a custom JavaScript engine - now what is so custom about its engine? Its actually good old SpiderMonkey, the original now open source JavaScript engine to be found in various browsers of the Netscape/Mozilla/Firefox family. It has thus helped in delivering gazillions of web pages since the dawn of the World Wide Web, and it’s still leaner and faster than its competing MS product, the Windows Scripting Host which is also employed by Internet Explorer and the IE-based breed of browsers. If you have been using vbScript and jScript on the Windows platform, you’ll surely hit some surprises. Firstly, the Netscape engine has no relationship to “ActiveX” or “Active Scripting.”

As such, it has no relation to platform dependent ActiveX scripting and a JS statement in the likes of:

var a = new ActivexObject(”ADO.Connection”);

is impossible by default, since being a MS “extension” to the standard; however, the browsers that use this engine can script various ActiveX controls on Windows so chances are good that Pixoria can find out how to open up an AppleScript equivalent for Windows users – until then, the engine remains sandboxed and limited to what it can shell out to the FreeBSD zsh command line interpreter and the various Unix utilities it provides – these aren’t documented in the Konfabulator reference, so if you seek that information, please go try any Linux or FreeBSD reference manual instead.

Another thing that any JavaScript coder with a HTML background should consider is that most of the objects that you are used to having around are just not available in Konfabulator’s object model since it is not a browser and has no notion of a “ document.all() ” or “ response.write(‘something’) ” ; however, application independent standard objects like “ Global ” and its sub-objects like “ Math ” are available. This implies that all so called client side DOM and named objects like “ Form ” , “ Document ” are not available, while objects such as “ Window ” and “ Image ” are completely redefined to Konfabulator’s needs.

GIMP - GNU Image Manipulation Program

The GIMP is the famous free, open source GNU Image Manipulation Program – I don’t do a GIMP tutorial here but consider this: Konfabulator shifts images around. It can do some text output and that’s about all – no line drawing, on canvas image or pixel manipulation or selecting a frame out or clip of a larger image as you might have been accustomed to by other widget engines. Sooner or later, you’ll need to do your own image manipulation – crop / scale / flood fill it with transparency at places Konfabulator won’t let you do with images you found on the web. Therefore, the Gimp is your friend – he may have his issues, look awfully non-Microsoft at first glance but he will never turn his back on you when you are ready to give him a chance. He reportedly can do almost everything that one would expect from big-wig imaging software like Adobe Illustrator, Quark X-Press, and others, but I can’t tell since I am not good at any of them.

Notepad vs. Write/Wordpad

If you open a Mac developed widget’s innards with Notepad, the text will look jagged. That is because of encoding differences that date back to computer stone age dot matrix printers. On the Mac/Unix, the single symbol LF (line feed) will store a return, while on MS-DOS and its descendants a pair of CR (Carriage Return) and LF will be needed – MS-DOS printer drivers were so dumb they needed to be told to turn the rolls up and the head return separately. Write/WordPad will understand both encodings, Notepad will not. If you still want to edit such a file with Notepad, open it with Write, click on File/Save As, and open the lower combo box to choose “text document – MS-DOS format” , click OK and you’re done. If you check that checkbox while MS-DOS is selected, Write will also stop getting on your nerves with about “lost formatting” every time you save. Use whatever editor you like but you may want to look for programmers’ editors that do automatic indentation after a curly brace followed by a, *cough*, line feed.

The Manual

Read it. Sleep with it. Give it a name. Read it again. Endure the latest Acrobat Reader bloat because of its superior search function. Steal some paper and ink to print it. Need to ask a question at the Konfabulator forums? Better read it again first, I mean it.

The Goal

Now let’s get our hands dirty – we’ll be doing a Cartman widget. South Park animations are easy enough to do so let’s get it on. We’ll need a Cartman.kon file with as little XML as possible and a Cartman.js with as much JavaScript as feasible, as well as a few images to be found on the web. For reasons of later zipping, the following folder structure would be needed, as well. In the test folder, we’ll open a “ name.widget ” folder for each project. This will need to be empty and have a Contents folder, where Cartman.kon and Cartman.js will be located and that will have a Resources subfolder. We could store all our images there as well as in Contents, but we want to be Mac compatible if we can. I also chose to open another Cartman subfolder just in case we wanted to do a more generalized South Park character – in that case we would add subfolders with the character names, store their personalized images there and do the switch in software.

The Preamble

Our Cartman.kon shall begin with the following lines:

on
This is a small widget to demonstrate
how to get things done in Konfabulator for Windows.
This is the declarative part that calls the code part.
–>

The first line contains the XML preamble – it’ll be always the same. You’ll see different encoding attributes here and there, but the Konfabulator XML parser doesn’t mind. Don’t put anything before this line, otherwise it isn’t valid XML.

In the second line, we specify our widget version and the required Konfabulator version – look what happens if I put a future version in it:

It’s a good idea to put a minimum version requirement to avoid incompatibilities with previous versions. Note that the tag encloses the entire XML here and needs a matching at the end of the file. During the development of the widget, we’ll have the debug console on.

The following comment isn’t processed in any way but by the eyes of anyone who opens the .kon file in a text editor – put anything here that you might want to tell, but keep in mind that “–>” inside the comment would invalidate the entire XML.

The Window

Konfabulator is, as stated before, an engine to shift images around, period. It also defines a rectangular area where your images can be shifted. It calls this place a window. You’ll need to declare at least one and at most one but one of it like this:

main_window
200
200
100%
1

The Title attribute can be omitted, but your widget would be seen as “Konfabulator-“ in task manager instead of “Konfabulator-Cartman Widget”. Another side effect would be blank menu items in the “Recent Widgets” and “Widget Preferences” submenus. The name attribute here is pure magic. As soon as you attach a name attribute to any Konfabulator object that supports it, be it inside the XML or in code, it will likely be accessible by code under that name. In the case of the window object, the following JS statement:

main_window.opacity=”50%”;

would dim the overall window object to 50% transparency – you can even change the title attribute at run time if you must.

Now lets have a background image attached:


body
200
200
0
0
left
255

On this image, we are going to draw eyes and mouth, so that our Cartman won’t be static all the time. However since we have a lot of eye and mouth images to look after, we’ll be loading them in code, not by XML declarations, so the body image will be the only one that is declared inside XML.

Before Getting into Code

The best time to pre-load our Eric Cartman’s facial expressions during widget load time – about to display but not yet visible. Konfabulator sports some events that can be tied to code that is either tied to an external script file or inside the node itself. What do we have here:

include(”cartman.js”);
var cman = new cartman();
print(”I’m done constructing!”);
–>

It’s my personal taste that I store as little code as possible into XML because of its strictness: it won’t tolerate “<” and “>” unless escaped as “<” and “>” or by embracing the entire code as a comment – if some XML guru suggests you to use the character data notation like in “”, just tell him that Konfabulator’s XML parser isn’t that modern.

On the above excerpt, I’m including an external script file, located in the Contents folder that defines a cartman object named cman, later more on this. After the object has been constructed, I log my success to the debug console.

Does this mean we’re done with the XML? Not yet: Bear with me while we add a single

and two other ’s:

slider
5
50The interval in which Cartman does his actions.

50
cman.mouseUp(); –>

// myWackyTimer.interval = myInterval.value;
cman.doRange();

Now our declarative part has ended. What has happened here?

  • There’s a new slider in the preferences dialog that doesn’t show off very well, but gives an interval from 5 to 50, that defaults to 50.
  • There’s the remnant of an onMouseUp action that has been commented out. It is going to be our testing booth and be uncommented on demand.
  • There’s an onTimer action that’s named myWackyTimer and fires every 5 seconds just to call a doFace method of our newly created cman object. It features a name attribute that expectedly does not work.
  • There’s an onPreferencesChanged action that shows a pathetic try to extend the aforesaid name attribute magic and utterly fails. Just uncomment the first line and see – Konfabulator neither allows adding more timers nor does it allow you to change its interval – the first breach of the otherwise so wonderful object model.

On To The Code

As it has been said, we’re going to construct a Cartman object – more out of cosmetic considerations, since we don’t need to have a bunch of loosely coupled functions and variables if we can bundle them into a single entity. One of the benefits of the JavaScript language is its object system. Objects aren’t declared like in C++ with a class statement, they are created whenever needed, variables and functions attached and detached at any time, not only declared at compile time. We could have added routines to the widget object instead, extended the Math object or have the C-coders messy function salad, it’s all up to your personal tastes. Meanwhile, we have a number of images ready to show – just the eyes and mouths screenshot and made transparent from the online Create-Your-Own South Park character flash game…

Inside cartman.js, we first do a multi line comment to watermark our vicinity:

/*
This is a small widget to demonstrate
how to get things done in Konfabulator for Windows.This is the code part that is called from the .kon file handlers.
*/

After this has been so simple, we’ll do our Cartman object’s constructor. A what? Well, a constructor is the part that is called when you issue a function call like “var cman = new cartman();” – we’ll fill the parenthesis with some life as follows:

function cartman() // constructor
{
print(”I’m constructing!”);
this.eyes = new Array();
this.eyes_name = “blink,closed,drowsy,normal,hng”;
this.eyes_name = this.eyes_name.split(”,”);
var root = “Resources/Cartman/eyes_”;
for( i=0; i < 5; i++ )
{
this.eyes[i] = new Image();
this.eyes[i].src = root + this.eyes_name[i] + “.png";
this.eyes[i].opacity=0;
this.eyes[i].alignment="center";
this.eyes[i].hOffset=108;
this.eyes[i].vOffset=52;
this.eyes[i].width = this.eyes[i].srcWidth * 0.7;
this.eyes[i].height = this.eyes[i].srcHeight * 0.7;
print( “Dynamically loaded Image: ” + this.eyes[i].src);
}
this.eyes[3].opacity = 255;
print("I’m somehow done constructing!");
}

What’s happening here?

  • A comment is written to the debug window.
  • An Array object is constructed. This array will store the image objects associated with the eyes. Note how the “this” keyword precedes the variable – it means that eyes now belongs to the newly created cartman object. All further access to the eyes array will also need the preceding “this”.
  • A string object is constructed and initialized.
  • The string object is turned into an array of five names.
  • A local string object is constructed and initialized.
  • A loop over 5 steps from 0 to 4 is being started – i is the counter
    1. The arrays i’th element is created as a new image – you can add objects to an array by simply accessing them – no boundary overflow, ever.
    2. The src attribute of the image object is set to a path to the ith of our stock eye images and thus loaded
    3. The image is made invisible
    4. Moved horizontally
    5. Moved vertically
    6. Scaled horizontally to 70%
    7. Scaled vertically to 70%
    8. Success and image location is being written to the debug window.
  • eyes_normal is being made visible since it is our starter eye
  • End of constructor message is being written to the debug window.

So far, we have a bold background, a correctly positioned pair of normal eyes on top of it and nothing happens. So, why did we endure such pain with a for loop and instead of just added those five images one by one? Imagine we had to do another 20 expressions, perform a switch to Kyle or so, then we would just extract these few lines into a more generalized and versatile AnimStrip object – another benefit is that our method of pulling one of these up front is now simpler to do, so let’s now add the doFace function to our cartman object:

prototype.doFace = function()
{
i = Math.round(Math.random()*4);
this.eyes[3].opacity = 0;
this.eyes[i].opacity = 255;
sleep(500);
this.eyes[i].opacity = 0;
this.eyes[3].opacity = 255;
}

What are we doing here?

  1. We declare a function named doFace that is a member of a cartman object. Note the usage of prototype here – if we just declared a function like the constructor and have it attached to cartman afterwards, it would have no notion of all the variables attached to this.
  2. We let JavaScript randomize a number between 0.0 and 4.0, since it could return, for example, 2.2 too, we let it have trimmed to full numbers.
  3. We hide the image object that corresponds to eyes_normal.png by accessing our “eyes” array by the “this” keyword.
  4. We make an image visible whose index in the array we just randomized.
  5. We send the entire JavaScript runtime to a 500 millisecond sleep. That’s about the time to blink an eye.
  6. We hide the randomized image.
  7. We restore the default eyes.

Now Cartman blinks his eyes every five seconds. Could he be made to smile (rather untypical)? Lets see how we can do this. Let’s have a smile object all by itself:

function cartman() // constructor
{
// unchanged code omitted for brevity:
this.eyes[3].opacity = 255;
this.smile = new Image;
this.smile.src = “Resources/Cartman/mouth_smile.png”;
this.smile.opacity=0;
this.smile.alignment=”center”;
this.smile.hOffset=110;

this.smile.vOffset=90; print(”I’m somehow done constructing!”);
}

New smile code in red. Also, our timer driven randomizer code needs to take a break if the smile is to go in sync with a selected eye:

cartman.prototype.doFace = function()
{
i = Math.round(Math.random()*4);
isSmile = (i == 4);
this.eyes[3].opacity = 0;
this.eyes[i].opacity = 255;
if( isSmile )
{
this.smile.opacity = 255;
sleep(1500);
}
else

sleep(500);
this.eyes[i].opacity = 0;
this.eyes[3].opacity = 255;
if( isSmile )
this.smile.opacity = 0;

}

Altered code in red again. What have we done here?

  1. The new isSmile variable now holds a Boolean; if i is 4, it evaluates to True, otherwise to False.
  2. Our first if clause: if our Cartman has to smile, then
    1. The smile image gets visible
    2. A smile takes longer than a blink.
  3. Otherwise
    1. We sleep the usual blink duration.
  4. Our second if clause after we restored the usual looks:
    1. Hide the smile image.

Summary

Our Cartman has started showing some signs of life. He blinks occasionally, and yet, he’s still boringly static. In the next installment, we’ll dig further into the object oriented aspects of JavaScript and have our Cartman speak his most famous sentence, wiggle his head and more – stay tuned.

Files for this Project

Contributor Profile

Herd is a 35 year old professional freelance programmer in the German automation industry. If he is not reading in his collection of 300 SciFi books, he enjoys himself coding aqua apps and menacing the south of Hessen with his rusty motorcycle. His girlfriend thinks he should spend less time on the Aqua emu boards.

Notes : This articles is originally written by Herd and published on AquaXP, republish on osx-e.com Articles section with permission.


Comments »

No comments yet.

Name (required)
E-mail (required - never shown publicly)
URI
Your Comment (smaller size | larger size)
You may use <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> in your comment.