NAME
XUL::Gui - render cross platform gui applications with firefox from perl
VERSION
version 0.30
this module is under active development, interfaces may change.
this code is currently in beta, use in production environments at your own risk
the code will be considered production ready, and interfaces finalized at version 0.50
this documentation is a work in progress
SYNOPSIS
use XUL::Gui;
display Label 'hello, world!';
# short enough? s/Label/P/ for bonus points
use XUL::Gui;
display Window title => "XUL::Gui's long hello", minwidth=>300,
GroupBox(
Caption('XUL'),
Button( label=>'click me', oncommand=> sub {shift->label = 'ouch'} ),
Button( id=>'btn',
label=>'automatic id registration',
oncommand=>sub{
$ID{btn}->label = 'means no more variable clutter';
$ID{txt}->value = 'and makes cross tag updates easy';
}),
Button( type=>'menu', label=>'menu button',
MenuPopup map {MenuItem label=>$_} qw/first second third/
),
TextBox( id=>'txt', FILL ),
ProgressMeter(mode=>'undetermined'),
),
GroupBox(
Caption('HTML too'),
TABLE( border=>1, TR map {TD $_} 'one', I('two'), B('three'), U('four'), SUP('five') ),
HR,
P('all the HTML tags are in CAPS'),
);
DESCRIPTION
this module exposes the entire functionality of mozilla firefox's rendering engine to perl by providing all of the XUL and HTML tags as functions and allowing you to interact with those objects directly from perl. gui applications created with this toolkit are cross platform, fully support CSS styling, inherit firefox's rich assortment of web technologies (browser, canvas and video tags, flash and other plugins), and are even easier to write than HTML.
this module is written in pure perl, and only depends upon core modules, making it easy to distribute your application.
all XUL and HTML objects in perl are exact mirrors of their javascript counterparts and can be acted on as such. for anything not written in this document or XUL::Gui::Manual, developer.mozilla.com is the official source of documentation:
http://www.hevanet.com/acorbin/xul/top.xul - XUL periodic table
gui's created with this module are event driven. an arbitrarily complex (and runtime mutable) object tree is passed to display, which then creates the gui in firefox and starts the event loop. display will wait for and respond to events until the quit function is called, or the user closes the firefox window.
all of javascript's event handlers are available, and can be written in perl (normally) or javascript (for handlers that need to be very fast such as image rollovers with onmouseover or the like). this is not to say that perl side handlers are slow, but with rollovers and fast mouse movements, sometimes there is mild lag due to protocol overhead.
the goal of this module is to make gui development as easy as possible. XUL's widgets and nested design structure gets us most of the way there, and this module with its light weight syntax, and "Do What I Mean" nature hopefully finishes the job. everything has sensible defaults with minimal boilerplate, and nested design means a logical code flow that isn't littered with variables. now you can focus on your gui's design and functionality, and hopefully not on the deficiencies of your toolkit. if XUL::Gui doesn't get you all the way there yet, give it time, I'm still working on it.
tags
all tags (XUL, HTML, user defined widgets, and the display function) are parsed the same way, and can fit into one of four templates
HR() is <hr />B('some bold text') is <b>some bold text<b/>in the special case of a tag with one argument, which is not another tag, that argument is added to that tag as a text node. this is mostly useful for HTML tags, but works with XUL as well
Label( value=>'some text', style=>'color: red' )<label value="some text" style="color: red;" />Hbox( id=>'mybox', Label('hello'), B('world'), style=>'border: 1px solid black')<hbox id="mybox" style="border: 1px solid black;"> <label>hello</label> <b>world</b> </hbox>unlike XML based XUL, attribute pairs and children can be mixed in any order, but attributes should probably be kept at the front for readability
setting the 'id' attribute names the object in the global %ID hash. otherwise an auto generated name matching /^xul_\d+$/ is used.
$object = Button( id=>'btn', label=>'OK' );
# $ID{btn} == $object
any tag attribute name that matches /^on/ is an event handler (onclick, onfocus....), and expects a sub{...} (perl event handler) or function q{...} (javascript event handler).
perl event handlers get passed a reference to themselves, and an event object
Button( label=>'click me', oncommand=> sub {
my ($self, $event) = @_;
$self->label = $event->type;
})
javascript event handlers have event and this set for you
Button( label=>'click me', oncommand=> function q{
this.label = event.type;
})
any attribute with a name that doesn't match /^on/ that has a code ref value is added to the object as a method
Tk's attribute style with a leading dash is supported. this is useful for readability when collapsing attribute lists with qw//
TextBox id=>'txt', width=>75, height=>20, type=>'number', decimalplaces=>4;
TextBox qw/-id txt -width 75 -height 20 -type number -decimalplaces 4/;
multiple 'style' attributes are joined with ';' into a single attribute
EXPORT
use XUL::Gui; # is the same as
use XUL::Gui qw/:base :util :widget :pragma :xul :html :const :image/;
the following export tags are available. :base is required for minimal functionality
:base %ID display quit alert function gui XUL
:widget @C %A %M $W widget attribute extends
:pragma buffered now cached noevents delay doevents
:const FLEX FIT FILL SCROLL MIDDLE
:image bitmap bitmap2src serve
:util zip mapn apply trace toggle
:internal tag object genid
:all (all exports)
:xul (also exported as Titlecase)
Action ArrowScrollBox Assign BBox Binding Bindings Box Broadcaster BroadcasterSet
Browser Button Caption CheckBox ColorPicker Column Columns Command CommandSet Conditions
Content DatePicker Deck Description Dialog DialogHeader DropMarker Editor Grid Grippy
GroupBox HBox IFrame Image Key KeySet Label ListBox ListCell ListCol ListCols ListHead
ListHeader ListItem Member Menu MenuBar MenuItem MenuList MenuPopup MenuSeparator
Notification NotificationBox Observes Overlay Page Panel Param PopupSet PrefPane PrefWindow
Preference Preferences ProgressMeter Query QuerySet Radio RadioGroup Resizer RichListBox
RichListItem Row Rows Rule Scale Script ScrollBar ScrollBox ScrollCorner Separator Spacer
SpinButtons Splitter Stack StatusBar StatusBarPanel StringBundle StringBundleSet Tab TabBox
TabPanel TabPanels Tabs Template TextBox TextNode TimePicker TitleBar ToolBar ToolBarButton
ToolBarGrippy ToolBarItem ToolBarPalette ToolBarSeparator ToolBarSet ToolBarSpacer
ToolBarSpring ToolBox ToolTip Tree TreeCell TreeChildren TreeCol TreeCols TreeItem TreeRow
TreeSeparator Triple VBox Where Window Wizard WizardPage
:html (also exported as html_lowercase)
A ABBR ACRONYM ADDRESS APPLET AREA AUDIO B BASE BASEFONT BDO BGSOUND BIG BLINK BLOCKQUOTE
BODY BR BUTTON CANVAS CAPTION CENTER CITE CODE COL COLGROUP COMMENT DD DEL DFN DIR DIV DL DT
EM EMBED FIELDSET FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME ILAYER IMG
INPUT INS ISINDEX KBD LABEL LAYER LEGEND LI LINK LISTING MAP MARQUEE MENU META MULTICOL NOBR
NOEMBED NOFRAMES NOLAYER NOSCRIPT OBJECT OL OPTGROUP OPTION P PARAM PLAINTEXT PRE Q RB RBC RP
RT RTC RUBY S SAMP SCRIPT SELECT SMALL SOURCE SPACER SPAN STRIKE STRONG STYLE SUB SUP TABLE
TBODY TD TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR VIDEO WBR XML XMP
for the OO purists:
use XUL::Gui ();
my $gui = XUL::Gui->new;
$gui->display( $gui->Label('hello world') );
# use $gui->id('someid') to access the %ID hash;
FUNCTIONS
utility functions
mapn {CODE} NUMBER LIST-
map over n elements at a time in
@_with$_ == $_[0]print mapn {$_ % 2 ? "@_" : " [@_] "} 3 => 1..20; > 1 2 3 [4 5 6] 7 8 9 [10 11 12] 13 14 15 [16 17 18] 19 20 zip LIST of ARRAYREF-
%hash = zip [qw/a b c/], [1..3]; apply {CODE} LIST-
apply a function to a copy of LIST and return the copy
print join ", " => apply {s/$/ one/} "this", "and that"; > this one, and that one toggle TARGET OPT1 OPT2-
alternate a variable between two states
toggle $state => 0, 1; bitmap WIDTH HEIGHT OCTETS-
returns a binary .bmp bitmap image. OCTETS is a list of BGR values
bitmap 2, 2, qw(255 0 0 255 0 0 255 0 0 255 0 0); # 2px blue square bitmap2src WIDTH HEIGHT OCTETS-
returns a packaged bitmap image that can be directly assigned to an image tag's src attribute. arguments are the same as
bitmap()$ID{myimage}->src = bitmap2src 320, 180, @image_data;
constants
FLEX flex => 1
FILL flex => 1, align =>'stretch'
FIT sizeToContent => 1
SCROLL style => 'overflow: auto'
MIDDLE align => 'center', pack => 'center'
each is a function that returns its constant, prepended to
its arguments, thus the following are both valid:
Box FILL pack=>'end';
Box FILL, pack=>'end';
gui functions
display LIST-
starts the http server, launches firefox, waits for events
takes a list of gui objects, and several optional parameters:
debug (0) .. 3 adjust verbosity to stderr silent (0) 1 disables all status messages nolaunch (0) 1 disables launching firefox, connect manually to http://localhost:8888 nochrome (0) 1 chrome mode disables all normal firefox gui elements, setting this option will turn those elements back on. port (8888) first port to try starting the server on, port++ after that delay milliseconds delays each gui update cycleif the first object is a
Window, that window is created, otherwise a default one is added. the remaining objects are then added to the window.displaywill not return until the the gui quitssee SYNOPSYS and XUL::Gui::Manual for more details
quit-
shuts down the server (causes a call to
displayto return at the end of the current event cycle) serve PATH MIMETYPE DATA-
add a virtual file to the server
serve '/myfile.jpg', 'text/jpeg', $jpegdata;the paths
qw( / /client.js /event /ping /exit /perl )are reserved object TAGNAME LIST-
creates a gui proxy object, allows run time addition of custom tags
object('Label', value=>'hello') is the same as Label( value=>'hello' ) tag NAME-
returns a code ref that generates proxy objects, allows for user defined tag functions
*mylabel = tag 'label'; \&mylabel == \&Label widget {CODE} HASH-
group tags together into common patterns, with methods and inheritance
*MyWidget = widget { Hbox( Label( value=> $A{label} ), Button( label=>'OK', attribute 'oncommand' ), @C ) } method => sub{ ... }, method2 => sub{ ... }; $ID{someobject}->appendChild( MyWidget( label=>'widget', oncommand=>\&event_handler ) ); inside widgets, several variables are defined variable contains the passed in %A attributes @C children %M methods $W a reference to the current widget much more detail in XUL::Gui::Manual extends OBJECT-
indicate that a widget inherits from another widget or tag
*MySubWidget = widget {extends MyWidget} submethod => sub{...}; more details in XUL::Gui::Manual attribute NAME-
includes an attribute name if it exists, only works inside of widgets. NAME is split on whitespace
attribute 'label type' # is syntactic sugar for map {$_ => $A{$_}} grep {exists $A{$_}} qw/label type/ attribute '+' # same as %A attribute '*' # any untouched attributes (by attribute) XUL STRING-
converts an XML XUL string to XUL::Gui objects. experimental.
this function is provided to facilitate drag and drop of XML based XUL from tutorials for testing. the perl functional syntax for tags should be used in all other cases
alert STRING-
open an alert message box
trace LIST-
carps LIST with object details, and then returns LIST unchanged
function JAVASCRIPT-
create a javascript function, useful for functions that need to be very fast, such as rollovers
Button( label=>'click me', oncommand=> function q{ this.label = 'ouch'; alert('hello from javascript'); }) to access widget siblings by id, wrap the id with C< W{...} > gui JAVASCRIPT-
executes JAVASCRIPT
PRAGMATIC BLOCKS
the following functions all apply pragmas to their CODE blocks. in some cases, they also take a list. this list will be @_ when the CODE block executes. this is useful for sending in values from the gui, if you don't want to use a now {block}
buffered {CODE} LIST-
delays sending gui updates
buffered { $ID{$_}->value = '' for qw/a bunch of labels/ }; # all labels are cleared at once cached {CODE}-
turns on caching of gets from the gui
now {CODE}-
execute immediately, from inside a buffered or cached block
delay {CODE} LIST-
delays executing its CODE until the next gui refresh
useful for triggering widget initialization code that needs to run after the gui objects are rendered
noevents {CODE} LIST-
disable event handling
doevents-
force a gui update before an event handler finishes
METHODS
# access attributes and properties
$object->value = 5; # sets the value in the gui
print $object->value; # gets the value from the gui
# the attribute is set if it exists, otherwise the property is set
$object->_value = 7; # sets the property directly
# method calls
$object->focus; # void context
$object->appendChild( H2('title') ); # or any arguments are always method calls
print $object->someAccessorMethod_; # append _ to force interpretation as a JS method call
in addition to mirroring all of an object's existing javascript methods / attributes / and properties to perl (with identical spelling / capitalization), several default methods have been added to all objects
->removeChildren( LIST )-
removes the children in LIST, or all children if none given
->removeItems( LIST )-
removes the items in LIST, or all items if none given
->appendChildren( LIST )-
appends the children in LIST
->prependChild( CHILD, [INDEX] )-
inserts CHILD at INDEX (defaults to 0) in the parent's child list
->appendItems( LIST )-
append a list of items
->replaceItems( LIST )-
removes all items, then appends LIST
CAVEATS
currently, it is not possible to open more than one window, or to use any features available to privileged chrome apps. in most cases you can get away with doing what you need in perl, but having proper file dialogs and drag/drop would be nice, so this is near the top of my todo list.
the code that attempts to find firefox may not work in all cases, patches welcome
for the TextBox object, the behaviors of the "value" and "_value" methods are reversed. it works better that way and is more consistent with the behavior of other tags.
AUTHOR
Eric Strom, <ejstrom at gmail.com>
BUGS
please report any bugs or feature requests to bug-xul-gui at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=XUL-Gui. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
ACKNOWLEDGMENTS
the mozilla development team
COPYRIGHT & LICENSE
copyright 2009 Eric Strom.
this program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.
see http://dev.perl.org/licenses/ for more information.