NAME
XUL::Gui - render cross platform gui applications with firefox from perl
VERSION
version 0.63
this module is under active development, interfaces may change.
this code is currently in beta, use in production environments at your own risk
SYNOPSIS
use XUL::Gui;
display Label 'hello, world!';
# short enough? remove "Label" for bonus points
use XUL::Gui;
display Window title => "XUL::Gui's long hello",
GroupBox(
Caption('XUL'),
Button(
label => 'click me',
oncommand => sub {$_->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', width => 300 ),
ProgressMeter( mode => 'undetermined' ),
),
GroupBox(
Caption('HTML too'),
TABLE( width => '100%',
TR map {TD $_}
'one', I('two'), B('three'), U('four'), SUP('five')
),
BR, 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
.
how things work
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 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.
this module is written in pure perl, and only depends upon core modules, making it easy to distribute your application. the goal of this module is to make all steps of 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. please send feedback if you think anything could be improved.
building blocks
just like in HTML
, you build up your gui using tags. all tags ( XUL
tags, HTML
tags, user defined widgets, and the display
function) are parsed the same way, and can fit into one of four templates:
no arguments
HR() <hr />
one simple argument
B('some bold text') <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. once parsed, the line
B('...')
becomesB( TEXT => '...' )
. the specialTEXT
attribute can be used directly if other attributes need to be set:FONT( color=>'blue', TEXT=>'...' )
.multiple attributes
Label( value=>'some text', style=>'color: red' ) <label value="some text" style="color: red;" />
attributes and children
Hbox( id => 'mybox', pack => 'center', Label( value => 'hello' ), BR, B('world') ) <hbox id="mybox" pack="center"> <label value="hello" /> <br /> <b>world</b> </hbox>
as you can see, the tag functions in perl nest and behave the same way as their counterpart element constructors in HTML/XUL
. just like in HTML
, you access the elements in your gui by id
. but rather than using document.getElementById(...)
all the time, setting the id
attribute names an element in the global %ID
hash. the same hash can be accessed using the ID(some_id)
function.
my $object = Button( id => 'btn', label => 'OK' );
# $ID{btn} == ID(btn) == $object
the ID hash also exists in javascript:
ID.btn == document.getElementById('btn')
due to the way this module works, every element needs an id
, so if you don't set one yourself, an auto generated id
matching /^xul_\d+$/
is used. you can use any id
that matches /\w+/
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
xul documentation links
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
event handlers
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 their object and an event object
Button( label=>'click me', oncommand=> sub {
my ($self, $event) = @_;
$self->label = $event->type;
})
in the event handler, $_ == $_[0]
so a shorter version would be:
oncommand => sub {$_->label = pop->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. methods are explained in more detail later on.
EXPORT
use XUL::Gui; # is the same as
use XUL::Gui qw/:base :util :pragma :xul :html :const :image/;
the following export tags are available:
:base %ID ID alert display quit widget
:tools function gui interval serve timeout toggle XUL
:pragma buffered cached delay doevents flush noevents now
:const BLUR FILL FIT FLEX MIDDLE SCROLL
:widgets ComboBox filepicker prompt
:image bitmap bitmap2src
:util apply mapn trace zip
:internal genid object realid tag
:all (all exports)
:default (same as with 'use XUL::Gui;')
: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
constants:
FLEX flex => 1
FILL flex => 1, align =>'stretch'
FIT sizeToContent => 1
SCROLL style => 'overflow: auto'
MIDDLE align => 'center', pack => 'center'
BLUR onfocus => 'this.blur()'
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';
object oriented interface
if you prefer an OO interface, there are a few ways to get one:
use XUL::Gui 'g->*'; # DYOI: draw your own interface
g
(which could be any empty package name) now has all of XUL::Gui's functions as methods. since draw your own interface does what you mean ( dyoidwym
), each of the following graphic styles are equivalent: g->*, g->, ->g, install_into->g
.
normally, installing methods into an existing package will cause a fatal error, however you can add !
to force installation into an existing package
no functions are imported into your namespace by default, but you can request any you do want as usual:
use XUL::Gui qw( g->* :base :pragma );
to use the OO interface:
g->display( g->Label('hello world') );
# is the same as
XUL::Gui::display( XUL::Gui::Label('hello world') );
use g->id('someid') or g->ID('someid') to access the %ID hash
the XUL tags are also available in lc and lcfirst:
g->label == XUI::Gui::Label
g->colorpicker == XUL::Gui::ColorPicker
g->colorPicker == XUL::Gui::ColorPicker
the HTML tags are also available in lc, unless an XUL tag
of the same name exists
if you prefer an object (which behaves exactly the same as the package 'g'):
use XUL::Gui (); # or anything you do want
my $g = XUL::Gui->oo; # $g now has XUL::Gui's functions as methods
if you like all the OO lowercase names, but want functions, draw that:
use XUL::Gui qw( ->main:: ); # ->:: will also export to main::
# '::' implies '!'
display label 'hello, world';
FUNCTIONS
gui functions
display LIST
-
display
starts the http server, launches firefox, and waits for events.it takes a list of gui objects, and several optional parameters:
debug (0) .. 6 adjust verbosity to stderr silent (0) 1 disables all stderr status messages trusted 0 (1) starts firefox with '-app' (requires firefox 3+) launch 0 (1) launches firefox, if 0 connect to http://localhost:port skin 0 (1) use the default 'chrome://global/skin' skin chrome 0 (1) chrome mode disables all normal firefox gui elements, setting this to 0 will turn those elements back on. xml (0) 1 returns the object tree as xml, the gui is not launched perl includes deparsed perl event handlers delay milliseconds delays each gui update cycle (for debugging) port first port to start the server on, port++ after that otherwise a random 5 digit port is used mozilla 0 (1) setting this to 0 disables all mozilla specific features including all XUL tags, the filepicker, and any trusted mode features. (used to implement Web::Gui)
if 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.display
will not return until the the gui quitssee
SYNOPSIS
, XUL::Gui::Manual, XUL::Gui::Tutorial, and theexamples
folder in this distribution for more details quit
-
shuts down the server (causes a call to
display
to return at the end of the current event cycle)quit
will shut down the server, but it can only shut down the client in trusted mode. 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' )
the
object
function is the constructor of all proxied gui objects, and all these objects inherit from[object]
which provides the following methods. - object introspection
-
objects and widgets inherit from a base class
[object]
that provides the following object inspection / extension methods. these methods operate on the current data that XUL::Gui is holding in perl, none of them will ever call out to the gui->has('item!') returns attributes or methods (see widget for details) ->attr('rows') lvalue access to $$self{A} attributes ->child(2) lvalue access to $$self{C} children it only makes sense to use attr or child to set values on objects before they are written to the gui ->can('update') lvalue access to $$self{M} methods ->attributes returns %{ $$self{A} } ->children returns @{ $$self{C} } ->methods returns %{ $$self{M} } ->widget returns $$self{W} ->id returns $$self{ID} ->parent returns $$self{P} ->super returns $$self{ISA}[0] ->super(2) returns $$self{ISA}[2] ->extends(...) sets inheritance (see widget for details)
these methods are always available for widgets, and if they end up getting in the way of any javascript methods you want to call for gui objects:
$object->extends(...) # calls the perl introspection function $object->extends_(...) # calls 'object.extends(...)' in the gui $x = $object->_extends; # fetches the 'object.extends' property $object->setAtribute('extends', ...); # and setting an attribute
or at runtime:
local $XUL::Gui::EXTENDED_OBJECTS = 0; # which prevents object inheritance # in the current lexical scope $object->extends(...); # calls the real javascript 'extends' method assuming that it exists
tag NAME
-
returns a code ref that generates proxy objects, allows for user defined tag functions
*mylabel = tag 'label'; \&mylabel == \&Label
ID OBJECTID
-
returns the gui object with the id
OBJECTID
. it is exactly the same as$ID{OBJECTID}
and has(*)
glob context so you don't need to quote the id.Label( id => 'myid' ) ... $ID{myid}->value = 5; ID(myid)->value = 5; # same
widget {CODE} HASH
-
widgets are containers used to group tags together into common patterns. in addition to grouping, widgets can have methods, attached data, and can inherit from other widgets
*MyWidget = widget { Hbox( Label( $_->has('label->value') ), Button( label => 'OK', $_->has('oncommand') ), $_->children ) } method => sub{ ... }, method2 => sub{ ... }, some_data => [ ... ]; # unless the value is a CODE ref, each widget # instance gets a new deep copy of the data $ID{someobject}->appendChild( MyWidget( label=>'widget', oncommand=>\&event_handler ) );
inside the widget's code block, several variables are defined:
variable contains the passed in $_{A} = { attributes } $_{C} = [ children ] $_{M} = { methods } $_ = a reference to the current widget (also as $_{W}) @_ = the unchanged runtime argument list
widgets have the following predefined (and overridable) methods that are synonyms / syntactic sugar for the widget variables:
$_->has('label') ~~ exists $_{A}{label} ? (label=>$_{A}{label}) : () $_->has('label->value') ~~ exists $_{A}{label} ? (value=>$_{A}{label}) : () $_->has('!label !command->oncommand style') ->has(...) splits its arguments on whitespace and will search $_{A}, then $_{M} for the attribute. if an ! is attached (anywhere) to an attribute, it is required, and the widget will croak without it. in scalar context, if only one key => value pair is found, ->has() will return the value. otherwise, the number of found pairs is returned $_->attr( STRING ) $_{A}{STRING} # lvalue $_->attributes %{ $_{A} } $_->child( NUMBER ) $_{C}[NUMBER] # lvalue $_->children @{ $_{C} } $_->can( STRING ) $_{M}{STRING} # lvalue $_->methods %{ $_{M} }
most everything that you would want to access is available as a method of the widget (attributes, children, instance data, methods). since there may be namespace collisions, here is the namespace construction order:
%widget_methods = ( passed in attributes, predefined widget methods, widget methods and instance data, passed in methods );
widgets can inherit from other widgets using the ->extends() method:
*MySubWidget = widget {$_->extends( &MyWidget )} submethod => sub {...};
more detail in XUL::Gui::Manual
alert STRING
-
open an alert message box
prompt STRING
-
open an prompt message box
filepicker MODE FILTER_PAIRS
-
opens a filepicker dialog. modes are 'open', 'dir', or 'save'. returns the path or undef on failure. if mode is 'open' and
filepicker
is called in list context, the picker can select multiple files. the filepicker is only available when the gui is running in 'trusted' mode.my @files = filepicker open => Text => '*.txt; *.rtf', Images => '*.jpg; *.gif; *.png';
trace LIST
-
carps
LIST
with object details, and then returnsLIST
unchanged function JAVASCRIPT
-
create a javascript event handler, useful for mouse events that need to be very fast, such as onmousemove or onmouseover
Button( label=>'click me', oncommand=> function q{ this.label = 'ouch'; alert('hello from javascript'); if (some_condition) { perl("print 'hello from perl'"); } }) $ID{myid} in perl is ID.myid in javascript
to access widget siblings by id, wrap the id with
W{...}
interval {CODE} TIME LIST
-
perl interface to javascript's
setInterval()
. interval returns a code ref which when called will cancel the interval.TIME
is in milliseconds.@_
will be set toLIST
when the code block is executed. timeout {CODE} TIME LIST
-
perl interface to javascript's
setTimeout()
. timeout returns a code ref which when called will cancel the timeout.TIME
is in milliseconds.@_
will be set toLIST
when the code block is executed. 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
gui JAVASCRIPT
-
executes
JAVASCRIPT
in the gui, returns the result
data binding
passing a reference to a scalar or coderef as a value in an object constructor will create a data binding between the perl variable and its corresponding value in the gui.
use XUL::Gui;
my $title = 'initial title';
display Window title => \$title,
Button(
label => 'update title',
oncommand => sub {
$title = 'title updated via data binding';
}
);
a property on a previously declared object can also be bound by taking a reference to it:
display
Label( id => 'lbl', value => 'initial value'),
Button(
label => 'update',
oncommand => sub {
my $label = \ID(lbl)->value;
$$label = 'new value';
}
)
this is just an application of the normal bidirectional behavior of gui accessors:
for (ID(lbl)->value) {
print "$_\n"; # gets the current value from the gui
$_ = 'new'; # sets the value in the gui
print "$_\n"; # gets the value from the gui again
}
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}
autobuffering
this module will automatically buffer certain actions within event handlers. autobuffering will queue setting of values in the gui until there is a get, the event handler ends, or doevents
is called. this eliminates the need for many common applications of the buffered
pragma.
flush
-
flush the autobuffer
buffered {CODE} LIST
-
delays sending all messages to the gui. partially deprecated (see autobuffering)
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, without causing a buffer flush or cache reset. buffered and cached will not work inside a now 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. the first element of
LIST
will be in$_
when the code block is executed noevents {CODE} LIST
-
disable event handling
doevents
-
force a gui update cycle before an event handler finishes
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 copyprint join ", " => apply {s/$/ one/} "this", "and that"; > this one, and that one
toggle TARGET OPT1 OPT2
-
alternate a variable between two states
toggle $state; # opts default to 0, 1 toggle $state => 'red', 'blue';
bitmap WIDTH HEIGHT OCTETS
-
returns a binary .bmp bitmap image.
OCTETS
is a list ofBGR
valuesbitmap 2, 2, qw(255 0 0 255 0 0 255 0 0 255 0 0); # 2px blue square
for efficiency, rather than a list of
OCTETS
, you can send in a single array reference. each element of the array reference can either be an array reference of octets, or a packed stringpack "C*" => OCTETS
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;
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 or
$object->appendChild( H2('title') ); # any arguments are always methods
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 are given ->removeItems( LIST )
-
removes the items in
LIST
, or all items if none are given ->appendChildren( LIST )
-
appends the children in
LIST
->prependChild( CHILD, [INDEX] )
-
inserts
CHILD
atINDEX
(defaults to 0) in the parent's child list ->replaceChildren( LIST )
-
removes all children, then appends
LIST
->appendItems( LIST )
-
append a list of items
->replaceItems( LIST )
-
removes all items, then appends
LIST
widgets
- ComboBox
-
create dropdown list boxes
items => [ ['displayed label' => 'value'], 'label is same as value' ... ] default => 'item selected if this matches its value' also takes: label, oncommand, editable, flex styles: liststyle, popupstyle, itemstyle getter: value
CAVEATS
too many changes to count. if anything is broken, please send in a bug report.
some options for display have been reworked from 0.36 to remove double negatives
widgets have changed quite a bit from version 0.36. they are the same under the covers, but the external interface is cleaner. for the most part, the following substitutions are all you need:
$W --> $_ or $_{W}
$A{...} --> $_{A}{...} or $_->attr(...)
$C[...] --> $_{C}[...] or $_->child(...)
$M{...} --> $_{M}{...} or $_->can(...)
attribute 'label onclick' --> $_->has('label onclick')
widget {extends ...} --> widget {$_->extends(...)}
export tags were changed a little bit from 0.36
thread safety should be better than in 0.36
currently it is not possible to open more than one window, hopefully this will be fixed soon
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, <asg at cpan.org>
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-2010 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.