-
Notifications
You must be signed in to change notification settings - Fork 1
Architecture
The following is a overview of how the SUIT Canvas Toolkit is set up and organized into sections, and how drawing and events are handled. Development is mainly based in the javascript/
folder where all of the JavaScript files are organized. Generally, each constructor object has its own JavaScript file. For example, each widget is in its own file to make sure everything is organized and that everyone can work on different parts of the toolkit without messing in the same file. Of course, these files need to be loaded in a specific order. A file named __dependencies__.json
is in the javascript/
folder which is used to help sort each file so it can be loaded in the right order.
The dependencies file is used to keep track of which JavaScript files depend on what, so that each file can be loaded in the right order. The format is JSON. It consists of a single JSON object where the keys represent a JavaScript file and the value of the key is an array of files that it depends on (or false
if it has no dependencies).
Here is an example:
{
"Foo": false,
"Bar": ["Foo"],
"Baz": ["Foo", "Baz"]
}
In this example, Foo.js
will be one of the files that is loaded before anything else, because it has no dependencies. Notice how the file extension is left out. Next, Bar.js
depends on only Foo.js
, so that is loaded next. And finally, Baz.js
is loaded last since is depends on Foo.js
and Baz.js
to exist. There is PHP code which takes this information and outputs <script>
tags in the correct order. This should be ported to JavaScript later on.
To avoid problems with SUIT objects interfering with user-code, all SUIT objects are members of the suit
namespace. So to create a new Button
object, you would use new suit.Button();
This file initializes the suit
namespace object and defines some standard (and useful) functions which some browsers may not include. It defines:
-
Function.prototype.inherit
: SUIT function; returns an empty prototype object that inherits from the function's prototype chain -
Function.prototype.bind
: ECMAScript 5 function -
Array.isArray
: ECMAScript 5 function
To prevent mismatched code, all objects inherit from its parent the same way. This section describes that. First, the prototype needs to be created so that calls on the children call on the parent. This is done using the Function.prototype.inherit
function provided in SUIT.js
. Here is a quick, example usage:
suit.Widget.prototype = suit.Object.inherit();
Now, suit.Widget.prototype
is ready to append its own methods. Now this is not enough, as some object propertes need to be set from suit.Object
when it is constructed. To solve this, we use constructor stealing. Here is an example of how it works:
suit.Widget = function() {
suit.Object.call(this);
this.parent = null;
this.screen = null;
this.event_mask = suit.Event.None;
};
Notice the line with suit.Object.call(this);
. This makes sure that the properties that the suit.Object
constructor sets are set before the Widget construtor can apply its own properties. Last but not least, it may be necessesary to call add extra code to a method that an object inherits. The method may be overwritten in order to change the behavior of that function for the object. If that occurs, you can access the method directly from the prototype of the parent constructor. Here is an example:
suit.Widget.prototype.emit = function(signal) {
suit.log("This widget is about to emit a signal: '%s'", signal);
suit.Object.prototype.emit.call(this, signal);
suit.log("This widget emitted a signal: '%s'", signal);
};
Now when you call the normal emit
method on an object, if it is a widget, you will get logging info as well as the normal operation inherited from suit.Object
.
Widgets are a necessary feature in any widget toolkit. suit.Widget
is an abstract constructor that is not created directly. They are only used to inherit from. Any constructor that inherits from suit.Widget
must implement the following functions:
- draw(context)
- get_request_mode()
- get_preferred_width()
- get_preferred_height()
- get_preferred_width_for_height()
- get_preferred_height_for_width()
For a bare-minimum widget, you need to implement functions that state what your widget looks like, and what size you want it to be.
You can't talk about widgets unless you talk about widget containers as well. Containers are used to lay out children or provide some functionality that require widgets to be its children. suit.Container
is also abstract and it inherits from suit.Widget
. Instead of creating a new suit.Container();
directly, you create one of its subclasses.
This section describes how the widgets are drawn. When a widget requests to be re-drawn (using queue_redraw()
), it notifies the Screen object that widget X needs to be redrawn (it has changed it appearence). Then, when it can, Screen clips drawing to the widget's allocation and calls the draw
method on the widget with a passed suit.Graphics
to render to. The widget then does it thing. When that is complete, Screen does the process all over again for the widget's children (if it has any).
This is a little more complicated and I'm too tired to really explain all the way (at this moment), but basically when a layout container gets a new allocation, gets notified that one if its children needs to be resized, or when its list of children changes, it goes through each children and asks what size it wants to be (or prefers to be). It then calculates this up and gives allocations to its children.