############################################################################### # # Win32::GUI::XMLBuilder # # 14 Dec 2003 by Blair Sutton # # Version: 0.39 (25th January 2007) # # Copyright (c) 2003-2007 Blair Sutton. All rights reserved. # This program is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # ############################################################################### package Win32::GUI::XMLBuilder; use strict; require Exporter; our $VERSION = 0.39; our @ISA = qw(Exporter); our $AUTHOR = "Blair Sutton - 2007 - Win32::GUI::XMLBuilder - $VERSION"; use XML::Twig; use Win32::GUI qw(WS_CAPTION WS_SIZEBOX WS_EX_CONTROLPARENT WS_CHILD DS_CONTROL WS_VISIBLE WS_VSCROLL WS_TABSTOP); use Win32::GUI::BitmapInline (); our $ICON = newIcon Win32::GUI::BitmapInline( q( AAABAAEAICAAAAEAGACoDAAAFgAAACgAAAAgAAAAQAAAAAEAGAAAAAAAAAAAAEgAAABIAAAAAAAA AAAAAAD///////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////cyfzJrfvcyfzcyfzJrfv////////////cyfzJ rfvcyfz////////////JrfvJrfvcyfz///////////////////////////////////////////// //////////+UW/ZeCfJeCfJeCfJwJfNeCfL////t5P6CQPVeCfJeCfJeCfJwJfPt5P7///9eCfJe CfKUW/b////////////////////////////////////////////////////t5P5eCfJeCfKCQPVw JfNeCfJeCfL///+md/heCfJeCfKUW/ZeCfJeCfKmd/j///9eCfJeCfKUW/b///////////////// ///////////////////////////////////JrfteCfJeCfLJrfuUW/ZeCfJeCfL///+UW/ZeCfJe CfL///9eCfJeCfKUW/b///9eCfJeCfKUW/b///////////////////////////////////////// ///////////JrfteCfJeCfLJrfuCQPVeCfJeCfL///+UW/ZeCfJeCfL///9eCfJeCfKUW/b///9e CfJeCfKUW/b////////////////////////////////////////////////////JrfteCfJeCfLJ rfteCfJeCfJeCfL///+UW/ZeCfJeCfL///9eCfJeCfKUW/b///9eCfJeCfKUW/b///////////// ///////////////////////////////////////JrfteCfJeCfLJrfvJrfvJrfvJrfv///+UW/Ze CfJeCfL///9eCfJeCfKUW/b///9eCfJeCfKUW/b///////////////////////////////////// ///////////////JrfteCfJeCfLJrfu4kvmUW/aUW/b///+UW/ZeCfJeCfL///9eCfJeCfKUW/b/ //9eCfJeCfKUW/b////////////////////////////////////////////////////JrfteCfJe CfLJrfuUW/ZeCfJeCfL///+UW/ZeCfJeCfL///9eCfJeCfKUW/b///9eCfJeCfKUW/b///////// ///////////////////////////////////////////JrfteCfJeCfKmd/iCQPVeCfJwJfP///+U W/ZeCfJeCfL///9eCfJeCfKUW/b///9eCfJeCfKUW/b///////////////////////////////// //////////////////////9wJfNeCfJeCfJeCfJeCfLJrfv///+UW/ZeCfJeCfL///9eCfJeCfKU W/b///9eCfJeCfKUW/b///////////////////////////////////////////////////////// //+4kvmUW/aUW/bcyfz///////+4kvmUW/aUW/b///+UW/aUW/a4kvn///+UW/aUW/a4kvn///// ///////////HyceOko7///////////+Oko7Hycf///////+Oko7///+Oko7///////+Oko7////H ycdVW1Vyd3Lj5OPHycdVW1VVW1VVW1WOko7///////////////////////////9yd3I5QDn///// //////85QDlyd3L///////9VW1X///9VW1X///////9VW1XHycdVW1X////j5ONVW1X///9yd3Lj 5OP///////////////////////////////////85QDmOko6qrar///+qraqOko5VW1X///////9V W1X///9VW1X///////9VW1X///////////////9VW1X///////9yd3Lj5OP///////////////// ///////////j5ONVW1Xj5ONVW1X///9yd3Lj5ONVW1Xj5OP///9VW1X///9VW1X///////9VW1X/ ///////HyceOko5VW1X///////////9yd3Lj5OP///////////////////////+qraqqrar///9V W1X///9VW1X///+qraqqrar///9VW1X///8ACQCOko6Oko5yd3L////////Hycdyd3Kqrar///// ///////j5ONyd3L///////////////////////9VW1X///////+Oko6Oko6Oko7///////9VW1X/ ///Hycf////HycfHyceqrar////Hyceqrar///////9VW1XHycfHycf////j5ONVW1X///////// //////////////9VW1X////////j5OMdJR3j5OP///////9VW1X///+Oko7///////////////// //////9VW1VVW1U5QDnj5OP///9VW1VVW1U5QDnj5OP////////////////////6WmT+5Ob///// ///////////////7dn/8rLL////6WmT9ycz////////6WmT7kZj////////6WmT9ycz////9ycz6 WmT6WmT6WmT6WmT6WmT6WmT////////////////6WmT4IzH+5Ob////////////7kZj3Bxf+5Ob/ ///5Pkv6WmT////////3Bxf3Bxf+5Ob////6WmT6WmT////+5Ob3Bxf5Pkv6WmT6WmT6WmT6WmT9 ycz////////////////6WmT4IzH+5Ob////+5Ob4IzH7kZj////////7dn/5Pkv////////3Bxf3 Bxf7dn/////7dn/5Pkv////////3Bxf7kZj////////////////////////////////////////6 WmT4IzH+5Ob7dn/4IzH////////////8rLL3Bxf////8rLL3Bxf8rLL3Bxf+5Ob8rLL3Bxf///// ///6WmT6WmT////////////////////////////////////////////6WmT4IzH3Bxf8rLL///// ///////+5Ob3Bxf9ycz8rLL3Bxf////4IzH7dn/+5Ob3Bxf9ycz////7dn/4IzH///////////// ///////////////////////////////////4IzH3Bxf+5Ob////////////////4IzH7kZj8rLL3 Bxf////7kZj3Bxf+5Ob4IzH7kZj////8rLL3Bxf///////////////////////////////////// ///////8rLL3Bxf6WmT4IzH+5Ob////////////6WmT6WmT7dn/5Pkv////////4IzH7dn/6WmT6 WmT////+5Ob3Bxf8rLL////////////////////////////////////////4IzH7dn/////6WmT4 IzH+5Ob////////7kZj4IzH6WmT6WmT////////7kZj3Bxf7dn/4IzH////////3Bxf7kZj///// ///////////////////////////////7kZj4IzH+5Ob////////6WmT4IzH+5Ob////8rLL3Bxf5 Pkv6WmT////////////4IzH5Pkv3Bxf////////6WmT6WmT///////////////////////////// ///+5Ob3Bxf7kZj////////////////6WmT4IzH+5Ob////3Bxf3Bxf7kZj////////////7kZj3 Bxf3Bxf8rLL////7dn/4IzH////////////////////////////////+5Ob8rLL///////////// ///////////8rLL9ycz////8rLL8rLL+5Ob////////////////8rLL8rLL+5Ob////+5Ob8rLL/ //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////8A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAA== ) ); =head1 NAME XMLBuilder - Build Win32::GUIs using XML. =head1 SYNOPSIS use Win32::GUI::XMLBuilder; my $gui = Win32::GUI::XMLBuilder->new({file=>"file.xml"}); my $gui = Win32::GUI::XMLBuilder->new(*DATA); Win32::GUI::Dialog; sub test { $gui->{Status}->Text("testing 1 2 3.."); } ... __END__ .. =head1 DEPENDENCIES XML::Twig Win32::GUI =head1 DESCRIPTION This module allows Win32::GUIs to be built using XML. For examples on usage please look in samples/ directory. =head1 XML SYNTAX XMLBuilder will parse an XML file or string that contains elements that describe a Win32::GUI object. All XML documents must be enclosed in .. elements and each separate GUI window must be enclosed in .. elements. To create a N-tier window system one might use a construction similar to: - ... ... ... =head1 ATTRIBUTES Elements can additionally be supplemented with attributes that describe its corresponding Win32::GUI object's properties such as top, left, height and width. These properties usually include those provided as standard in each Win32::GUI class. I.e. Elements that require referencing in your code should be given a name attribute. An element with attribute: - and are equivalent but the former is more true to what is happening under the hood. One can generally pass a Button to TrackPopupMenu and a Button handle to MDIClient's windowmenu attribute. A separator line can be specified by setting the separator attribute to 1. One can also use NEM events directly as attributes such as onClick (or OEM events by using PopupMenu_Click), etc.. See the menus.xml for an extensive example in the samples/ directory. =cut sub WGXMenu { my ($self, $t, $e) = @_; my $name = $self->genname($e); $self->debug("\nWGXMenu: $name"); $self->{$name} = new Win32::GUI::Menu() || $self->error; foreach my $button ($e->children()) { next if $button->gi !~ /^(Item|Button)$/; $self->WGXMenu_Button($button, $name); } } sub WGXMenu_Button { my ($self, $e, $parent) = @_; my $name = $self->genname($e); $e->{'att'}->{'id'} = $self->{_menuid_}++; $self->debug("\nWGXMenu_Button: $name"); $self->{$name} = $self->{$parent}->AddMenuButton($self->evalhash($e)); foreach my $item ($e->children()) { $item->{'att'}->{'id'} = $self->{_menuid_}++; my $iname = $self->genname($item); if ($item->gi eq 'Button' || $item->children_count()) { $self->{'submenu'.$self->{_menuid_}} = new Win32::GUI::Menu(); my $bname = $self->WGXMenu_Button($item, 'submenu'.$self->{_menuid_}); $item->{'att'}->{'submenu'} = $self->{$bname}; $self->{$name}->AddMenuItem($self->evalhash($item)); } elsif ($item->gi eq 'Item') { $self->{$iname} = $self->{$name}->AddMenuItem($self->evalhash($item)); } } return $name; } =item Creates a menu system. The amount of '>'s prefixing a text label specifies the menu items depth. A value of text '-' (includes '>-', '>>-', etc) creates a separator line. To access named menu items one must use the menu widgets name, i.e. $gui->{PopupMenu}->{SelectAll}, although one can access an event by its name, i.e. SelectAll_Click. One can also use NEM events directly as attributes such as onClick, etc.. See the makemenu.xml example in the samples/ directory. The MakeMenu element suffers from the limitation of being only able to nest menus to 2 layers. This is inherent from the underlying Win32::GUI module. I would suggest using the more configurable WGXMenu above. The element was previously called . The tag is deprecated but remains only for backward compatibility and will be removed in a later release. Please try to update your code to use MakeMenu instead. =cut sub Menu { MakeMenu(@_) } sub MakeMenu { my ($self, $t, $e) = @_; my $name = $self->genname($e); $self->debug("\nMenu: $name"); my @m; foreach ($e->children()) { next if $_->gi ne 'Item'; $_->{'att'}->{'name'} = '0' if ! exists $_->{'att'}->{'name'}; my $label = $_->{'att'}->{'text'}; $self->debug("Text: $label"); delete $_->{'att'}->{'text'}; # prevents preformated text becoming label push @m, $label, { $self->evalhash($_) }; } $self->{$name} = Win32::GUI::MakeMenu(@m) || $self->error; } =item Creates a key accelerator table. =cut sub AcceleratorTable { my ($self, $t, $e) = @_; my $name = $self->genname($e); $self->debug("\nAcceleratorTable: $name"); my @a; foreach ($e->children()) { my $key = $_->{'att'}->{'key'}; my $sub = $_->{'att'}->{'sub'}; if ($sub =~ /^\s*sub\s*\{.*\}\s*/) { $sub = eval "{ package main; no strict; use Win32::GUI(); ".$sub."}"; print STDERR $@ if $@; } else { $sub = \&{'::'.$sub}; } $self->debug("$key -> $sub"); push @a, $key, $sub; } $self->{$name} = new Win32::GUI::AcceleratorTable(@a) || $self->error; } =item The element creates a top level widget. In addition to standard Win32::GUI::Window attributes it also has a 'show=n' attribute. This instructs XMLBuilder to give the window a Show(n) command on invocation. NOTE: Since the onResize event is defined automatically for the this element one must set the attribute 'eventmodel' to 'both' to allow _Event events to be caught! =item is very similar to , except that by default it cannot be resized and it doesn't have the minimize and maximize buttons. =item The element creates a Multiple Document Interface. It has a similar behaviour to the attribute. PLease see the MDI.xml sample. =cut sub _GenericTop { my ($self, $t, $e) = @_; my $widget = $e->gi; my $name = $self->genname($e); # should this be allowed? my $show = $e->{'att'}->{'show'}; $self->debug("\n$widget (_GenericTop): $name"); $self->{$name} = eval "new Win32::GUI::$widget(\$self->evalhash(\$e))" || $self->error; $self->{$name}->SetEvent('Resize', $self->genresize($name)); ${$self->{_show_}}{$name} = $show eq '' ? 1 : $show; foreach ($e->children()) { if (exists &{$_->gi}) { &{\&{$_->gi}}($self, $t, $_); } else { $self->_Generic($t, $_); } } } =item A WGXPanel is a shorthand for a Window element with popstyles WS_CAPTION, WS_SIZEBOX and WS_EX_CONTROLPARENT and pushstyles WS_CHILD, DS_CONTROL and WS_VISIBLE. It is useful for grouping controls together. ... =cut sub WGXPanel { my ($self, $t, $e) = @_; my $name = $self->genname($e); my $parent = $self->getParent($e); my $show = $e->{'att'}->{'show'}; $self->debug("\nWGXPanel: $name; Parent: $parent"); $e->{'att'}->{'parent'} = $self->{$parent}; $e->{'att'}->{'popstyle'} = WS_CAPTION()|WS_SIZEBOX()|WS_EX_CONTROLPARENT(); $e->{'att'}->{'pushstyle'} = WS_CHILD()|DS_CONTROL()|WS_VISIBLE(); $self->debug("\nWGXPanel: $name"); $self->{$name} = eval "new Win32::GUI::Window(\$self->evalhash(\$e))" || $self->error; $self->{$name}->SetEvent('Resize', $self->genresize($name)); ${$self->{_show_}}{$name} = $show eq '' ? 1 : $show; foreach ($e->children()) { if (exists &{$_->gi}) { &{\&{$_->gi}}($self, $t, $_); } else { $self->_Generic($t, $_); } } } =item Creates a TreeView. These can be nested deeply using the sub element . Please look at the treeview.pl example in the samples/ directory. etc... ... =cut sub TreeView { my ($self, $t, $e) = @_; my $name = $self->genname($e); my $parent = $self->getParent($e); $self->debug("\nTreeView: $name; Parent: $parent"); $self->{$name} = $self->{$parent}->AddTreeView($self->evalhash($e)) || $self->error; if($e->children_count()) { $self->TreeView_Item($e, $name); } } sub TreeView_Item { my ($self, $e, $parent) = @_; my $name = $e->{'att'}->{'name'}; foreach my $item ($e->children()) { next if $item->gi ne 'Item'; my $iname = $item->{'att'}->{'name'}; $self->debug("Item: $iname; Parent: $name"); $item->{'att'}->{'parent'} = "\$self->{$name}" if $name ne $parent; $self->{$iname} = $self->{$parent}->InsertItem($self->evalhash($item)); if($item->children_count()) { $self->TreeView_Item($item, $parent); } } } =item Generate a combobox with drop down items specified with the elements. In addition to standard attributes for Win32::GUI::Combobox there is also a 'dropdown' attribute that automatically sets the 'pushstyle' to 'WS_VISIBLE()|0x3|WS_VSCROLL()|WS_TABSTOP()'. In 'dropdown' mode an element has the additional attribute 'default'. =cut sub Combobox { my ($self, $t, $e) = @_; my $name = $self->genname($e); my $parent = $self->getParent($e); $self->debug("\nCombobox: $name; Parent: $parent"); $e->{'att'}->{'pushstyle'} = WS_VISIBLE()|0x3|WS_VSCROLL()|WS_TABSTOP() if $e->{'att'}->{'dropdown'}; $self->{$name} = $self->{$parent}->AddCombobox($self->evalhash($e)) || $self->error; my $default; if($e->children_count()) { foreach my $item ($e->children()) { next if $item->gi ne 'Item'; my $text = $item->{'att'}->{'text'}; $default = $text if $item->{'att'}->{'default'}; $self->debug("Item: $text"); $self->{$name}->InsertItem($text); } } $self->{$name}->Select($self->{$name}->FindStringExact($default)) if $default; } =item Generate a listbox with drop down items specified with the elements. In addition to standard attributes for Win32::GUI::Listbox there is also a 'dropdown' attribute that automatically sets the 'pushstyle' to 'WS_CHILD()|WS_VISIBLE()|1'. In 'dropdown' mode an element has the additional attribute 'default'. =cut sub Listbox { my ($self, $t, $e) = @_; my $name = $self->genname($e); my $parent = $self->getParent($e); $self->debug("\nListbox: $name; Parent: $parent"); $e->{'att'}->{'pushstyle'} = $e->{'att'}->{'dropdown'} ? WS_VSCROLL()|WS_CHILD()|WS_VISIBLE()|1 : WS_VSCROLL()|WS_VISIBLE()|WS_CHILD(); $self->{$name} = $self->{$parent}->AddListbox($self->evalhash($e)) || $self->error; # $self->{$name}->SendMessage(0x0195, 201, 0); my $default; if($e->children_count()) { foreach my $item ($e->children()) { next if $item->gi ne 'Item'; my $text = $item->{'att'}->{'text'}; $default = $text if $item->{'att'}->{'default'}; $self->debug("Item: $text"); $self->{$name}->AddString($text); } } $self->{$name}->Select($self->{$name}->FindStringExact($default)) if $default; } =item See rebar.xml example in samples/ directory. =cut sub Rebar { my ($self, $t, $e) = @_; my $name = $self->genname($e); my $parent = $self->getParent($e); $self->debug("\nRebar: $name; Parent: $parent"); $self->{$name} = $self->{$parent}->AddRebar($self->evalhash($e)) || $self->error; foreach my $item ($e->children()) { my $bname = $self->genname($item); $self->debug("Band: $bname"); my $f; $f->{'att'}->{'parent'} = $self->{$parent}; $f->{'att'}->{'popstyle'} = WS_CAPTION()|WS_SIZEBOX(); $f->{'att'}->{'pushstyle'} = WS_CHILD(); # push non-Band attributes into Window class foreach (keys %{$item->{'att'}}) { if ($_ !~ /^(image|index|bitmap|child|foreground|background|width|minwidth|minheight|text|style)$/) { $f->{'att'}->{$_} = $item->{'att'}->{$_}; } } $self->debug("Window: $bname"); $self->{$bname} = new Win32::GUI::Window($self->evalhash($f)) || $self->error; $item->{'att'}->{'child'} = $self->{$bname}; $self->{$bname}->SetEvent('Resize', $self->genresize($bname)); foreach ($item->children()) { $self->debug($_->{'att'}->{'name'}); $self->debug($_->gi); if (exists &{$_->gi}) { &{\&{$_->gi}}($self, $t, $_); } else { $self->_Generic($t, $_); } } $self->{$name}->InsertBand($self->evalhash($item)); } } =item A TabStrip can be created using the following structure: - See wizard_tabstrip.xml example in samples/ directory. =item A TabFrame should behave identically to a TabStrip. TabFrame is no longer supported and will be removed from a future release. Please try to update your code to use TabStrip instead. =cut sub TabFrame { TabStrip(@_); } sub TabStrip { my ($self, $t, $e) = @_; my $name = $self->genname($e); my $parent = $self->getParent($e); $e->{'att'}->{'onChange'} = "sub { my \$i; for (\$i = 0; \$i < \$_[0]->Count; \$i++) { \$self->{\$self->{$name}->{\$i}}->Show(\$_[0]->SelectedItem == \$i ? 1 : 0); } }"; $self->debug("\nTabStrip: $name; Parent: $parent"); $self->{$name} = $self->{$parent}->AddTabStrip($self->evalhash($e)) || $self->error; my $tabcount = 0; foreach my $item ($e->children()) { my $bname = $self->genname($item); $self->debug("Tab: $bname"); my $f; $f->{'att'}->{'parent'} = $self->{$parent}; $f->{'att'}->{'popstyle'} = WS_CAPTION()|WS_SIZEBOX()|WS_EX_CONTROLPARENT(); $f->{'att'}->{'pushstyle'} = WS_CHILD()|DS_CONTROL(); $f->{'att'}->{'pushstyle'} |= WS_VISIBLE() if $tabcount == 0; $self->{$name}->InsertItem($self->evalhash($item)); # push non-Item attributes into Window class foreach (keys %{$item->{'att'}}) { if ($_ !~ /^(image|index|text)$/) { $f->{'att'}->{$_} = $item->{'att'}->{$_}; } } ($f->{'att'}->{'left'}, $f->{'att'}->{'top'}, $f->{'att'}->{'width'}, $f->{'att'}->{'height'}) = ( $self->{$name}->Left + ($self->{$name}->DisplayArea)[0], $self->{$name}->Top + ($self->{$name}->DisplayArea)[1], ($self->{$name}->DisplayArea)[2], ($self->{$name}->DisplayArea)[3], ); $self->debug("Window: $bname"); $self->{$bname} = new Win32::GUI::Window($self->evalhash($f)) || $self->error; $self->{$bname}->SetEvent('Resize', $self->genresize($bname)); $self->{_left_}{$parent}{$bname} = "\$self->{$name}->Left + (\$self->{$name}->DisplayArea)[0]"; $self->{_top_}{$parent}{$bname} = "\$self->{$name}->Top + (\$self->{$name}->DisplayArea)[1]"; $self->{_width_}{$parent}{$bname} = "(\$self->{$name}->DisplayArea)[2]"; $self->{_height_}{$parent}{$bname} = "(\$self->{$name}->DisplayArea)[3]"; push @{$self->{_worder_}{$parent}}, $bname; push @{$self->{_horder_}{$parent}}, $bname; push @{$self->{_lorder_}{$parent}}, $bname; push @{$self->{_torder_}{$parent}}, $bname; $self->{$name}->{$tabcount} = $bname; # stash index to name mapping! foreach ($item->children()) { $self->debug($_->{'att'}->{'name'}); $self->debug($_->gi); if (exists &{$_->gi}) { &{\&{$_->gi}}($self, $t, $_); } else { $self->_Generic($t, $_); } } $tabcount++; } } =item A WGXSplitter can be created using the following structure: - The reason this is called a WGXSplitter is because it does not exist as a super-class to a Splitter object. It's width dimension for example holds the complete width of both panes and its splitterwidth ... See splitter.xml example in samples/ directory. =cut sub WGXSplitter { my ($self, $t, $e) = @_; my $name = $self->genname($e); my $parent = $self->getParent($e); $e = $self->expandDimensions($e); if (exists $e->{'att'}->{'range'}) { if ($e->{'att'}->{'range'} =~ m/^\s*(.+)\s*,\s*(.+)\s*$/) { ($e->{'att'}->{'min'}, $e->{'att'}->{'max'}) = ($1, $2); delete $e->{'att'}->{'range'}; } else { $self->debug("Failed to parse range '$e->{'att'}->{'range'}', should have format '[min, max]'"); } } my ($LEFT, $TOP, $WIDTH, $HEIGHT); if($e->{'att'}->{'horizontal'}) { $e->{'att'}->{'_notop_'} = 1; $e->{'att'}->{'_noheight_'} = 1; $TOP = $e->{'att'}->{'top'}; $e->{'att'}->{'top'} = "exec:".join('+', map { s/^exec://; $_ } $TOP, $e->{'att'}->{'start'}); $HEIGHT = $e->{'att'}->{'height'}; $e->{'att'}->{'height'} = $e->{'att'}->{'splittersize'}; $e->{'att'}->{'min'} = "exec:".join('+', map { s/^exec://; $_ } $TOP, $e->{'att'}->{'min'}) if exists $e->{'att'}->{'min'}; $e->{'att'}->{'max'} = "exec:".join('+', map { s/^exec://; $_ } $TOP, $e->{'att'}->{'max'}) if exists $e->{'att'}->{'max'}; $e->{'att'}->{'onRelease'} = "sub { \$self->{\$self->{$name}->{0}}->Move(\$_[0]->Left, $TOP); \$self->{\$self->{$name}->{0}}->Resize(\$_[0]->Width, \$_[1] - $TOP); \$self->{\$self->{$name}->{1}}->Move(\$_[0]->Left, \$_[1] + \$_[0]->Height); \$self->{\$self->{$name}->{1}}->Resize(\$_[0]->Width, $HEIGHT - \$_[0]->Height - \$_[1] + $TOP); }"; } else { $e->{'att'}->{'_noleft_'} = 1; $e->{'att'}->{'_nowidth_'} = 1; $LEFT = $e->{'att'}->{'left'}; $e->{'att'}->{'left'} = "exec:".join('+', map { s/^exec://; $_ } $LEFT, $e->{'att'}->{'start'}); $WIDTH = $e->{'att'}->{'width'}; $e->{'att'}->{'width'} = $e->{'att'}->{'splittersize'}; $e->{'att'}->{'min'} = "exec:".join('+', map { s/^exec://; $_ } $LEFT, $e->{'att'}->{'min'}) if exists $e->{'att'}->{'min'}; $e->{'att'}->{'max'} = "exec:".join('+', map { s/^exec://; $_ } $LEFT, $e->{'att'}->{'max'}) if exists $e->{'att'}->{'max'}; $e->{'att'}->{'onRelease'} = "sub { \$self->{\$self->{$name}->{0}}->Move($LEFT, \$_[0]->Top); \$self->{\$self->{$name}->{0}}->Resize(\$_[1] - $LEFT, \$_[0]->Height); \$self->{\$self->{$name}->{1}}->Move(\$_[1] + \$_[0]->Width, \$_[0]->Top); \$self->{\$self->{$name}->{1}}->Resize($WIDTH - \$_[0]->Width - \$_[1] + $LEFT, \$_[0]->Height); }"; } $self->debug("\nWGXSplitter: $name; Parent: $parent"); $self->{$name} = $self->{$parent}->AddSplitter($self->evalhash($e)) || $self->error; my $tabcount = 0; foreach my $item ($e->children()) { my $bname = $self->genname($item); $self->debug("Pane: $bname"); my $f; $f->{'att'}->{'parent'} = $self->{$parent}; $f->{'att'}->{'popstyle'} = WS_CAPTION()|WS_SIZEBOX()|WS_EX_CONTROLPARENT(); $f->{'att'}->{'pushstyle'} = WS_CHILD()|DS_CONTROL()|WS_VISIBLE(); # push attributes into Window class foreach (keys %{$item->{'att'}}) { $f->{'att'}->{$_} = $item->{'att'}->{$_}; } $self->debug("Window: $bname"); $self->{$bname} = new Win32::GUI::Window($self->evalhash($f)) || $self->error; $self->{$bname}->SetEvent('Resize', $self->genresize($bname)); if($e->{'att'}->{'horizontal'}) { $self->{_left_}{$parent}{$bname} = $tabcount == 0 ? "\$self->{$name}->Left" : "\$self->{$name}->Left"; $self->{_top_}{$parent}{$bname} = $tabcount == 0 ? "$TOP" : "\$self->{$name}->Top + \$self->{$name}->Height"; $self->{_width_}{$parent}{$bname} = $tabcount == 0 ? "\$self->{$name}->Width" : "\$self->{$name}->Width"; $self->{_height_}{$parent}{$bname} = $tabcount == 0 ? "\$self->{$name}->Top - $TOP" : "$HEIGHT - \$self->{$name}->Top - \$self->{$name}->Height + $TOP"; } else { $self->{_left_}{$parent}{$bname} = $tabcount == 0 ? "$LEFT" : "\$self->{$name}->Left + \$self->{$name}->Width"; $self->{_top_}{$parent}{$bname} = $tabcount == 0 ? "\$self->{$name}->Top" : "\$self->{$name}->Top"; $self->{_width_}{$parent}{$bname} = $tabcount == 0 ? "\$self->{$name}->Left - $LEFT" : "$WIDTH - \$self->{$name}->Width - \$self->{$name}->Left + $LEFT"; $self->{_height_}{$parent}{$bname} = $tabcount == 0 ? "\$self->{$name}->Height" : "\$self->{$name}->Height"; } push @{$self->{_worder_}{$parent}}, $bname; push @{$self->{_horder_}{$parent}}, $bname; push @{$self->{_lorder_}{$parent}}, $bname; push @{$self->{_torder_}{$parent}}, $bname; $self->{$name}->{$tabcount} = $bname; # stash index to name mapping! foreach ($item->children()) { $self->debug($_->{'att'}->{'name'}); $self->debug($_->gi); if (exists &{$_->gi}) { &{\&{$_->gi}}($self, $t, $_); } else { $self->_Generic($t, $_); } } $tabcount++; } } =item Allows you to create a timer for use in your program. =cut sub Timer { my ($self, $t, $e) = @_; my $name = $self->genname($e); my $parent = $self->getParent($e); my $elapse = $e->{'att'}->{'elapse'}; $self->debug("\nTimer: $name, $elapse, ($parent)"); $self->{$name} = new Win32::GUI::Timer($self->{$parent}, $name, $elapse) || $self->error; } =item Generic Elements Any widget not explicitly mentioned above can be generated by using its name as an element id. For example a Button widget can be created using: -