NAME
XUL::Gui - render cross platform gui applications with firefox from perl
VERSION
version 0.51
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? s/Label/P/ for bonus points
use XUL::Gui;
display Window title => "XUL::Gui's long hello",
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', 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.
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 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. please send feedback if you think anything could be improved.
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'), pack=>'center' )
<hbox id="mybox" pack="center"> <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} == 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 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
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 :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
: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';
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 DYOI DWYM 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
-
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 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 4 digit port > 1024 is used
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 and XUL::Gui::Manual 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' )
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
-
group tags together into common patterns, with methods and inheritance
*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}) @_ = 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
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.my @files = filepicker open => Text => '*.txt; *.rtf', Images => '*.jpg; *.gif; *.png';
trace LIST
-
carps LIST with object details, and then returns LIST 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
-
perl interface to javascript's
setInterval()
. interval returns a code ref which when called will cancel the interval. TIME is in milliseconds. timeout {CODE} TIME
-
perl interface to javascript's
setTimeout()
. timeout returns a code ref which when called will cancel the timeout. TIME is in milliseconds. 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
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
noevents {CODE} LIST
-
disable event handling
doevents
-
force a gui update 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 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; # opts default to 0, 1 toggle $state => 'red', 'blue';
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
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 string
pack "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 at INDEX (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 also value' ... ] default => 'item selected if this matches its value' also takes: label, oncommand, editable, flex styles: liststyle, popupstyle, itemstyle getter: value
CAVEATS
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 in the next release
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.