=head1 NAME

Tkx::Tutorial - How to use Tkx

=head1 DESCRIPTION

I<Tk> is a toolkit that allows you to create applications with
graphical interfaces for Windows, Mac OS X and X11.  The Tk toolkit
is native to the I<Tcl> programming language, but its ease of use and
cross-platform availability has made it the GUI toolkit of choice for
many other dynamic languages as well.

I<Tkx> is a Perl module that makes the Tk toolkit available to Perl
programs.  By loading the Tkx module Perl programs can create
windows and fill them with text, images, buttons and other controls
that make up the user interface of the application.

=head2 Hello World

Let's start with the mandatory exercise of creating an application
that greats the world.  Here we make the application window contain a
single button which will shut down the application if clicked.  The
code to make this happen is:

    use Tkx;
    
    Tkx::button(".b",
        -text => "Hello, world",
        -command => sub { Tkx::destroy("."); },
    );
    Tkx::pack(".b");
    
    Tkx::MainLoop()

Save this to a file called F<hello.pl> and then run C<perl hello.pl>
to start up the application.  A window with the text "Hello, world"
should appear on your screen.

After the Tkx module has been loaded by the C<use Tkx> statement
the application will show an empty window called ".".  We create a
I<button> with the name ".b" and tell the window to display the button
with the call to C<Tkx::pack()>.  After the layout of the window has
been set up we need to pass control back to Tk so that it can draw
the window and invoke our callback if the button is clicked.  This is
achieved by the C<Tkx::MainLoop()> call at the end.  Clicking the
button will invoke the subroutine registered with the C<-command>
option of the button.  In this case the callback simply destroys the
window, which in turn will terminate the application.

For reference this is how the same program would look in Tcl:

    package require Tk
    
    button .b \
        -text "Hello, world" \
        -command { destroy . }
    pack .b

This program can be executed by the F<tclsh> binary that comes with
Tcl/Tk.  As you can see the code is mostly identical, but with a
slightly different syntax.  The only real difference is that the call
to MainLoop() is implicit in Tcl and does not have to be spelled out.

Tkx does not come with documentation that explain all the widgets
(like "button" above) that are available for use.  Instead you will
need to read the mostly excellent documentation that comes with C<Tcl/Tk> and
then figure out how this translates to Tkx yourself.  As you can
see this translation is straight forward.  You basically only have add
the prefix "Tkx::" to all the functions and use the Perl way of
passing arguments.  Tcl is a very simple language, so it should not
take long to understand enough of it to be able to read its
documentation with ease.

A great place to look up the Tk documentation is
L<http://aspn.activestate.com/ASPN/docs/ActiveTcl/at.pkg_index.html>.
This documents core Tk as well as all the useful add-on packages that
are part of ActiveTcl. The ActiveTcl HTML documentation can also be
downloaded from L<http://downloads.activestate.com/ActiveTcl/html/>
and installed locally.  The official Tcl/Tk docs are found at
L<http://www.tcl.tk/doc/>.

=head2 Hello World with objects

The windows and controls that make up a Tk interface are called
I<widgets>.  The widgets are identified by path names of the form
C<.foo.bar.baz>.  These names are hierarchical in the same way as file
system names are, but "." is used instead of "/" to separate levels.
The name C<.foo.bar.baz> is the name of a widget that is child of widget
C<.foo.bar> which in turn is a child of C<.foo>.  At the top of this
hierarchy we have a widget called C<.>, which is the main window of
the application.

The Tkx module provide a class called C<Tkx::widget>, that can be
used to hide the details of Tk path names from Tkx applications.
This provide a more "perlish" way to create and manipulate Tk widgets.

Our "Hello, world" program can be rewritten like this using the
C<Tkx::widget> class:

    use Tkx;
    
    my $mw = Tkx::widget->new(".");
    my $b = $mw->new_button(
        -text => "Hello, world",
        -command => sub { $mw->g_destroy; },
    );
    $b->g_pack;
    
    Tkx::MainLoop()

By loading the Tkx module we make the C<Tkx::widget> class
available and create the main window (the widget called C<.>).  Next
we instantiate a new C<Tkx::widget> object wrapping the main window.
It is customary to name this object C<$mw>.

To create a new button child widget we call C<< $mw->new_button >>
method.  Constructor methods are always prefixed with C<new_>.  The rest
of the method name is the name of the Tk widget to create; i.e. "button"
in this case.  Arguments are passed as before.

Calling a "g_" method will invoke the corresponding Tk command with the
widget path as argument.  In the code above we destroy the main window
by calling C<< $mw->g_destroy >> and we pack the button in the main
window by invoking C<< $b->g_pack >>.

Calling a "m_" method will invoke a Tk subcommand for the given
widget, but there is no example of this is the code above.  The most
commonly used subcommand is "configure" that is used to change the
attributes of a widget.  We could for instance change the text
displayed by the button by invoking:

    $b->m_configure(-text => "Goodbye, cruel world");

In the end we need to invoke the MainLoop as before.

For trivial programs like the one above using C<Tkx::widget> wrappers
does not appear to be a win, but as the application grows and the Tk
path names get longer it surely is.

=head2 Setting up a menu line

Most real GUI application will need a menu line at the top of the
application window or screen.  The following runnable program shows
how a minimal menu can be set up with Tkx:

     1	#!/usr/bin/perl -w
     2	
     3	use strict;
     4	use Tkx;
     5	
     6	our $VERSION = "1.00";
     7	
     8	(my $progname = $0) =~ s,.*[\\/],,;
     9	my $IS_AQUA = Tkx::tk_windowingsystem() eq "aqua";
    10	
    11	Tkx::package_require("style");
    12	Tkx::style__use("as", -priority => 70);
    13	
    14	my $mw = Tkx::widget->new(".");
    15	$mw->configure(-menu => mk_menu($mw));
    16	
    17	Tkx::MainLoop();
    18	exit;
    19	
    20	sub mk_menu {
    21	    my $mw = shift;
    22	    my $menu = $mw->new_menu;
    23	
    24	    my $file = $menu->new_menu(
    25	        -tearoff => 0,
    26	    );
    27	    $menu->add_cascade(
    28	        -label => "File",
    29	        -underline => 0,
    30	        -menu => $file,
    31	    );
    32	    $file->add_command(
    33	        -label => "New",
    34	        -underline => 0,
    35	        -accelerator => "Ctrl+N",
    36	        -command => \&new,
    37	    );
    38	    $mw->g_bind("<Control-n>", \&new);
    39	    $file->add_command(
    40	        -label   => "Exit",
    41	        -underline => 1,
    42	        -command => [\&Tkx::destroy, $mw],
    43	    ) unless $IS_AQUA;
    44	
    45	    my $help = $menu->new_menu(
    46	        -name => "help",
    47	        -tearoff => 0,
    48	    );
    49	    $menu->add_cascade(
    50	        -label => "Help",
    51	        -underline => 0,
    52	        -menu => $help,
    53	    );
    54	    $help->add_command(
    55	        -label => "\u$progname Manual",
    56	        -command => \&show_manual,
    57	    );
    58	
    59	    my $about_menu = $help;
    60	    if ($IS_AQUA) {
    61		# On Mac OS we want about box to appear in the application
    62		# menu.  Anything added to a menu with the name "apple" will
    63		# appear in this menu.
    64		$about_menu = $menu->new_menu(
    65		    -name => "apple",
    66	        );
    67		$menu->add_cascade(
    68		    -menu => $about_menu,
    69	        );
    70	    }
    71	    $about_menu->add_command(
    72	        -label => "About \u$progname",
    73	        -command => \&about,
    74	    );
    75	
    76	    return $menu;
    77	}
    78	
    79	
    80	sub about {
    81	    Tkx::tk___messageBox(
    82	        -parent => $mw,
    83	        -title => "About \u$progname",
    84	        -type => "ok",
    85	        -icon => "info",
    86	        -message => "$progname v$VERSION\n" .
    87	                    "Copyright 2005 ActiveState. " .
    88	                    "All rights reserved.",
    89	    );
    90	}

We start out as all proper Perl programs should by enabling warnings
and stricture at line 1 and 3.  Then we load Tkx which will create our
main application window at line 4.

In line 9 we initialize C<$IS_AQUA> constant.  Aqua is the native
interface of Mac OS X.  We need this constant because the menu layout
on Aqua is not the same as for the other windowing systems.  Note that
Tk on Mac OS X can be compiled against either Aqua or X11.  When our
application runs under X11 we want to use the standard Unix menu
layout, so it would not be correct to just make our code conditional
on what operating system it runs under (C<< $^O eq 'darwin' >> for Mac
OS X).

In line 11 and 12 we override the default look&feel style of Tk to a
more modern variant. Tcl packages can be loaded with the
C<Tkx::package_require()> function and we can access the Tcl command
C<style::use> as C<Tkx::style__use> in Perl, i.e. we need to turn the
double colon into a double underscore.  More about Tcl packages and
namespaces in the next section.

In line 14 we obtain a C<Tkx::widget> reference to the main window as
before and then we simply set up the application menu by setting up the
C<-menu> option of the main window in line 15.

In a real application there would be additional code between line 15
and 17 to set up the rest of the application window, but for this
demonstration we just leave the window empty.

In line 17 we ask Tk to start processing events, by invoking
C<Tkx::MainLoop()>.  This function will return when the application
window has been destroyed and when that happens we are done at line
18.

The application menu itself is set up and returned by the C<mk_menu()>
function in line 20 to 77.  This code should be easy enough to follow.
Note how we make I<File | New> and I<Help | Foo Manual> both reference
functions that are not yet written.  The application will still run,
but when you try to invoke these menu entries you get an "Application
Error Dialog" from Tk.  It is handy to be able to leave stubs like
this around during the development.  Just remember to add the C<new>
and C<show_manual> functions before the application ships. :-)

The C<-underline> options are provided to make it possible to select
menu entries with the keyboard.  The corresponding character of the
C<-label> will be underlined and you will be able to select this entry
by pressing the key when the menu is active.

It is also possible to set up direct keyboard shortcuts like we done
for the I<File | New> function at line 32.  Note that the
C<-accelerator> option only adds the text to the menu item, so we need
to use an explicit call to set up this binding as done in line 38.

For Aqua we don't want to add the "File | Exit" entry to the menu
because the OS itself always provide a Quit action in the application
menu.  Proper Aqua applications will also need to add the "About" function
on the application menu instead of the "Help" menu as is common on
other platforms.

The menu names "apple" and "help" provided in line 46 and 65 has
special significance to Tk.  Menu items added to the "apple" menu
will show up in the application menu.  The name is historic from the
time when this stuff would actually show in the menu with the picture
of the Apple logo.  In Mac OS X these entries show up at the top of
the menu just right of the apple.  If not provided C<Tk> will provide
its own "About" entry that will tell you about what version of
Tcl/Tk you are using.  A menu called "help" menu will be flushed
right on Unix even though this style seems to be out of fashion in
modern Unix applications.

The Tkx distribution contain a script called F<menu> which is a
runnable version of the program shown here.  You might want to use
this as a starting point for your own Tkx applications.

=head2 Using Tcl packages

When the Perl application starts up and load Tkx, the only functions
available in the C<Tkx::> namespace are those commands provided by core
Tcl/Tk.  These commands are described in the "Tcl" and "Tk" sections
at L<http://aspn.activestate.com/ASPN/docs/ActiveTcl/at.pkg_index.html>.

Additional commands can be loaded from Tcl packages.  Once loaded new
commands show up in the C<Tkx::> namespace.  This example loads the
"Tktable" package in order to make the C<table> command to create
I<table> widgets available:

    use Tkx;
    Tkx::package_require("Tktable");

    my $mw = Tkx::widget->new(".");
    my $t = $mw->new_table(
        -rows => 5,
        -cols => 3,
    );
    $t->g_pack;
    
    Tkx::MainLoop()

Packages are loaded by calling the C<Tkx::package_require()> function
taking the package name as argument.  An optional version number can
be provided as the second argument if you want to make sure a certain
version or newer is loaded.

One source of confusion here is what the proper spelling of the
package name to provide to Tkx::package_require() is.  The Tcl/Tk
documentation will call the package in the example above I<TkTable>
(with two upper case "T"s) and not really mention the exact spelling
of the package name (only one upper case "T").  In some cases the
"synopsis" section describing the package will spell out the package
name, but in cases like this we have found no better way than to peek
into the F<pkgIndex.tcl> files in the Tcl C<lib/> area if loading the
package fails.  The package documented as "BWidgets" should be loaded
as "BWidget" (without the "s") and the package documented as
"IWidgets" should be loaded as "Iwidgets" (with a lower case "w").
Somebody ought to be spanked.

Most modern Tcl packages will not create names at the top level like
TkTable did above.  Instead they will create functions in a Tcl
namespace with a name matching the package name.  In the menu example
of the previous section we loaded the "style" package which created a
command called "use" in the "style" namespace.  This command can be
referenced as "::style::use" or "style::use" from Tcl.  From Perl this
maps to a function called C<Tkx::style__use>, i.e. we replace the
double colon with double underscore and ignore the colon in the front.
Read L<Tkx> for details about how sequences of "_" in C<Tkx::> names
are mapped to Tcl names.

=head2 Setting up application icons

Not written yet.

=head2 Subclassing Tkx::widget

Not written yet.

=head2 Megawidgets

Not written yet.

=head1 LICENSE

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

Copyright 2005 ActiveState.  All rights reserved.

=head1 SEE ALSO

L<Tkx>

L<tkxed>
