Keywords: SVG, User Interfaces, XSLT, CSS, Graphical Stylesheet
Biography
Alastair Fettes is currently in his final year of Computer Engineering at the University of Victoria will graduate in April of 2005. Alastair is a major contributor to the SPARK project (http://www.schemasoft.org) to create an open source SVG based user interface framework. He enjoys many physical activities including rollerblading, skateboarding, soccer, ultimate and frisbee golf.
Biography
After receiving his Ph.D. in Mathematical Physics from Yale University in 1989, Philip spent a year as Assistant Professor of Physics at Knox College, followed by four years as Assistant Professor of Mathematics at the University of Toronto. His background in Differential Geometry and in computer modelling of physical phenomena served as unorthodox preparation for his subsequent move into industry as a Software Engineer with an emphasis on Computer Graphics. By 1997 Philip was in charge of a software research team creating early Web technologies based on HTML, XML, CSS and Java. Philip now lives and works in Vancouver, Canada, where he is President of SchemaSoft (http://www.schemasoft.com/), a software development consulting company he co-founded in 1999. He is an Advisory Committee Representative of the World Wide Web Consortium (http://www.w3.org/), has been a member of the W3C Scalable Vector Graphics Working Group (http://www.w3.org/Graphics/SVG/) since its inception in 1998, and was chief organizer of the SVG Open 2003 conference (http://www.svgopen.org/2003/). Philip is Chair of the BC Advanced Systems Institute International Scientific Advisory Board (http://www.asi.bc.ca/). He is also a Director of the Vancouver XML Developers Association (http://www.vanx.org/), an organization that he co-founded in 2000. He regularly writes and lectures on topics related to software engineering, XML and SVG.
The purpose of the SPARK project is to create a flexible, interoperable SVG-based user interface framework. Using well established and standardized languages including SVG, XML, Java and IDL, we went about creating a framework that could easily be used by others to rapidly develop SVG based applications or prototypes.
This project was approached as a full software engineering system architecture project. After the initial proposal the project went through a risk analysis phase to decide upon the main goals to be completed throughout the term. After the risks had been analyzed and mitigation strategies had been created, the design entered the design stage.
The design stage consisted of a number of smaller iterations. First a set of class diagrams were created. During the creation a number of design patterns were selected that would best solve many of the interoperability risks that were discovered in the risk analysis stage. The class diagrams themselves were fluid and continually updated once architecture problems had been discovered. A helpful step that was done during the creation of the class diagrams was to create Interface Definition Language (IDL) files for each of the modules. This once again was used to give us a better perspective on how the classes would work together.
Once the initial class diagrams had been created the process of creating the different interfaces and classes began. It was decided to write these in the Java programming language even though the final target language was ECMAScript. The reason for this is that ECMAScript does not support true object oriented programming. Classes in ECMAScript are not so much classes as methods (functions) with attributes and their own functions. ECMAScript also does not support interfaces and can be very hard to understand the relationship between classes. Therefore the entire framework was created in a rough draft using Java. A side benefit of this process was the ability to produce JavaDoc documentation for the framework from these completed class files.
During the design stage of the project lifecycle widgets and applications were made throughout to test the different aspects of the framework. Many problems were discovered during this prototype stage including a problem that was actually a duplicate of a problem created with the Java 1.1 language. Cascading Observer calls throughout the UI hierarchy added significant lag and efficiency reductions. It was from these trials that the final class diagram (listed within) was completed. After the widgets had been stabilized then applications could be created.
Unfortunately there were not a great number of applications created due to time limitations. On a side note a fellow by the name of Bernd Seidenspinner created his own application using an earlier version of the framework and emailed the demo to Alastair. This demonstration application was a significant example of how easy to use the UI framework was. The problems that Bernd noted had during development we had also noted and had already made steps to mitigate these problems. The fact that a great number of applications were not made is unfortunate however, the fact that someone in Germany was able to create their own application is a great testament to the flexibility and ease of use of the framework.
The final results of the project must be considered a success. An entire framework has been created and used by an individual on the other side of the world. Widgets and applications may be created independently and easily. The risks discovered during the risk analysis stage have all been mitigated and the resulting framework is complete.
1. Introduction
2. Project Risks and Goals
2.1 Cardinal Aims
2.2 Secondary Aims
2.3 Tertiary Aim
3. Patterns
3.1 Model-View-Controller
3.1.1 Model
3.1.2 View
3.1.3 Controller
3.2 Container
3.3 Observer
3.4 Command
3.5 Factory
3.6 Decorator
4. Framework
4.1 Overview
4.2 Interfaces
4.2.1 Observer and Subject
4.2.1.1 API Description
4.2.2 Command and Command Holder
4.2.2.1 API Description
4.2.3 SPARKFactory
4.2.3.1 API Description
4.3 Widget Class
4.3.1 SVG
4.3.2 API Description
4.4 Atom Class
4.4.1 SVG
4.4.2 API
4.5 Container Class
4.5.1 SVG
4.5.2 API Description
4.6 SPARK Class
4.6.1 API Description
4.7 Widgets Module Class Diagram
4.8 Widgets Module IDL Definitions
5. Skinning
5.1 Skinning With CSS
5.2 Skinning With XSLT
6. Framework Helpers
6.1 SPARKHelperFactory Class
6.1.1 API Description
6.2 SPARKHelperDecorator Class
6.2.1 API Description
6.3 Helper Module UML Diagram
6.4 Helper Module IDL Definitions
7. Future
7.1 Framework Development
7.1.1 Widgets
7.1.2 Skins
7.1.3 Applications
7.2 sXBL
7.3 Framework v2.0
8. Conclusion
Acknowledgements
Bibliography
The purpose of this project was to create a framework that describes a set of rules and techniques for creating SVG user interface widgets. The architecture describes the interfaces that the differently widget types must follow in order for the interoperability of the widgets.
There are two distinct yet intertwined sides of the framework - SVG (Scalable Vector Graphics) [SVG] and ECMAScript (European Computer Manufacturers Association Script) [ECMAScript] . The SVG describes the Model (data) and the View (visual) while the ECMAScript describes the controller. The SVG has been structured to a certain extend to enable interoperability while leaving it flexible enough such that UI (User Interface) developers may create visually stunning and impressive applications and have full control over the look and feel. Using CSS (Cascading Style Sheets) [CSS2] in conjunction with the SVG the UI developer has even more control over the visual representation of their application.
The following paper describes the process followed during the life cycle of the project and gives a detailed account of the final results.
This project has two main aims/goals. A failure to fulfill both these aims results in the failure of this project. They are as follows:
The aims are defined as:
From these two goals it is possible to construct a Cause-Effect tree:
From this Cause-Effect tree a number of other risks are deduced and are listed as secondary aims of the project.
The two major risks discovered during the risk analysis stage led to the discovery of a number of sub-risks that could result in project failure. These risks are listed as follows:
Therefore as these risks could result in project failure they then become secondary aims of the project. These secondary aims are then defined as follows:
Finally, in accordance with the W3C (World Wide Web Consortium) WAI (Web Accessibility Initiative) group the final goal of this project is to enable accessibility of applications created using the framework. Accessibility will not be strictly enforced though there will be guidelines in place to enable accessibility and attempt to lean the application developer towards creating accessible solutions.
The MVC (Model-View-Controller) architectural design pattern is a very useful, successful and widely used pattern. The idea is to separate the different parts of an application into three separate categories (layers):
There are a number of benefits from creating applications that follow this design pattern. It gives the programmer the ability to have multiple views of the same model. Another important result is code separation. Applications and components become easier to understand and fix as a change in the UI code does not affect other parts of the application. The net result of this is reduced bugs and fix times for application developers - a very important goal in any software project.
The framework uses the MVC pattern in two distinct ways: for widgets and for applications. Each widget defines its own Model, its own Controller and its own View. The application itself has its own View (the UI components), its own Controller (the logic that interacts with the components) and its own Model (state information and business logic).
The model defines the state information or business logic of the software component. The model by itself simply contains information about the application and its current state. For this project in particular it is used to store information about UI widgets. Examples include things such as if a button is on or off, the current value of a slider, etc. For the SVG based UI framework this is implemented through the metadata element and is described in detail later.
The view gives us the visual representation of the model. An MVC based application should enable the developer to change the view without effecting the functionality of the application. Of course there are limits and this statement should not be taken out of context. The direct correlation between this and the SVG-UI framework is the idea of skinning. The ability to give the interface a different look (through the use of SVG skinning and CSS). An example could be using a rect instead of a circle for the visual representation of a radio button. The underlying code base does not need to be changed when it is changed from a circle to a rect, only the actual look of the widget itself.
The controller acts as the link between the Model and the View. The controller generally is in charge of handling events generated by both the user and the application. To use a metaphor, the model is the applications DNA, the View is the applications skin/hair/eye color/etc, and the controller is nervous system.
The Container pattern has been chosen as an attempt to reduce the base complexity of widgets. Every widget may be broken down into either a composite (Container) or an atomic (Atom) widget. Atoms are defined as in nature such that they may contain no other Atoms. A Container is described in the fashion of molecule in nature such that it may contain Atoms and/or Containers.
The separation of duties is important for reducing the complexity of the framework. If a widget is known to be an Atom, then the widget developer may develop their widget knowing full well that it will never contain any other widgets and thus remove a great deal of code to handle this case.
Container widgets have the ability to use other widgets themselves to complete their task. Of course this does add problems for interoperability. A Container widget could expect to get notified of a particular action from an Atom or Container widget that it itself contains. If that Atoms or Container is then changed to not notify it's Observers (see Section 3.3 ) upon that action then the holding Container will now not work correctly. Therefore it is up to the widget developers to ensure that widgets keep the same notification rules for upgrades or changes to the widgets. This is left up to the widget developers to decide upon and is out of the scope of this project. This project is to create a framework such that this communication is enabled.
The Observer pattern describes a publish/subscribe relationship between
software components. There is a many-to-many relationship between
Observers and Subjects. An Observer may watch
0-N
Subjects, and Subjects may be observed by
0-N
Observers. An Observer informs another component
(a Subject) that it wishes to be notified when that component changes
state (does something). When the component (a Subjects) changes state
in some form or another it notifies all of its Observers with this fact.
The Observer pattern is used for widget to widget communication in the framework. The rules for notification are somewhat relaxed from the original pattern specification. Due to the possibility of cascading notifications, a Subject may not always notify its observers of a change. The state changes that do signal this notification must be well documented by the widget developer. Once again this avoids cascading notifications up the Observer-Subject dependency tree and is done to mitigate any adverse efficiency problems. This problem was found in the Java 1.1 release and was then fixed with the release of Java 1.2.
The Observer pattern implementation used by the framework is described in detail in Section 4.2.1 .
The Command pattern also describes public/subscribe relationship between
software components. The reason that the Command pattern has been used
in the framework is to accommodate widget-application communication. Widgets
are known as CommandHolders and the application use cases are implemented
as Commands. Once again there is a many-to-many relationship between
Commands and CommandHolders. A CommandHolder may hold
0-N commands. A Command may be added to any number of
CommandHolders.
The rule for execution of commands should follow the rules of the Observer pattern (see Section 3.3 ). A widget must have a well defined behaviour when it comes to execution of Commands. An example is for a button. When that button is pushed the Command should be executed. It is unlikely that a Window would execute Commands though it is very likely that its components would. This of course is up to the widget developers and is used by the application developers. There is no Command dependency tree so therefore it is not possible to have cascading Command execution.
The Command pattern implementation used by the framework is described in detail in Section 4.2.2 .
The Factory pattern is a fairly common and widely used design pattern for object instantiation. It was chosen to give the application developer the greatest flexibility when creating their application. The Factory is used to instantiate widgets and handles all decision logic that accompanies that instantiation. The Factory pattern implementation used by the framework is described in detail in Section 6.1 .
The Decorator pattern is a perfect design patter for user interfaces and specifically the given framework and its accompanying development kit. The intent of the Decorator pattern is to "attach additional responsibilities to an object dynamically" [Design Patterns] . The Decorator is passed the widgets and adds application specific logic to individual instances of UI components. The frameworks' implementation of the Decorator pattern is described in detail in Section 6.2 .
The initial framework must describe all of the following: widget authoring, widget-widget communication, application-widget communication and application- server communication. Widget authoring describes the process by which a Widget ( A component of a whole - in this case refers to a user interface component ) is created. Widget-widget communication refers to the process by which widgets interact within the application amongst themselves. This communication is independent of the widget-application communication. Both of these are internal to the framework and are not dependant upon external entities such as an application.
The framework must also describe the external Communications - those Communications that travel outside of the GUI (Graphical User Interface) itself. These include widget-application interactions as well as application- server interactions. Without a standard Communication system between the GUI and the application the framework is rendered useless. Also, without a standard communication system for application-server interactions the framework may be pigeonholed and ignored.
The most important of these four initial framework definitions stated above are the widget authoring, widget-widget communications and the widget-application communication. The application-server Communication is less important specifically because initially there is no need to standardize it. This interaction may still be accomplished without a standard in place and therefore becomes less important in the creation of the framework. It is still important to standardize this at some time in the future but it is outside the scope of this initial report.
All interfaces used in the framework have been explained in terms of the design pattern they implement, their API and their IDL (Interface Definition Language) . The latter two are given so as to better explain in both words and in code exactly what the functions are and how to use them for developers. Some interfaces are useful only to Component developers while others are only useful to Application developers. It is however useful to be versed in the entire framework so that one may have a more thorough understanding of the interactions that are present within the application.
Both Observer and Subject are part of the Observer design pattern (see Section 3.3 ). These two interfaces are used as the communication medium for widget-widget interaction and communication. Containers are both Observers and Subjects at the same time while Atoms are only Subjects.
The following is the API description for the Observer interface:
The following is the API for the Subject interface:
The following is the frameworks implementation of the Command pattern (see Section 3.4 ). These interfaces are used to enable interaction between the widgets and the application. Generally speaking every Widget is a CommandHolder but does not necessarily hold any Commands. Commands are generally implemented as application use cases. They are executed when a specific state change happens in the CommandHolder.
The following is the API for the Command interface:
The following is the API for the CommandHolder interface:
The SPARKFactory is a simple interface stub that is used in conjunction with the SPARK class (see Section 4.6 ) itself. An application developer must implement this interface and both of it's functions for the framework to work correctly. The reason for this is that widgets assume that the SPARK class contains a class of type SPARKFactory and will request it to create new widget instances at various times during the execution of the program. A standard CustomFactory is pre-build and included in the Helper package. This interface is in place in case the developer wishes to have more customization abilities over their application and the creation of their widgets.
The SPARKFactory has been given a necessarily simple API . The reason for this is to make it easier for application developers to customize how their applications are loaded.
The Widget class is the super class for all Widgets in the SPARK framework. Every widget has two distinct parts: SVG and Script. The script has been well standardized and documented in this report and is necessary to implement the Controller layer for the Widget (see Section 3.1 ).
The SVG however has been standardized for different reasons. The SVG itself contains both the view and the model for each and every widget. The structure has been standardized such that applications may be declaratively created by UI developers without any prior knowledge of how the script itself works. The net result is that entire applications may have their user interfaces completely authored in SVG alone. Then it is up to the application developer to add the use cases to implement the application logic.
A side bonus of standardizing the SVG (as has been done below) is that the framework is then ready to be used in a WYSIWYG (What you see is what you get) UI authoring application. The standard SVG structure has been created such that a WYSIWYG application can simply insert the appropriate SVG into the root document in. This then allows very, very quick prototyping and/or application development. The specific details regarding containers is discussed in Figure 11 .
All widgets must conform to a specific SVG structure.
<g id="uniqueID" class="SPARK widgetType WidgetName CSS">
<desc>Required - Widget accessibility description</desc>
<metadata>Optional - Model storage location</metadata>
... any svg content ...
</g>
|
Figure 6: Widget SVG Template
The generic SVG structure has been defined in this structure for a number of reasons that are discussed below. The specific requirements are as follows:
<desc/>
<metadata/>
<metadata>foo</metadata> or
<metadata><SPARK pos="0.5" delta="0.1"/></metadata>.
It is up to the widget author to define their own expected model structure.
There is a possibility that in the future a standard model definition will
be created (with the ability to customize). NOTE: The structure for metadata
model information has yet to be formalized and therefore it is up to the
widget author to specify exactly how the model stores information.
The Widget class has the following API as well as the API defined for the CommandHolder interface (defined in Section 4.2.2.1 , i.e. Widget implements CommandHolder):
The Atom is the most basic widget type in the UI framework. It is used as an endpoint with the fact that it may contain no other widgets. A simple example of an Atom widget would be a Radiobutton or a Button. A Slider would not however be considered an Atom due to the fact that a Slider may be considered to contain two buttons (left/right or up/down arrows). The Atom class inheritance UML is found in Figure 7 .
The SVG format for the Atom widget is generally the same as the SVG format defined in Figure 6 , with a minor change to the class attribute. The class attribute is now standardized to be "SPARK atom AtomClassName", with AtomClassName being the name of the Atom class that was created and this SVG code block refers to.
<g id="uniqueID" class="SPARK atom AtomClassName">
<desc>Required - Description</desc>
<metadata>Optional - Model</metadata>
... Any SVG content (View)...
</g>
|
Figure 8: Atom SVG Template
Once again any SVG content is allowed once the required pieces have been added. This has been done to give the UI programmer the greatest flexibility for look and feel. They may create as much or as little SVG structure for styling the widget that they deem necessary. An example of an Atom SVG structure is shown in Figure 9 . Note how it still conforms to the basic Atom SVG structure defined in Figure 8 and is therefore valid atom-widget SVG.
<g id="button1" class="SPARK atom Button" transform="translate(100,100) scale(2)">
<desc>This button is pressed to popup a message listed in the metadata.</desc>
<metadata>Hello</metadata>
<rect width="90" height="25" x="0" y="0" class="Button">
<animate attributeName="width" from="90" to="100" dur="0.2s"
begin="button1.mouseover" fill="freeze"/>
<animate attributeName="height" from="25" to="30" dur="0.2s"
begin="button1.mouseover" fill="freeze"/>
<animate attributeName="x" from="0" to="-3" dur="0.2s"
begin="button1.mouseover" fill="freeze"/>
<animate attributeName="y" from="0" to="-3" dur="0.2s"
begin="button1.mouseover" fill="freeze"/>
<animate attributeName="width" from="100" to="90" dur="0.2s"
begin="button1.mouseout" fill="freeze"/>
<animate attributeName="height" from="30" to="25" dur="0.2s"
begin="button1.mouseout" fill="freeze"/>
<animate attributeName="x" from="-3" to="0" dur="0.2s"
begin="button1.mouseout" fill="freeze"/>
<animate attributeName="y" from="-3" to="0" dur="0.2s"
begin="button1.mouseout" fill="freeze"/>
</rect>
<text y="15" x="5" class="Button">Demo button 1</text>
</g>
|
Figure 9: Atom SVG Example
Finally note: The class attribute is used by the parser (SPARKFactory) on application load to decide what class to instantiate with that particular SVG snippet. If the AtomClassName class is not found, it will be ignored and not instantiated. If it is, a new scripting object will be attached as the controller for this model/view.
The Atom class does not have its own API calls rather it is simply a concrete extension of the Widget class and implements the Subject interface (i.e. Atom extends Widget implements Subject). Therefore the API that is available for Atom widgets is defined in Section 4.3.2 (Widget) and Section 4.2.1.1 (Subject).
Containers are defined as Widgets that may contain other widgets. Examples include Radiobutton Groups, Windows, and Sliders. The main idea for Containers is to provide Atoms a place to reside and to add any extra functionality that depends upon more than one widget.
A very good abstract example of a container is a "Moveable" harness. The harness is simply a container with no visual representation. Any widgets that it contains are then given the ability to be moved around as a group. This is a great example of a non-standard widget type that SVG based user interfaces allow.
The UML notation that defines the Container scripting object is shown in Figure 10 .
Similar to the Atom widget, the Container widget has generally the same as the SVG format as defined in Figure 6 , with it's own specific class attribute requirements. The class attribute is now standardized to be "SPARK container ContainerClassName", with ContainerClassName being the name of the Container class that was created and this SVG code block refers to. It is as flexible as the Atom for customizing the look and feel. It does however have one distinct difference and that has been added to support the idea of containing other widgets.
<g id="uniqueID" class="SPARK container ContainerClassName">
<desc>Required - Description</desc>
<metadata>Optional - Model</metadata>
... Any SVG content (View)...
... 1 or more Contents structures (may be nested)...
</g>
|
Figure 11: Container SVG Template
In addition to its normal SVG structure, a Container must also contain one or more content structures. These structures are used to contain other widgets (both Atom and Container widgets). A content node is always owned by node defined by the following XPath (note: is one entire XPath statement):
ancestor::g[ contains( @class, 'SPARK container' ) ]/
node()[ position() = count(
ancestor::g[ contains( @class, 'SPARK container' ) ]
) ]
|
The basic rule is that a contents node is owned by the first ancestor (in the SVG tree) that is a container widget structure. It is required that a container knows where its contents structures are located.
The following is the Container Contents structure that was listed in Figure 11 .
<g class="SPARK contents">
... Any SVG content (View)... and
... Any number of Atom and/or Container widgets...
</g>
|
Figure 12: Container SVG Template
An example of combining Containers with Atom widgets can be seen in Figure 13 . Once again it may be noted that the Container has its visual representation and it may be seen that the Container contains a contents structure. Within that structure the Radiobuttons' that it contains are declared. This shows how a user interface may be declaratively created.
<g id="radiobuttongroup" transform="translate(20,100)"
class="SPARK container RadiobuttonGroup">
<desc>This is a demo of a radiobutton group.</desc>
<metadata></metadata>
<text>
<tspan>Select a color number</tspan>
<tspan x="0" dy="20">the radiobutton group:</tspan>
</text>
<g class="SPARK contents">
<g id="radiobutton1-1" transform="translate(20,40)"
class="SPARK atom Radiobutton">
<desc>This is demo radiobutton 1. You can click it.</desc>
<metadata>one</metadata>
<circle r="5" />
<text x="8" y="3">one</text>
</g>
<g id="radiobutton1-2" transform="translate(20,60)"
class="SPARK atom Radiobutton">
<desc>This is demo radiobutton 2. You can click it.</desc>
<metadata>two</metadata>
<circle r="5" />
<text x="8" y="3">two</text>
</g>
</g>
</g>
|
Figure 13: Container SVG Example
It is assumed that Container will instantiate the Atoms and Containersthat they contain (located in a specified SVG structure called "contents"). It is assumed that the Container itself is instantiated by either it's owner container (that it is contained by) or by the application itself.
The SPARK class is the most complex and useful class in the framework. This class handles many different types of duties including Event distribution, type registration, global widget registration and as a container for the Factory used in widget creation.
The following is the detailed description of the publically available members of the SPARK class:
<g/> element it will no longer receive the mouseMove events.
Using this function those events may be redirected to the slider class and it
may continue being moved without handling the mouse events directly.
SPARK.registerWidgetType( "Radiobutton" ).
Therefore, when say a factory class calls the SPARK.isWidget function
with a class attribute such as class="SPARK atom Radiobutton" the
isWidget function will return true because it is known that this widget type is
supported. This function is generally called during the initialization of a
factory object.
SPARK.REGESTERED_WIDGETS.
SPARK.REGESTERED_WIDGETS. It will no longer be available in that
list of widgets. If it was not originally in the list nothing will happen.
The following is the UML class diagram for the Widgets Module. The class diagram does not include any helper classes (see Chapter 6 for their UML class diagrams).
The following is the IDL definition for the Widgets Module. It does not include any helper classes (see Chapter 6 for their IDL definitions).
// File: Widgets.idl
#ifndef _WIDGETS_IDL_
#define _WIDGETS_IDL_
// For access to SVGElement
// see http://www.w3.org/TR/SVG11/idl.html
#include "svg.idl"
#pragma prefix "Widgets.Framework.SPARK"
#pragma javaPackage "SPARK.Framework.Widgets"
module Widgets
{
typedef svg::SVGElement SVGElement;
typedef svg::SVGEvent SVGEvent;
interface Object;
interface Atom;
interface Command;
interface CommandHolder;
interface Container;
interface Observer;
interface SPARK;
interface SPARKFactory;
interface Subject;
interface Widget;
interface Command {
void execute( );
};
interface CommandHolder {
void addCommand( inout Command in_command );
void removeCommand( inout Command in_command );
};
interface Observer {
void update( inout Subject in_subect );
};
interface Subject {
void attach( inout Observer in_observer );
void detach( inout Observer in_observer );
};
interface Widget {
readonly attribute string ID;
readonly attribute string TYPE;
void setState( in Object in_state );
Object getState();
};
interface Atom : Widget, Subject { };
interface Container : Widget, Subject, Observer {
void addWidget( inout Widget in_widget );
void removeWidget( inout Widget in_widget );
};
interface SPARK {
typedef sequence <Widget> REGISTERED_WIDGETS;
boolean requestMouseFocus( inout Widget in_widget );
boolean releaseMouseFocus( inout Widget in_widget );
void handleMouseEvent( inout SVGEvent evt );
void requestKeyboardFocus( inout Widget in_widget );
void releaseKeyboardFocus( inout Widget in_widget );
void handleKeyboardEvent( inout SVGEvent evt );
void registerWidgetType( in string in_type );
void deregisterWidgetType( in string in_type );
boolean isWidget( in string in_name );
void registerWidget( inout Widget in_widget );
void deregisterWidget( inout Widget in_widget );
void setFactory( inout SPARKFactory in_factory );
SPARKFactory getFactory( );
};
interface SPARKFactory {
Widget createWidget( inout SVGElement in_node );
void createContents( inout SVGElement in_node,
inout Container in_container );
};
};
#endif // _WIDGETS_IDL_
|
Figure 16: Widgets Module IDL Definitions
One of the most important parts of the framework is to give the developer the option to customize the look and feel of the user interface. There are two main ways to accomplish this goal: through SVG and through CSS.
The easiest way to customize the visual representation of the user interface defined in the framework is through the use of CSS . Stylesheets may be replaced and swapped with no effect to the applications functionality. One application may have multiple CSS stylesheets and many applications may share the same CSS stylesheet. This idea is express in Figure 17 .
The fact that the class attribute is used in SVG as a space separated list can
easily be harnessed by the user interface developer. Every widget in the
framework has a well defined class attribute that contains not only it's class
name but may also contain any other pertinent CSS styling class. An example
SVG class attribute could easily be class="SPARK atom Button RedButton".
CSS styles could be applied to all widgets of a certain type or widgets could be
given a separate CSS class to style only certain widgets. An example CSS file
is shown in
Figure 18
.
*.Radiobutton
{
stroke: #000000;
fill: #dddddd;
stroke-width: 1
}
*.Button
{
stroke: lightgrey;
fill: midnightblue;
}
*.hide
{
display: none;
}
*.on
{
fill: red;
stroke-width: 2;
}
|
Figure 18: Simple CSS example for skinning an application
<g id="button1" class="SPARK atom Button hide">
<title>A hidden button</title>
<text>Hidden</text>
</g>
<g id="rb1" class="SPARK atom Radiobutton on">
<title>A radiobutton that has been turned on</title>
<metadata>true</metadata>
<circle r="5"/>
</g>
|
Figure 19: Example of a Widget using CSS
Using Cascading Stylesheets is a very easy way to visually style an application. Using colors, gradients, stroke widths, etc an entire application may have its look and feel change by simply updating the CSS stylesheet. CSS can also be used to control user interactions (such as the "hide" class in Figure 19 ) where the button is actually hidden from view using CSS as opposed to traditional methods of removing the SVG itself. The reasons for wanting to use CSS in styling an application are the same for using CSS in styling web pages - the ease with which visual changes are implemented.
The SVG construct described in Section 4.3.1 shows one option for customization of individual widgets which is important to a certain extent. There is, however, another option for customizing the user interface through the use of XSLT. These fall into two main categories: transformation for visual markup and transformation to generate the entire application.
The first and simplest form of skinning through the use of XSLT is to add custom SVG visual content to the application. The process for creating SVG from XML using XSLT and customizing the target is shown in Figure 20 .
The benefit of this process is that the application may be targeted for specific users, demographics or platforms. The look and feel could easily be internationalized for a different country. Or it could be created in SVG Light for mobile applications. The process by which this could be accomplished would be to author the application with a combination of custom XML markup and framework conforming SVG code:
<g id="radiobutton" transform="translate(20,100)" class="SPARK atom Radiobutton">
<desc>This is a demo of a radiobutton.</desc>
<metadata></metadata>
<custom:data xmlns:custom="http://www.myurl.com">
<text>Red</text>
</custom:data>
</g>
|
In Figure 21 there is no visual representation of the Radiobutton. Using the XSLT transformation process, information from the custom markup can be combined used to dynamically add a uniform look and feel to the application. The UI programmer could simply draw out what each Radiobutton looks like without having to insert the SVG into each Radiobutton individually. Therefore to update the visual representation (i.e. use a box instead of a circle for the radiobuttons) would be as simple as rerunning the xslt.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:custom="http://www.myurl.com">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:include href="external_defs.xslt"/>
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<!--
Copy any uncaught element exactly.
-->
<xsl:template match="*">
<xsl:copy>
<xsl:for-each select="@*">
<xsl:copy/>
</xsl:for-each>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<!--
Used to customize any widget.
-->
<xsl:template match="custom:data">
<xsl:copy>
<!-- Insert custom Radiobutton visual SVG markup -->
<xsl:call-template name="Customize.Widget">
<xsl:with-param name="type" select="parent::g/@class" />
<xsl:with-param name="data" select="."/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
|
Figure 22: XSLT used to insert custom SVG markup
Another option for customization is to define the entire user interface in terms of XML Schema defined types (i.e. select one, boolean, string). Using knowledge of these types and an instance of the XML Schema, the XML could be input into an XSLT to dynamically produce an entire application.
Any user interface may be defined as a set of data types either nested together or individually placed within the application. The process involved will be finalized shortly.
This process is non-trivial for script-generated user interfaces. Generating script through XSLT is a very difficult task to say the least. This is by far the biggest benefit to creating a declarative SVG user interface framework.
One of the main goals of the project was to create a framework that is easy to use (see Section 2.1 ). Though many of the decisions done during the project were done partly towards fulfilling this goal, the idea of a Helper module is completely geared towards it. The helper module is not a necessity to use the framework itself. The only part of the framework that is actually required is the Widgets module. The Helpers module has been created simply to enable developers to create applications faster and with more ease by removing some of the tedium of UI instantiation.
The Helpers module currently consists of two classes: SPARKHelperFactory and SPARKHelperDecorator. The factory class is a concrete instance of the SPARKFactory interface defined in the Widgets module (see Section 4.2.3 ). The decorator is an added design pattern that has been used to ease the integration of application and interface. There are plans to add more classes to the Helpers module including a class that performs common Mouse functions (such as coordinate conversion). For now there are only two though and they are defined below.
The SPARKHelperFactory has been added to the framework to help application developers have a fast track to instantiating their user interface framework controllers. With minor modifications it may be used in any application to handle all creation duties.
The SPARKHelperFactory is a concrete implementation of the SPARKFactory defined in Section 4.2.3 . Once agian the API is quite simple and easy to use. The API is defined as follows:
SPARK.addFactory( SPARKHelperFactory.init() ). This function
must be modified by the application programmer to support all the
widgets that have been used in the application by registering their type
with the global SPARK class (i.e.
SPARK.registerType( "Button" ); ).
Once again, application programmers should note that there are a total of three
functions that must be modified in this class in order to use it in their
application: init, createAtom, createContainer.
The SPARKHelperDecorator is a concrete implementation of the Decorator pattern described in Section 3.6 . Using a very simple interface the application programmer may add custom, application specific logic to their widgets through the use of this decorator class.
The API of the SPARKHelperDecorator is extremely simple but using this class is extremely powerful when developing a complex application.
in_widget).
If there is no custom logic to be added nothing will happen. This function should
be called from a factory createWidget function after the widget has
finished its instantiation. This function will require modification by
the UI programmer.
There are many ways to add custom logic to the widgets but the route suggested is through the Command pattern (see Section 3.4 ). As the Widget class has been declared to implement the CommandHolder interface ( Section 4.2.2 ) this can be harnessed by creating the application appropriately.
For example: suppose a developer has written their application as a set of distinct use cases, with each use case initiated by a particular user interface event. The use cases could be implemented as seperate classes that implement the Command interface defined earlier and thus simply be added to the required widget. Then, when the widget goes through a well defined state changed, the command is executed and thus the use case is initiated.
The following code would be all that is required to accomplish this feat:
SPARKHelperDecorator.prototype.decorate = function( in_widget )
{
// only handle these two widgets
if( in_widget.ID == "button1" )
{
// add the first use case to "button1"
in_widget.addCommand( new UseCase1() );
}
else if( in_widget.ID == "button2" )
{
// add the second use case to "button2"
in_widget.addCommand( new UseCase1() );
}
};
function UseCase1()
{
this.name = "Use Case 1";
}
// UseCase1 implements Command
UseCase1.prototype.execute = function()
{
alert( this.name );
// Application logic goes here
// ...
//
}
function UseCase2()
{
this.name = "Use Case 2";
}
// UseCase2 implements Command
UseCase2.prototype.execute = function()
{
alert( this.name + " was clicked." );
// Application logic goes here
// ...
//
}
|
Figure 26: Example of using the SPARKHelperDecorator (ECMAScript)
As can be seen, integrating the application and interface is accomplished
seamlessly with not major dependencies except for widget id's. Therefore the
widget that initiates the use case is easily swapped for another by simply
adjusting which id is caught in the decorate() function.
// File: Helpers.idl
#ifndef _HELPERS_IDL_
#define _HELPERS_IDL_
// For access to SVGElement
// see http://www.w3.org/TR/SVG11/idl.html
#include "svg.idl"
// For access to Widgets
#include "Widgets.idl"
#pragma prefix "Helpers.Framework.SPARK"
#pragma javaPackage "SPARK.Framework.Helpers"
module Helpers
{
typedef Widgets::Widget Widget;
typedef Widgets::Atom Atom;
typedef Widgets::Container Container;
typedef Widgets::SPARKFactory SPARKFactory;
typedef svg::SVGElement SVGElement;
interface SPARKHelperFactory;
interface SPARKHelperDecorator;
interface SPARKHelperFactory : SPARKFactory {
void setDecorator( inout SPARKHelperDecorator in_decorator );
SPARKHelperFactory init( );
};
interface SPARKHelperDecorator {
void decorate( inout Widget in_widget );
};
};
#endif // _HELPERS_IDL_
|
Figure 28: Helper Module IDL Definitions
There are a number of current developments in the SVG community that will most definitely affect the future of this framework. Technologies such as sXBL, XAML, and user interfaces created by other groups will greatly affect the development of the next generation of the framework, hopefully for the better. The following is a short list of topics that are on the radar screen to be tackled in the very near future.
Currently we have a grand theme for the future of this framework as a truly open source project. It would consist of three distinct developer types all working together for the greater good of the community: widget developers, skin developers and application developers. Combining resources from all three there is a huge potential to have a very robust, widely supported and widely implemented/deployed SVG user interface framework.
The fastest way to get the SVG community to adopt this framework and to start implementing applications in it is to have a plethora of ready to use, pre-authored widgets. Kevin Lindseys' site http://www.kevlindev.com is well known for the availability of widgets. Obviously the benefit of this framework is that widgets are very easy to be created and there is no "box" preventing the developer from inventing an amazing new widget.
Before these amazing widgets are invented though the basics must first be created. A very valuable widget would be a textbox and would easily be the most widely used widget in the framework and add immense popularity. Alastair had the benefit of working on a project where he had to author his own detailed, fully functional textbox SVG widget. Hopefully though he will not be the only one implementing new widgets though for the time being it does appear to be that way. Other examples of widgets that would add to the popularity of the framework would be a better window implementation, tab panel widgets and many other common widgets that may be found in normal user interface frameworks (such as Java Swing and .Net).
It is believed that a major area for development in relation to the framework is with respect to application skins. Skins may be developed independently of applications and do not have any scripting requirements. Therefore application skins may be created in a static environment and customized to suit the developers' wishes.
From this fact it may be deduced that a community sharing skins could easily add to the popularity of the framework. Examples of skinning applications include skins for Winamp to skins for instant messaging programs such as ICQ. It is a well known fact that some developers cherish the role of creating beautiful, functional user interfaces while other developers prefer to stick to the application logic itself. The development of skins could give these UI developers a creative outlet and a way of showing off their skills.
Finally, a community with emphasis on application creation is integral to the future goals of the framework and the open source project. A strong support network for new developers to expert developers to help spread the knowledge of the framework would be invaluable.
One of the interesting features of SVG 1.2 is XBL - XML Binding Language. Depending on the functionality available and implementations, XBL has the possibility of becoming an integral part of the framework in the future for obvious reasons (binding data to the SVG widgets - view - of the data).
It has been decided that the framework v1.0 will support all of SVG 1.1. As currently there are no final release viewers for SVG 1.2 and the SVG 1.2 draft has yet to be solidified, those features specific to SVG 1.2 have been ignored for this version of the framework. It has been decided that version 2.0 will support SVG 1.2.
SVG based user interfaces are possible. It is possible to create a framework that describes the user interface components and has been described in this report. It is now up to the SVG community at large to either adopt the framework, learn from it and improve the concepts, or to ignore. From the initial reactions of members of this community the future looks bright.
We look forward to all the hard work and effort that the SVG working group puts in every week towards the newest SVG candidate recommendation. New features to this language will only make it stronger and projects such as this one will benefit greatly from the work of these hard working individuals. The more pervasive SVG gets throughout the world the more likely this framework will prosper underneath their helm.
The authors wish to acknowledge Christopher Lewis and Chris Peto for their dedication to SVG based user interfaces. They have done some truly amazing work with CGUI in the past 2 years.
Alastair had the unique privilege of working with Darryl Fuller at SchemaSoft and specifically on a client project developing SVG user interface widgets. Darryl was a constant sounding board for the ideas listed in this report and for thoughtful comments and ideas regarding SVG GUI widgets.
The authors wish to acknowledge Kevin Lindsey and his amazing collection of SVG GUI widgets. Mr. Lindsey can definitely be listed as the innovator in the field of SVG GUI widgets.
XHTML rendition created by gcapaper Web Publisher v2.0, © 2001-3 Schema Software Inc.