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('...') becomes B( TEXT => '...' ). the special TEXT 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

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:

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 quits

see SYNOPSIS , XUL::Gui::Manual, XUL::Gui::Tutorial, and the examples 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 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 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 to LIST 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 to LIST 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 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 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.