view release on metacpan or search on metacpan
lib/Games/Axmud/OtherWin.pm view on Meta::CPAN
# Standard IVs for 'free' windows
# The window's default size, in pixels
widthPixels => $widthPixels,
heightPixels => $heightPixels,
# Default border/item spacing sizes used in the window, in pixels
borderPixels => $axmud::CLIENT->constFreeBorderPixels,
spacingPixels => $axmud::CLIENT->constFreeSpacingPixels,
# A string to use as the window title. If 'undef', a generic title is used
title => $axmud::SCRIPT . ' information',
# Hash containing any number of key-value pairs needed for this particular 'config'
# window; for example, for example, GA::PrefWin::TaskStart uses it to specify a task
# name and type. Set to an empty hash if not required
configHash => {%configHash},
# IVs for this type of window
# Widgets
notebook => undef, # Gtk3::Notebook
button => undef, # Gtk3::Button
};
# Bless the object into existence
bless $self, $class;
return $self;
}
##################
# Methods
# Standard window object functions
# sub winSetup {} # Inherited from GA::Generic::FreeWin
sub winEnable {
# Called by GA::Generic::Win->createFreeWin, after the call to $self->winSetup
# After the Gtk3::Window has been setup and moved into position, makes it visible
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 on success
my ($self, $check) = @_;
# Local variables
my $firstTab;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->winEnable', @_);
}
# Make the window appear on the desktop
$self->winShowAll($self->_objClass . '->winEnable');
$self->ivPoke('enabledFlag', TRUE);
# This type of window is unique (only one can be open at any time); inform the GA::Client
# it has opened
$axmud::CLIENT->set_aboutWin($self);
# If a tab to show on startup was specified, open it
$firstTab = $self->ivShow('configHash', 'first_tab');
if (defined $firstTab) {
# (Window is open at the 'about' tab by default, so we don't have to check that
# $firstTab is set to 'about')
if ($firstTab eq 'credits') {
$self->notebook->set_current_page(1);
} elsif ($firstTab eq 'help') {
$self->notebook->set_current_page(2);
} elsif ($firstTab eq 'peek') {
$self->notebook->set_current_page(3);
} elsif ($firstTab eq 'changes') {
$self->notebook->set_current_page(4);
} elsif ($firstTab eq 'install') {
$self->notebook->set_current_page(5);
} elsif ($firstTab eq 'license') {
$self->notebook->set_current_page(6);
} elsif ($firstTab eq 'license_2') {
$self->notebook->set_current_page(7);
}
}
return 1;
}
# sub winDesengage {} # Inherited from GA::Generic::FreeWin
sub winDestroy {
# Can be called by anything
# Updates IVs
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments, if the window can't be destroyed or if it has already
# been destroyed
# 1 on success
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->winDestroy', @_);
}
if (! $self->winBox) {
# Window already destroyed in a previous call to this function
return undef;
}
# Close any 'free' windows for which this window is a parent
foreach my $winObj ($self->ivValues('childFreeWinHash')) {
$winObj->winDestroy();
}
# Destroy the Gtk3::Window
eval { $self->winBox->destroy(); };
if ($@) {
# Window can't be destroyed
return undef;
} else {
$self->ivUndef('winWidget');
$self->ivUndef('winBox');
}
# Inform the owner and the desktop object of this 'free' window's demise
$axmud::CLIENT->desktopObj->del_freeWin($self);
if ($self->owner) {
$self->owner->del_childFreeWin($self);
}
# This type of window is unique (only one can be open at any time); inform the GA::Client
# it has closed
$axmud::CLIENT->set_aboutWin();
return 1;
}
# sub winShowAll {} # Inherited from GA::Generic::Win
sub drawWidgets {
# Called by $self->winSetup
# Sets up the About window with its standard widgets
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my (
$file, $fileHandle,
@aboutList, @helpList, @peekList, @changesList, @installList, @licenseList,
@license2List,
);
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->drawWidgets', @_);
}
# Create a packing box
my $packingBox = Gtk3::VBox->new(FALSE, 0);
$self->winBox->add($packingBox);
$packingBox->set_border_width(0);
# Create an image on the left
my $hBox = Gtk3::HBox->new(FALSE, 0);
$packingBox->pack_start($hBox, TRUE, TRUE, 0);
my $vBox = Gtk3::VBox->new(FALSE, 0);
$hBox->pack_start($vBox, FALSE, FALSE, 0);
my $frame = Gtk3::Frame->new(undef);
$vBox->pack_start($frame, FALSE, FALSE, 0);
$frame->set_size_request(64, 64);
$frame->set_shadow_type($axmud::CLIENT->constShadowType);
my $image = Gtk3::Image->new_from_file($axmud::CLIENT->getDialogueIcon());
$frame->add($image);
lib/Games/Axmud/OtherWin.pm view on Meta::CPAN
}
# Add the 'license' tab to the notebook
$self->addTab($notebook, '_LGPL License', FALSE, @license2List);
# Update IVs
$self->ivPoke('packingBox', $packingBox);
$self->ivPoke('notebook', $notebook);
$self->ivPoke('button', $button);
return 1;
}
# sub redrawWidgets {} # Inherited from GA::Generic::Win
# ->signal_connects
# Other functions
sub addTab {
# Called by $self->drawWidgets
# Adds a tab to the About window's notebook
#
# Expected arguments
# $notebook - The Gtk3::Notebook to which the tab must be added
# $label - The tab's label text
#
# Optional arguments
# $newlineFlag - TRUE if a newline character should be added to every line in @list,
# FALSE if not (because the contents of @list were loaded from a file
# and already contain newline characters)
# @list - A list of lines to add to the Gtk3::TextView (can be an empty list)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $notebook, $label, $newlineFlag, @list) = @_;
# Check for improper arguments
if (! defined $notebook || ! defined $label) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->addTab', @_);
}
# Add the tab
my $tab = Gtk3::Label->new_with_mnemonic($label);
my $scroller = Gtk3::ScrolledWindow->new();
$notebook->append_page($scroller, $tab);
$scroller->set_policy('automatic', 'automatic');
# Create a textview using the system's preferred colours and fonts
my $textView = Gtk3::TextView->new();
$scroller->add_with_viewport($textView);
my $buffer = Gtk3::TextBuffer->new();
$textView->set_buffer($buffer);
$textView->set_editable(FALSE);
$textView->set_cursor_visible(FALSE);
$axmud::CLIENT->desktopObj->setTextViewStyle($self->winType, $textView);
# Fill the textview
if (! $newlineFlag) {
$buffer->set_text(join("", @list));
} else {
$buffer->set_text(join("\n", @list));
}
return 1
}
##################
# Accessors - set
##################
# Accessors - get
sub notebook
{ $_[0]->{notebook} }
sub button
{ $_[0]->{button} }
}
{ package Games::Axmud::OtherWin::Connect;
use strict;
use warnings;
# use diagnostics;
use Glib qw(TRUE FALSE);
our @ISA = qw(
Games::Axmud::Generic::OtherWin Games::Axmud::Generic::FreeWin Games::Axmud::Generic::Win
Games::Axmud
);
##################
# Constructors
sub new {
# Called by GA::Generic::Win->createFreeWin
# Creates a new instance of the Connections window, which displays a list of world
# profiles and invites the user to connect to one of them
#
# Expected arguments
# $number - Unique number for this window object
# $workspaceObj - The GA::Obj::Workspace handling the workspace in which this window
# should be created
# $owner - The owner; a 'grid' window object (but not an 'external' window) or a
# 'free' window object. When this window opens/closes, the owner is
# informed via calls to its ->add_childFreeWin / ->del_childFreeWin
# functions
#
# Optional arguments
# $session - The GA::Session from which this function was called. 'undef' if the
# calling function didn't specify a session and $owner's ->session IV
# is also 'undef'
# $title - Ignored if set (all 'other' windows define their own title)
# $editObj - Ignored if set
lib/Games/Axmud/OtherWin.pm view on Meta::CPAN
worldObj => undef,
# The GA::Obj::MiniWorld that stores the changes being made by the user to the grid
# widgets. For an existing world profile, the mini-world exists in $self->worldHash;
# otherwise it's a temporary GA::Obj::MiniWorld that might (or might not) be stored as
# a world profile, at some point
miniWorldObj => undef,
# Flag set to TRUE when $self->resetGridWidgets or $self->updateGridWidgets are
# changing the value displayed in the grid widgets; this stops the mini-world object
# from being modified (the mini-world object should only store changes made by the
# user)
updateFlag => undef,
# First line displayed in the Gtk3::TreeView
newWorldString => '<b><i>Create new world</i></b>',
# First line displayed in the Gtk3::ComboBox
noCharString => '<no character>',
# First line displayed in 'information' section
noWebsiteString => 'Websites: (no websites)',
# Second line
noConnectString => 'Connections: 0',
# Current search terms. If 'undef', all worlds are listed; otherwise, only those worlds
# matching one or both search terms are listed
searchRegex => undef,
searchLanguage => undef,
};
# Bless the object into existence
bless $self, $class;
return $self;
}
##################
# Methods
# Standard window object functions
# sub winSetup {} # Inherited from GA::Generic::FreeWin
sub winEnable {
# Called by GA::Generic::Win->createFreeWin, after the call to $self->winSetup
# After the Gtk3::Window has been setup and moved into position, makes it visible
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 on success
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->winEnable', @_);
}
# Make the window appear on the desktop
$self->winShowAll($self->_objClass . '->winEnable');
$self->ivPoke('enabledFlag', TRUE);
# Fill the treeview
$self->resetTreeView($self->treeView);
# The 'connect' button should have focus
$self->connectButton->grab_focus();
# This type of window is unique (only one can be open at any time); inform the GA::Client
# it has opened
$axmud::CLIENT->set_connectWin($self);
return 1;
}
# sub winDesengage {} # Inherited from GA::Generic::FreeWin
sub winDestroy {
# Can be called by anything
# Updates IVs
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments, if the window can't be destroyed or if it has already
# been destroyed
# 1 on success
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->winDestroy', @_);
}
if (! $self->winBox) {
# Window already destroyed in a previous call to this function
return undef;
}
# Close any 'free' windows for which this window is a parent
foreach my $winObj ($self->ivValues('childFreeWinHash')) {
$winObj->winDestroy();
}
# Destroy the Gtk3::Window
eval { $self->winBox->destroy(); };
if ($@) {
# Window can't be destroyed
return undef;
} else {
$self->ivUndef('winWidget');
$self->ivUndef('winBox');
}
# Inform the owner and the desktop object of this 'free' window's demise
$axmud::CLIENT->desktopObj->del_freeWin($self);
if ($self->owner) {
$self->owner->del_childFreeWin($self);
}
# This type of window is unique (only one can be open at any time); inform the GA::Client
# it has closed
$axmud::CLIENT->set_connectWin();
return 1;
}
# sub winShowAll {} # Inherited from GA::Generic::Win
sub drawWidgets {
# Called by $self->winSetup
# Sets up the Connections window with its standard widgets
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->drawWidgets', @_);
}
# Create a packing box
my $packingBox = Gtk3::VBox->new(FALSE, $self->spacingPixels);
$self->winBox->add($packingBox);
$packingBox->set_border_width(0);
# Update IVs immediately, for the benefit of any functions called
$self->ivPoke('packingBox', $packingBox);
# Create a horizontal pane to divide the window in two, with an image/treeview on the
# left, and everything else on the right
my $hPaned = Gtk3::HPaned->new();
$packingBox->pack_start($hPaned, TRUE, TRUE, 0);
$hPaned->set_wide_handle(TRUE);
# On the left, create a vertical packing box, with an image at the top, a strip of buttons
# in the middle and a treeview at the bottom
my $vBox = Gtk3::VBox->new(FALSE, $self->spacingPixels);
$hPaned->add1($vBox);
# Create a frame containing an image
my $frame = Gtk3::Frame->new(undef);
$vBox->pack_start($frame, FALSE, FALSE, 0);
$frame->set_shadow_type($axmud::CLIENT->constShadowType);
my $image = Gtk3::Image->new_from_file($self->defaultIcon);
$frame->add($image);
lib/Games/Axmud/OtherWin.pm view on Meta::CPAN
$treeSelection->select_iter($matchPointer);
} else {
$treeSelection->select_iter($model->get_iter_first());
}
return 1;
}
sub resetGridWidgets {
# Called by $self->selectWorldCallback when the user clicks on the 'Create new world' line
# in the treeview
# Resets IVs and resets the widgets in the window's Gtk3::Grid, ready for the user to enter
# details for a new world
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->resetGridWidgets', @_);
}
# Reset the IV which stores the currently displayed world
$self->ivUndef('worldObj');
# Create a temporary GA::Obj::MiniWorld to store the changes
$self->ivPoke('miniWorldObj', Games::Axmud::Obj::MiniWorld->new());
# Set a flag to TRUE to stop the mini-world object being updated, as we change the values
# displayed in the grid's widgets
$self->ivPoke('updateFlag', TRUE);
# Reset the 'create world' button's label (it gets modified by $self->updateGridWidgets)
$self->createWorldButton->set_label('Create world');
$self->createWorldButton->set_tooltip_text('Create a world profile');
# Reset the grid widgets
$self->entry->set_text('');
$self->entry2->set_text('');
$self->entry3->set_text('');
$self->checkButton->set_active(FALSE);
$self->radioButton->set_active(TRUE);
my $comboBox = $self->resetComboBox(TRUE);
$self->ivPoke('comboBox', $comboBox);
$self->websiteLabel->set_text($self->noWebsiteString);
$self->connectionLabel->set_text($self->noConnectString);
$self->descripBuffer->set_text('');
# (These calls eliminate flashing when the screenshot is updated rapidly, for example when
# the user scrolls through the list of worlds)
$self->winShowAll($self->_objClass . '->resetGridWidgets');
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->resetGridWidgets');
# Update the world screenshot, using the default logo
# If a logo for this world exists, use it; otherwise use the default logo
my $image = Gtk3::Image->new_from_file($self->defaultIcon);
$axmud::CLIENT->desktopObj->removeWidget($self->frame, $self->image);
$self->frame->add($image);
$self->ivPoke('image', $image);
# (A repeat of those calls eliminates it entirely)
$self->winShowAll($self->_objClass . '->resetGridWidgets');
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->resetGridWidgets');
# The entry box for the world's name must be made editable
$self->entry->set_editable(TRUE);
# The 'pwd' / 'account' buttons start insensitive, but can be sensitised if the user selects
# a character
$self->editPwdButton->set_sensitive(FALSE);
$self->editAccButton->set_sensitive(FALSE);
# The 'reset world' button must be insensitive when there isn't a corresponding world
# profile
$self->resetWorldButton->set_sensitive(FALSE);
# The 'add', 'connect offline' and 'connect to world' buttons must be insensitive until the
# user at least types something in the 'host address' entry box
$self->addCharButton->set_sensitive(FALSE);
$self->offlineButton->set_sensitive(FALSE);
$self->connectButton->set_sensitive(FALSE);
# Update complete
$self->ivPoke('updateFlag', FALSE);
# The call to ->show_all() causes the image to appear
$self->winShowAll($self->_objClass . '->resetGridWidgets');
return 1;
}
sub updateGridWidgets {
# Called by $self->selectWorldCallback when the user clicks on a line in the treeview
# corresponding to a world profile
# Also called by $self->testModeLoginCallback
#
# Updates IVs and updates the widgets in the window's Gtk3::Grid, so they show details about
# the world
#
# Expected arguments
# $worldObj - The GA::Profile::World object corresponding to the clicked line
# $line - The text of the treeview line that the user clicked
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $worldObj, $line, $check) = @_;
# Local variables
my (
$displayFlag, $modName, $host, $port, $website, $connections, $logoPath,
@charList,
);
# Check for improper arguments
if (! defined $worldObj || ! defined $line || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->updateGridWidgets', @_);
}
# Decide which list should be displayed. Default display mode is 'undef', representing
# a list of world profiles
if ($self->otherWorldButton->get_active()) {
lib/Games/Axmud/OtherWin.pm view on Meta::CPAN
if (! $displayFlag) {
$connections = 'Connections: ' . $worldObj->numberConnects;
if ($worldObj->lastConnectDate && $worldObj->lastConnectTime) {
$connections .= ', most recent: ' . $worldObj->lastConnectDate . ' at '
. $worldObj->lastConnectTime;
}
} else {
$connections = 'Connections: (n/a)';
}
$self->connectionLabel->set_markup($connections);
# (Descrip)
if ($self->miniWorldObj->ivExists('propHash', 'descrip')) {
$self->descripBuffer->set_text($self->miniWorldObj->ivShow('propHash', 'descrip'));
} elsif (! $displayFlag && $worldObj->worldDescrip) {
$self->descripBuffer->set_text($worldObj->worldDescrip);
} elsif (! $displayFlag) {
$self->descripBuffer->set_text('');
} else {
$self->descripBuffer->set_text(
'This world profile won\'t be created until you click one of the buttons below',
)
}
# Move the 'descrip' textview's scrollbar to the top, in case the user has been browsing
# another world's description
$self->descripTextView->scroll_to_iter(
$self->descripBuffer->get_start_iter(),
0.0,
TRUE,
0,
1,
);
# If a logo for this world exists, use it; otherwise use the default logo
if (! $displayFlag) {
$logoPath = $axmud::DATA_DIR . '/logos/' . $worldObj->name . '.png';
}
if ($displayFlag || ! (-e $logoPath)) {
$logoPath = $axmud::CLIENT->getClientLogo($worldObj->adultFlag);
}
# (These calls eliminate flashing when the screenshot is updated rapidly, for example when
# the user scrolls through the list of worlds)
$self->winShowAll($self->_objClass . '->updateGridWidgets');
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->updateGridWidgets');
# Update the world screenshot
my $image = Gtk3::Image->new_from_file($logoPath);
$axmud::CLIENT->desktopObj->removeWidget($self->frame, $self->image);
$self->frame->add($image);
$self->ivPoke('image', $image);
# (A repeat of those calls eliminates it entirely)
$self->winShowAll($self->_objClass . '->updateGridWidgets');
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->updateGridWidgets');
# The entry box for the world's name must not be changed
$self->entry->set_editable(FALSE);
# The 'add' button must be sensitive
$self->addCharButton->set_sensitive(TRUE);
# The 'pwd'/'account' buttons start sensitised if there's a selected character, but
# desensitised if not
if ($self->miniWorldObj->selectChar) {
$self->editPwdButton->set_sensitive(TRUE);
$self->editAccButton->set_sensitive(TRUE);
} else {
$self->editPwdButton->set_sensitive(FALSE);
$self->editAccButton->set_sensitive(FALSE);
}
# The 'reset world' button must be sensitive
$self->resetWorldButton->set_sensitive(TRUE);
# If the world profile doesn't have a ->dns, ->ipv4 or ->ipv6 value, Axmud obviously won't
# be able to connect to the world. Make the connect buttons desensitised until the user
# types something in the 'host address' entry box
if (! $host) {
$self->offlineButton->set_sensitive(FALSE);
$self->connectButton->set_sensitive(FALSE);
} else {
# Otherwise, these two buttons start sensitised
$self->offlineButton->set_sensitive(TRUE);
$self->connectButton->set_sensitive(TRUE);
}
# Update complete
$self->ivPoke('updateFlag', FALSE);
# The call to ->show_all() causes the image to appear
$self->winShowAll($self->_objClass . '->updateGridWidgets');
return 1;
}
sub resetComboBox {
# Called by $self->createGridWidgets, ->resetGridWidgets and ->updateGridWidgets
# Not sure how to empty a Gtk3::ComboBox, so we'll just destroy the old one, and replace it
# with a new one
#
# Expected arguments
# (none besides $self)
#
# Optional arguments
# $destroyFlag - If TRUE, a combobox already exists, and must be deleted. If FALSE (or
# 'undef'), the combobox is being drawn for the first time
# @charList - A list of characters to display in the combobpx. If empty, the
# combobox will contain only the '<no character>' string. If not
# empty, the '<no character>' is added to @charList as the first item
#
# Return values
# 'undef' on improper arguments
# Otherwise returns the Gtk3::ComboBox created
my ($self, $destroyFlag, @charList) = @_;
# Local variables
my ($count, $index);
# (No improper arguments to check)
# If a Gtk3::ComboBox already exists, destroy it
if ($destroyFlag) {
$axmud::CLIENT->desktopObj->removeWidget($self->grid, $self->comboBox);
}
# Create a new combobox
unshift (@charList, $self->noCharString);
my $comboBox = $self->addComboBox($self->grid, undef, \@charList, undef,
4, 8, 7, 8);
# If the current mini-world object specifies a character, make that the combobox's active
# item. Otherwise, make the '<no character>' string the active item
$index = 0;
if ($self->miniWorldObj && $self->miniWorldObj->selectChar) {
$count = -1;
OUTER: foreach my $string (@charList) {
$count++;
if ($string eq $self->miniWorldObj->selectChar) {
$index = $count;
last OUTER;
}
}
}
$comboBox->set_active($index);
# Also, the 'pwd'/'account' buttons should only be sensitised when there's a selected
# character
if ($self->miniWorldObj) {
if ($self->miniWorldObj->selectChar) {
$self->editPwdButton->set_sensitive(TRUE);
$self->editAccButton->set_sensitive(TRUE);
} else {
$self->editPwdButton->set_sensitive(FALSE);
$self->editAccButton->set_sensitive(FALSE);
}
}
# Now we can add the combobox's ->signal_connect, which updates the mini-world object when
# a character is selected
$comboBox->signal_connect('changed' => sub {
my $char = $comboBox->get_active_text();
if ($char eq $self->noCharString) {
$self->miniWorldObj->ivUndef('selectChar');
# When no character is selected, the 'pwd'/'account' buttons must be desensitised
$self->editPwdButton->set_sensitive(FALSE);
$self->editAccButton->set_sensitive(FALSE);
} else {
$self->miniWorldObj->ivPoke('selectChar', $char);
# When no character is selected, the 'pwd'/'account' buttons must be desensitised
$self->editPwdButton->set_sensitive(TRUE);
lib/Games/Axmud/OtherWin.pm view on Meta::CPAN
# area)
packingBox => undef, # Gtk3::VBox
# Standard IVs for 'free' windows
# The window's default size, in pixels
widthPixels => 600,
heightPixels => 300,
# Default border/item spacing sizes used in the window, in pixels
borderPixels => $axmud::CLIENT->constFreeBorderPixels,
spacingPixels => $axmud::CLIENT->constFreeSpacingPixels,
# A string to use as the window title. If 'undef', a generic title is used
title => $axmud::SCRIPT . ' client console',
# Hash containing any number of key-value pairs needed for this particular 'config'
# window; for example, for example, GA::PrefWin::TaskStart uses it to specify a task
# name and type. Set to an empty hash if not required
configHash => {%configHash},
# IVs for this window
textView => undef, # Gtk3::TextView
buffer => undef, # Gtk3::TextBuffer
};
# Bless the object into existence
bless $self, $class;
return $self;
}
##################
# Methods
# Standard window object functions
# sub winSetup {} # Inherited from GA::Generic::FreeWin
sub winEnable {
# Called by GA::Generic::Win->createFreeWin, after the call to $self->winSetup
# After the Gtk3::Window has been setup and moved into position, makes it visible
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 on success
my ($self, $check) = @_;
# Local variables
my @list;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->winEnable', @_);
}
# Make the window appear on the desktop
$self->winShowAll($self->_objClass . '->winEnable');
$self->ivPoke('enabledFlag', TRUE);
# This type of window is unique (only one can be open at any time); inform the GA::Client
# it has opened
$axmud::CLIENT->set_consoleWin($self);
# If any system messages have been stored, we can display them now
@list = $axmud::CLIENT->systemMsgList;
if (@list) {
do {
my ($type, $msg);
$type = shift @list;
$msg = shift @list;
$self->update($type, $msg);
} until (! @list);
}
# Each system message is displayed here only once
$axmud::CLIENT->reset_systemMsg();
return 1;
}
# sub winDesengage {} # Inherited from GA::Generic::FreeWin
sub winDestroy {
# Can be called by anything
# Updates IVs
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments, if the window can't be destroyed or if it has already
# been destroyed
# 1 on success
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->winDestroy', @_);
}
if (! $self->winBox) {
# Window already destroyed in a previous call to this function
return undef;
}
# Close any 'free' windows for which this window is a parent
foreach my $winObj ($self->ivValues('childFreeWinHash')) {
$winObj->winDestroy();
}
# Destroy the Gtk3::Window
eval { $self->winBox->destroy(); };
if ($@) {
# Window can't be destroyed
return undef;
} else {
$self->ivUndef('winWidget');
$self->ivUndef('winBox');
}
# Inform the owner and the desktop object of this 'free' window's demise
$axmud::CLIENT->desktopObj->del_freeWin($self);
if ($self->owner) {
$self->owner->del_childFreeWin($self);
}
# This type of window is unique (only one can be open at any time); inform the GA::Client
# it has closed
$axmud::CLIENT->set_consoleWin();
return 1;
}
# sub winShowAll {} # Inherited from GA::Generic::Win
sub drawWidgets {
# Called by $self->winSetup
# Sets up the Client Console window with its standard widgets
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->drawWidgets', @_);
}
# Create a packing box
my $packingBox = Gtk3::VBox->new(FALSE, 0);
$self->winBox->add($packingBox);
$packingBox->set_border_width(0);
# Create a textview
my $scroller = Gtk3::ScrolledWindow->new(undef, undef);
$packingBox->pack_start($scroller, TRUE, TRUE, 0);
$scroller->set_shadow_type($axmud::CLIENT->constShadowType);
$scroller->set_policy('automatic', 'automatic');
$scroller->set_border_width(5);
# Use a textview with default colours/fonts
my $textView = Gtk3::TextView->new();
$scroller->add($textView);
my $buffer = Gtk3::TextBuffer->new();
$textView->set_buffer($buffer);
$textView->set_editable(FALSE);
$textView->set_cursor_visible(FALSE);
$textView->set_can_focus(FALSE);
$textView->set_wrap_mode('word-char'); # Wrap words if possible, characters if not
$axmud::CLIENT->desktopObj->setTextViewStyle('main', $textView);
# Create a mark at the end of the buffer, with right gravity, so that whenever text is
# inserted, we can scroll to that mark (and the mark stays at the end)
my $endMark = $buffer->create_mark('end', $buffer->get_end_iter(), FALSE);
# Update IVs
$self->ivPoke('packingBox', $packingBox);
$self->ivPoke('textView', $textView);
$self->ivPoke('buffer', $buffer);
# Create some colour tags, so that system messages can be displayed in their usual colours
$self->createColourTags();
return 1;
}
# sub redrawWidgets {} # Inherited from GA::Generic::Win
# ->signal_connects
# Other functions
sub createColourTags {
# Called by $self->drawWidgets
# Create some Gtk3::TextTags, so that system messages can be shown in their usual colours
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->update', @_);
}
$self->buffer->create_tag(
'system',
'foreground'
=> $axmud::CLIENT->returnRGBColour($axmud::CLIENT->customShowSystemTextColour),
);
$self->buffer->create_tag(
'error',
'foreground'
=> $axmud::CLIENT->returnRGBColour($axmud::CLIENT->customShowErrorColour),
);
$self->buffer->create_tag(
'warning',
'foreground'
=> $axmud::CLIENT->returnRGBColour($axmud::CLIENT->customShowWarningColour),
);
lib/Games/Axmud/OtherWin.pm view on Meta::CPAN
return $self;
}
##################
# Methods
# Standard window object functions
# sub winSetup {} # Inherited from GA::Generic::FreeWin
# sub winEnable {} # Inherited from GA::Generic::FreeWin
# sub winDesengage {} # Inherited from GA::Generic::FreeWin
# sub winDestroy {} # Inherited from GA::Generic::FreeWin
# sub winShowAll {} # Inherited from GA::Generic::Win
sub drawWidgets {
# Called by $self->winSetup
# Sets up the Gtk3::Window by drawing the window's widgets
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my $title;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->drawWidgets', @_);
}
# Create a packing box
my $packingBox = Gtk3::VBox->new(FALSE, 0);
$self->winBox->add($packingBox);
$packingBox->set_border_width(0);
# At the top, create a textview
my $scroller = Gtk3::ScrolledWindow->new(undef, undef);
$packingBox->pack_start($scroller, TRUE, TRUE, 0);
$scroller->set_shadow_type($axmud::CLIENT->constShadowType);
$scroller->set_policy('automatic', 'automatic');
$scroller->set_border_width(0);
# Create a textview with default colours/fonts
my $textView = Gtk3::TextView->new();
$scroller->add($textView);
my $buffer = Gtk3::TextBuffer->new();
$textView->set_buffer($buffer);
$textView->set_editable(TRUE);
$textView->set_cursor_visible(TRUE);
$axmud::CLIENT->desktopObj->setTextViewStyle($self->winType, $textView);
# ->signal_connect appears below
# Set the initial contents of the textview
$buffer->set_text($self->ivShow('configHash', 'mcp_content'));
# At the bottom, create a button strip in a horizontal packing box
my $hBox = Gtk3::HBox->new(FALSE, 0);
$packingBox->pack_end($hBox, FALSE, FALSE, $self->spacingPixels);
# Create some buttons
my $cancelButton = Gtk3::Button->new('Cancel');
$hBox->pack_start($cancelButton, TRUE, TRUE, $self->borderPixels);
$cancelButton->get_child->set_width_chars(10);
$cancelButton->signal_connect('clicked' => sub {
$self->winDestroy();
});
$cancelButton->set_sensitive(FALSE);
my $saveButton = Gtk3::Button->new('Save');
$hBox->pack_start($saveButton, TRUE, TRUE, $self->borderPixels);
$saveButton->get_child->set_width_chars(10);
$saveButton->signal_connect('clicked' => sub {
$self->doSave($buffer);
$cancelButton->set_sensitive(FALSE);
});
my $saveCloseButton = Gtk3::Button->new('Save and close');
$hBox->pack_end($saveCloseButton, TRUE, TRUE, $self->borderPixels);
$saveCloseButton->get_child->set_width_chars(15);
$saveCloseButton->signal_connect('clicked' => sub {
$self->doSave($buffer);
$self->winDestroy();
});
# ->signal_connect from above
$buffer->signal_connect('changed' => sub {
$cancelButton->set_sensitive(TRUE);
});
# Update IVs (not worth storing widgets other than the main packing box)
$self->ivPoke('packingBox', $packingBox);
return 1;
}
# sub redrawWidgets {} # Inherited from GA::Generic::Win
# ->signal_connects
# Other functions
sub doSave {
# Called by $self->drawWidgets
# 'Saves' the contents of the window by sending an MSP message to the world
#
# Expected arguments
# $buffer - The window's Gtk3::Buffer
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $buffer, $check) = @_;
# Local variables
my (
$text,
@list,
);
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->doSave', @_);
}
$text = $axmud::CLIENT->desktopObj->bufferGetText($buffer);
@list = split(/\n/, $text);
# Send the MCP message (one or more multiline parts)
$self->session->mcpSendMultiLine(
'dns-org-mud-moo-simpleedit-set',
'reference',
$self->ivShow('configHash', 'mcp_reference'),
'content',
\@list,
'type',
$self->ivShow('configHash', 'mcp_type'),
);
return 1;
}
##################
# Accessors - set
##################
# Accessors - get
}
{ package Games::Axmud::OtherWin::PatternTest;
use strict;
use warnings;
# use diagnostics;
use Glib qw(TRUE FALSE);
our @ISA = qw(
Games::Axmud::Generic::OtherWin Games::Axmud::Generic::FreeWin Games::Axmud::Generic::Win
Games::Axmud
);
##################
# Constructors
sub new {
# Called by GA::Generic::Win->createFreeWin
# Creates a new instance of the Pattern Test window, which allows the user to to test
# patterns (regexes) on the fly
#
# Expected arguments
# $number - Unique number for this window object
# $workspaceObj - The GA::Obj::Workspace handling the workspace in which this window
# should be created
# $owner - The owner; a 'grid' window object (but not an 'external' window) or a
# 'free' window object. When this window opens/closes, the owner is
# informed via calls to its ->add_childFreeWin / ->del_childFreeWin
# functions
#
# Optional arguments
# $session - The GA::Session from which this function was called. 'undef' if the
# calling function didn't specify a session and $owner's ->session IV
# is also 'undef'
# $title - Ignored if set (all 'other' windows define their own title)
# $editObj - Ignored if set
lib/Games/Axmud/OtherWin.pm view on Meta::CPAN
return $self;
}
##################
# Methods
# Standard window object functions
# sub winSetup {} # Inherited from GA::Generic::FreeWin
# sub winEnable {} # Inherited from GA::Generic::FreeWin
# sub winDesengage {} # Inherited from GA::Generic::FreeWin
# sub winDestroy {} # Inherited from GA::Generic::FreeWin
# sub winShowAll {} # Inherited from GA::Generic::Win
sub drawWidgets {
# Called by $self->winSetup
# Sets up the Gtk3::Window by drawing the window's widgets
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my $title;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->drawWidgets', @_);
}
# Create a packing box
my $packingBox = Gtk3::VBox->new(FALSE, 0);
$self->winBox->add($packingBox);
$packingBox->set_border_width(0);
# At the top, create a textview
my $scroller = Gtk3::ScrolledWindow->new(undef, undef);
$packingBox->pack_start($scroller, TRUE, TRUE, 0);
$scroller->set_shadow_type($axmud::CLIENT->constShadowType);
$scroller->set_policy('automatic', 'automatic');
$scroller->set_border_width(0);
# Create a textview with default colours/fonts
my $textView = Gtk3::TextView->new();
$scroller->add($textView);
my $buffer = Gtk3::TextBuffer->new();
$textView->set_buffer($buffer);
$textView->set_editable(TRUE);
$textView->set_cursor_visible(TRUE);
$axmud::CLIENT->desktopObj->setTextViewStyle($self->winType, $textView);
# At the bottom, create several horizontal packing boxes for various widgets
my $hBox = Gtk3::HBox->new(FALSE, 0);
$packingBox->pack_start($hBox, FALSE, FALSE, $self->spacingPixels);
my $radioButton = Gtk3::RadioButton->new_with_label(undef, 'Execute instructions');
$hBox->pack_start($radioButton, TRUE, TRUE, $self->spacingPixels);
my $checkButton = Gtk3::CheckButton->new_with_label('(ignore empty lines)');
$hBox->pack_start($checkButton, TRUE, TRUE, $self->spacingPixels);
my $radioButton2 = Gtk3::RadioButton->new_with_label(
$radioButton->get_group(),
'Run as a script',
);
$hBox->pack_start($radioButton2, TRUE, TRUE, $self->spacingPixels);
# Second strip
my $hBox2 = Gtk3::HBox->new(FALSE, 0);
$packingBox->pack_start($hBox2, FALSE, FALSE, 0);
my $label = Gtk3::Label->new('Prepend:');
$hBox2->pack_start($label, FALSE, FALSE, $self->spacingPixels);
my $entry = Gtk3::Entry->new();
$hBox2->pack_start($entry, TRUE, TRUE, 0);
$entry->set_tooltip_text('Prepend this to every world command');
my $label2 = Gtk3::Label->new('Append:');
$hBox2->pack_start($label2, FALSE, FALSE, $self->spacingPixels);
my $entry2 = Gtk3::Entry->new();
$hBox2->pack_start($entry2, TRUE, TRUE, 0);
$entry2->set_tooltip_text('Append this to every world command');
# Third strip
my $hBox3 = Gtk3::HBox->new(FALSE, 0);
$packingBox->pack_end($hBox3, FALSE, FALSE, $self->spacingPixels);
my $okButton = Gtk3::Button->new('Send');
$hBox3->pack_start($okButton, TRUE, TRUE, 0);
my $clearButton = Gtk3::Button->new('Send and clear text');
$hBox3->pack_start($clearButton, FALSE, FALSE, $self->spacingPixels);
$clearButton->get_child->set_width_chars(20);
my $closeButton = Gtk3::Button->new('Close window');
$hBox3->pack_start($closeButton, FALSE, FALSE, 0);
$closeButton->get_child->set_width_chars(15);
# ->signal_connects for the buttons
$radioButton->signal_connect('toggled' => sub {
if ($radioButton->get_active()) {
$checkButton->set_sensitive(TRUE);
$entry->set_sensitive(TRUE);
$entry2->set_sensitive(TRUE);
$okButton->set_label('Send');
$clearButton->set_label(' Send and clear text ');
}
});
$radioButton2->signal_connect('toggled' => sub {
if ($radioButton2->get_active()) {
$checkButton->set_active(FALSE);
$checkButton->set_sensitive(FALSE);
$entry->set_sensitive(FALSE);
$entry->set_text('');
$entry2->set_sensitive(FALSE);
$entry2->set_text('');
$okButton->set_label('Run');
$clearButton->set_label(' Run and clear text ');
}
});
$okButton->signal_connect('clicked' => sub {
if ($radioButton->get_active()) {
# Execute instructions
$self->executeInstructions(
$axmud::CLIENT->desktopObj->bufferGetText($buffer),
$entry->get_text(),
$entry2->get_text(),
$checkButton->get_active(),
);
} else {
# Save the script as a temporary file, and execute it
$self->runScript($axmud::CLIENT->desktopObj->bufferGetText($buffer));
}
});
$clearButton->signal_connect('clicked' => sub {
if ($radioButton->get_active()) {
# Execute instructions
$self->executeInstructions(
$axmud::CLIENT->desktopObj->bufferGetText($buffer),
$entry->get_text(),
$entry2->get_text(),
$checkButton->get_active(),
);
} else {
# Save the script as a temporary file, and execute it
$self->runScript($axmud::CLIENT->desktopObj->bufferGetText($buffer));
}
$buffer->set_text('');
});
$closeButton->signal_connect('clicked' => sub {
$self->winDestroy();
});
# Update IVs (not worth storing widgets other than the main packing box)
$self->ivPoke('packingBox', $packingBox);
return 1;
}
# sub redrawWidgets {} # Inherited from GA::Generic::Win
# ->signal_connects
# Other functions
sub executeInstructions {
# Called by $self->drawWidgets when the user clicks the 'Send' button
# Executes the contents of the window as instructions, one line at a time
#
# Expected arguments
# $text - The contents of the Gtk3::TextBuffer
# $preText - Text to prepend to any world commands (or an empty string)
# $postText - Text to append to any world commands (or an empty string)
# $ignoreFlag - TRUE if empty lines should be ignored, FALSE if they should be used (as
# world commands)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $text, $preText, $postText, $ignoreFlag, $check) = @_;
# Local variables
my (@cmdList, @finalList);
# Check for improper arguments
if (
! defined $text || ! defined $preText || ! defined $postText || ! defined $ignoreFlag
|| defined $check
) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->executeInstructions', @_);
}
# Split $text into lines
@cmdList = split(/\n/, $text);
# Ignore empty lines, if required
if (! $ignoreFlag) {
@finalList = @cmdList;
} else {
lib/Games/Axmud/OtherWin.pm view on Meta::CPAN
# area)
packingBox => undef, # Gtk3::VBox
# Standard IVs for 'free' windows
# The window's default size, in pixels
widthPixels => 600,
heightPixels => 300,
# Default border/item spacing sizes used in the window, in pixels
borderPixels => $axmud::CLIENT->constFreeBorderPixels,
spacingPixels => $axmud::CLIENT->constFreeSpacingPixels,
# A string to use as the window title. If 'undef', a generic title is used
title => $axmud::SCRIPT . ' session console #' . $session->number,
# Hash containing any number of key-value pairs needed for this particular 'config'
# window; for example, for example, GA::PrefWin::TaskStart uses it to specify a task
# name and type. Set to an empty hash if not required
configHash => {%configHash},
# IVs for this window
textView => undef, # Gtk3::TextView
buffer => undef, # Gtk3::TextBuffer
};
# Bless the object into existence
bless $self, $class;
return $self;
}
##################
# Methods
# Standard window object functions
# sub winSetup {} # Inherited from GA::Generic::FreeWin
sub winEnable {
# Called by GA::Generic::Win->createFreeWin, after the call to $self->winSetup
# After the Gtk3::Window has been setup and moved into position, makes it visible
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 on success
my ($self, $check) = @_;
# Local variables
my @list;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->winEnable', @_);
}
# Make the window appear on the desktop
$self->winShowAll($self->_objClass . '->winEnable');
$self->ivPoke('enabledFlag', TRUE);
# This type of window is unique (only one can be open per session); inform the GA::Session
# it has opened
$self->session->set_consoleWin($self);
# If any system messages have been stored, we can display them now
@list = $self->session->systemMsgList;
if (@list) {
do {
my ($type, $msg);
$type = shift @list;
$msg = shift @list;
$self->update($type, $msg);
} until (! @list);
}
# Each system message is displayed here only once
$self->session->reset_systemMsg();
return 1;
}
# sub winDesengage {} # Inherited from GA::Generic::FreeWin
sub winDestroy {
# Can be called by anything
# Updates IVs
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments, if the window can't be destroyed or if it has already
# been destroyed
# 1 on success
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->winDestroy', @_);
}
if (! $self->winBox) {
# Window already destroyed in a previous call to this function
return undef;
}
# Close any 'free' windows for which this window is a parent
foreach my $winObj ($self->ivValues('childFreeWinHash')) {
$winObj->winDestroy();
}
# Destroy the Gtk3::Window
eval { $self->winBox->destroy(); };
if ($@) {
# Window can't be destroyed
return undef;
} else {
$self->ivUndef('winWidget');
$self->ivUndef('winBox');
}
# Inform the owner and the desktop object of this 'free' window's demise
$axmud::CLIENT->desktopObj->del_freeWin($self);
if ($self->owner) {
$self->owner->del_childFreeWin($self);
}
# This type of window is unique (only one can be open per session); inform the GA::Session
# it has closed
$self->session->set_consoleWin();
return 1;
}
# sub winShowAll {} # Inherited from GA::Generic::Win
# sub drawWidgets {} # Inherited from GA::OtherWin::ClientConsole
# sub redrawWidgets {} # Inherited from GA::Generic::Win
# ->signal_connects
# Other functions
# sub createColourTags {} # Inherited from GA::OtherWin::ClientConsole
# sub update {} # Inherited from GA::OtherWin::ClientConsole
##################
# Accessors - set
##################
# Accessors - get
}
{ package Games::Axmud::OtherWin::Simulate;
use strict;
use warnings;
# use diagnostics;
use Glib qw(TRUE FALSE);
our @ISA = qw(
Games::Axmud::Generic::OtherWin Games::Axmud::Generic::FreeWin Games::Axmud::Generic::Win
Games::Axmud
);
##################
# Constructors
sub new {
# Called by GA::Generic::Win->createFreeWin
# Creates a new instance of the Simulate window (an 'other' window). The window contains a
# textview in which the user can type text. When the 'Simulate' button is clicked, the
# contents of the textview (if any) is combined into a single string (with multiple lines
# separated by newline characters). The string is then used in a ';simulateworld' command,
# and appears in the session's default textview, as if it had been received from the world
#
# Expected arguments
# $number - Unique number for this window object
lib/Games/Axmud/OtherWin.pm view on Meta::CPAN
# Local variables
my (
$width, $height, $title, $sampleText, $sampleUnderlay,
@tagList,
%prettyHash, %reversePrettyHash, %ansiHash,
);
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->drawWidgets', @_);
}
# Import the list of Axmud standard colour/style tags (which also includes the dummy tags
# like 'bold', 'reverse_off' and 'attribs_off')
@tagList = $axmud::CLIENT->constColourStyleList;
# (For convenience, add 'attribs_off' to both the beginning and end of the list)
unshift(@tagList, 'attribs_off');
# Also import the hash of pretty names for each standard tag, in which the keys are the
# items in @tagList
%prettyHash = $axmud::CLIENT->constPrettyTagHash;
# Use a reverse hash too, so we can work out which combobox item was selected
%reversePrettyHash = reverse %prettyHash;
# Prepare a hash of ANSI escape sequences which the user can insert at any place in the
# textview, in the form
# $ansiHash{tag} = number_of_ANSI_escape_sequence
%ansiHash = (
(reverse $axmud::CLIENT->constANSIColourHash),
(reverse $axmud::CLIENT->constANSIStyleHash),
);
$ansiHash{'bold'} = 1;
$ansiHash{'bold_off'} = 22;
$ansiHash{'reverse'} = 7;
$ansiHash{'reverse_off'} = 27;
$ansiHash{'conceal'} = 8;
$ansiHash{'conceal_off'} = 28;
$ansiHash{'attribs_off'} = 0;
# Create a packing box
my $packingBox = Gtk3::VBox->new(FALSE, 0);
$self->winBox->add($packingBox);
$packingBox->set_border_width(0);
# At the top, create a textview
my $scroller = Gtk3::ScrolledWindow->new(undef, undef);
$packingBox->pack_start($scroller, TRUE, TRUE, 0);
$scroller->set_shadow_type($axmud::CLIENT->constShadowType);
$scroller->set_policy('automatic', 'automatic');
$scroller->set_border_width(0);
# Create a textview with default colours/fonts
my $textView = Gtk3::TextView->new();
$scroller->add($textView);
my $buffer = Gtk3::TextBuffer->new();
$textView->set_buffer($buffer);
$textView->set_editable(TRUE);
$textView->set_cursor_visible(TRUE);
$axmud::CLIENT->desktopObj->setTextViewStyle($self->winType, $textView);
# At the bottom, create a button strip in a horizontal packing box
my $hBox = Gtk3::HBox->new(FALSE, 0);
$packingBox->pack_end($hBox, FALSE, FALSE, $self->spacingPixels);
# Create a combo
my $comboBox = Gtk3::ComboBoxText->new();
$hBox->pack_start($comboBox, FALSE, FALSE, $self->borderPixels);
$title = 'Add an ANSI escape sequence:';
$sampleText = 'Sample xterm-256 text colour';
$sampleUnderlay = 'Sample xterm-256 underlay colour';
$comboBox->append_text($title);
foreach my $tag (@tagList) {
$comboBox->append_text($prettyHash{$tag});
# GA::Client->constColourStyleList doesn't include xterm colour tags, so we'll insert
# a sample text and a sample underlay colour right just before the style tags
if ($tag eq 'ul_white') {
$comboBox->append_text($sampleText);
$comboBox->append_text($sampleUnderlay);
}
}
$comboBox->set_active(0);
# Create the 'Apply' button
my $addButton = Gtk3::Button->new('Apply');
$hBox->pack_start($addButton, FALSE, FALSE, 0);
$addButton->get_child->set_width_chars(8);
$addButton->signal_connect('clicked' => sub {
my ($prettyTag, $tag, $ansi);
$prettyTag = $comboBox->get_active_text();
if ($prettyTag) {
if ($prettyTag eq $sampleText) {
# Use an example xterm-256 text colour (dark grey)
$ansi = chr(27) . '[38;5;234m';
} elsif ($prettyTag eq $sampleUnderlay) {
# Use an example xterm-256 underlay colour (light orange)
$ansi = chr(27) . '[48;5;214m';
} elsif ($prettyTag ne $title) {
# Get an Axmud colour/style tag (or one of the dummy tags like 'bold',
# 'reverse_off' and 'attribs_off')
$tag = $reversePrettyHash{$prettyTag};
# Convert it to an ANSI escape sequence
$ansi = chr(27) . '[' . $ansiHash{$tag} . 'm';
}
if ($ansi) {
$buffer->insert_at_cursor($ansi);
}
}
});
# Create the 'Simulate' button
my $okButton = Gtk3::Button->new('Simulate');
$hBox->pack_end($okButton, FALSE, FALSE, 0);
$okButton->get_child->set_width_chars(8);
$okButton->signal_connect('clicked' => sub {
my ($text, $type);
$text = $axmud::CLIENT->desktopObj->bufferGetText($buffer);
$type = $self->ivShow('configHash', 'type');
# If the textview contains some text, and if the calling GA::Session still exists...
if ($text && $axmud::CLIENT->ivExists('sessionHash', $self->session->number)) {
if ($type eq 'prompt') {
# Simulate a prompt received from the world. The TRUE argument means that the
# 'main' window's blinker shouldn't be turned on.
chomp $text;
$self->session->processIncomingData($text, TRUE);
} else {
# Simulate text received from the world. The TRUE argument means that the main
# window's blinker shouldn't be turned on.
$self->session->processIncomingData($text, TRUE);
}
}
});
# Create the 'Close' button
my $cancelButton = Gtk3::Button->new('Close');
$hBox->pack_end($cancelButton, FALSE, FALSE, $self->spacingPixels);
$cancelButton->get_child->set_width_chars(8);
$cancelButton->signal_connect('clicked' => sub {
$self->winDestroy();
});
# Update IVs (not worth storing widgets other than the main packing box)
$self->ivPoke('packingBox', $packingBox);
return 1;
}
# sub redrawWidgets {} # Inherited from GA::Generic::Win
# ->signal_connects
# Other functions
##################
# Accessors - set
##################
# Accessors - get
}
{ package Games::Axmud::OtherWin::SourceCode;
use strict;
use warnings;
# use diagnostics;
use Glib qw(TRUE FALSE);
our @ISA = qw(
Games::Axmud::Generic::OtherWin Games::Axmud::Generic::FreeWin Games::Axmud::Generic::Win
Games::Axmud
lib/Games/Axmud/OtherWin.pm view on Meta::CPAN
# Methods
# Standard window object functions
sub winSetup {
# Called by GA::Generic::Win->createFreeWin, after the call to $self->new
# Creates the Gtk3::Window itself
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if the window can't be opened
# 1 on success
my ($self, $check) = @_;
# Local variables
my $iv;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->winSetup', @_);
}
# Before doing anything, try to read the file (and don't open this window if it can't be
# done)
if (! $self->readFile()) {
return undef;
}
# Create the Gtk3::Window
my $winWidget = Gtk3::Window->new('toplevel');
if (! $winWidget) {
return undef;
} else {
# Store the IV now, as subsequent code needs it
$self->ivPoke('winWidget', $winWidget);
$self->ivPoke('winBox', $winWidget);
}
# Set up ->signal_connects
$self->setDeleteEvent(); # 'delete-event'
# Set the window title
$winWidget->set_title($self->title);
# Set the window's default size and position
$winWidget->set_default_size($self->widthPixels, $self->heightPixels);
$winWidget->set_border_width($self->borderPixels);
$winWidget->set_position('center');
# Set the icon list for this window
$iv = $self->winType . 'WinIconList';
$winWidget->set_icon_list($axmud::CLIENT->desktopObj->{$iv});
# Draw the widgets used by this window
if (! $self->drawWidgets()) {
return undef;
}
# The calling function can now call $self->winEnable to make the window visible
return 1;
}
# sub winEnable {} # Inherited from GA::Generic::FreeWin
# sub winDesengage {} # Inherited from GA::Generic::FreeWin
# sub winDestroy {} # Inherited from GA::Generic::FreeWin
# sub winShowAll {} # Inherited from GA::Generic::Win
sub drawWidgets {
# Called by $self->winSetup
# Sets up the Gtk3::Window by drawing the window's widgets
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->drawWidgets', @_);
}
# Create a packing box
my $packingBox = Gtk3::VBox->new(FALSE, 0);
$self->winBox->add($packingBox);
$packingBox->set_border_width(0);
# At the top, create a textview
my $frame = Gtk3::Frame->new($self->title);
$packingBox->pack_start($frame, TRUE, TRUE, 0);
# Update the frame label
$frame->set_label(
'World model room #' . $self->modelObj->number . ' (' . $self->file . ')',
);
$frame->set_border_width(0);
my $scroller = Gtk3::ScrolledWindow->new(undef, undef);
$frame->add($scroller);
$scroller->set_shadow_type($axmud::CLIENT->constShadowType);
$scroller->set_policy('automatic', 'automatic');
$scroller->set_border_width(5);
# Create a textview with default colours/fonts
my $textView = Gtk3::TextView->new();
$scroller->add($textView);
my $buffer = Gtk3::TextBuffer->new();
$textView->set_buffer($buffer);
$textView->set_editable(FALSE);
$textView->set_cursor_visible(FALSE);
$axmud::CLIENT->desktopObj->setTextViewStyle($self->winType, $textView);
# Copy the contents of the file to the textview
$buffer->set_text(join("\n", $self->lineList));
# At the bottom, create a button strip in a horizontal packing box
my $hBox = Gtk3::HBox->new(FALSE, 0);
$packingBox->pack_end($hBox, FALSE, FALSE, $self->spacingPixels);
# Add a single button
my $button = Gtk3::Button->new(' Close ');
$hBox->pack_end($button, FALSE, FALSE, $self->borderPixels);
$button->get_child->set_width_chars(10);
$button->signal_connect('clicked' => sub {
$self->winDestroy();
});
# Update IVs (not worth storing widgets other than the main packing box)
$self->ivPoke('packingBox', $packingBox);
return 1;
}
# sub redrawWidgets {} # Inherited from GA::Generic::Win
# ->signal_connects
# Other functions
sub readFile {
# Called by $self->winSetup before creating the Gtk3::Window
# Performs a few checks, displaying a 'dialogue' window if the source code viewer window
# can't be opened for one reason or another
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if the window should not be opened
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my (
$worldModelObj, $obj, $virtualFlag, $sourcePath, $errorMsg, $file, $fileName,
$fileHandle,
@lineList,
);
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->readFile', @_);
}
# Import the world model (for convenience)
$worldModelObj = $self->session->worldModelObj;
# Import some values from $self->configHash (for convenience)
lib/Games/Axmud/OtherWin.pm view on Meta::CPAN
notebookCurrentHeader => undef,
# When the user double-clicks an item in the notebook's list, the reference of the
# function which should be called in response (usually to make double-clicking the
# equivalent of clicking on one of the buttons)
# Set to 'undef' if nothing should happen
notebookSelectRef => undef,
# Hash of treeview headers, in the form
# $headerHash{header_string} = ref_of_subroutine
headerHash => {},
# List of notebok 'tab_name's in the same order used in the window
# (match the keys of ->notebookTabHash)
notebookTabList => [],
# Hash of notebook tabs, in the form
# $notebookTagHash{tab_name} = reference_to_Gtk3::Label_of_tab
notebookTabHash => {},
# Hash of data lists displayed in the notebook, in the form
# $notebookDataHash{tab_name} = reference_to_GA::Obj::SimpleList
notebookDataHash => {},
# To access Axbasic's default data, $self->setupTreeView creates a dummy
# Language::Axbasic::Script object, which is stored here so that functions like
# $self->axbasicHeader can use it
dummyScriptObj => undef,
};
# Bless the object into existence
bless $self, $class;
return $self;
}
##################
# Methods
# Standard window object functions
# sub winSetup {} # Inherited from GA::Generic::FreeWin
sub winEnable {
# Called by GA::Generic::Win->createFreeWin, after the call to $self->winSetup
# After the Gtk3::Window has been setup and moved into position, makes it visible
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 on success
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->winEnable', @_);
}
# Make the window appear on the desktop
$self->winShowAll($self->_objClass . '->winEnable');
$self->ivPoke('enabledFlag', TRUE);
# This type of window is unique to its GA::Session (only one can be open at any time, per
# session); inform the session it has opened
$self->session->set_viewerWin($self);
return 1;
}
# sub winDesengage {} # Inherited from GA::Generic::FreeWin
sub winDestroy {
# Can be called by anything
# Updates IVs
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments, if the window can't be destroyed or if it has already
# been destroyed
# 1 on success
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->winDestroy', @_);
}
if (! $self->winBox) {
# Window already destroyed in a previous call to this function
return undef;
}
# Close any 'free' windows for which this window is a parent
foreach my $winObj ($self->ivValues('childFreeWinHash')) {
$winObj->winDestroy();
}
# Destroy the Gtk3::Window
eval { $self->winBox->destroy(); };
if ($@) {
# Window can't be destroyed
return undef;
} else {
$self->ivUndef('winWidget');
$self->ivUndef('winBox');
}
# Inform the owner and the desktop object of this 'free' window's demise
$axmud::CLIENT->desktopObj->del_freeWin($self);
if ($self->owner) {
$self->owner->del_childFreeWin($self);
}
# This type of window is unique to its GA::Session (only one can be open at any time, per
# session); inform the session it has closed
$self->session->set_viewerWin();
return 1;
}
# sub winShowAll {} # Inherited from GA::Generic::Win
sub drawWidgets {
# Called by $self->winSetup
# Sets up the data viewer window with its standard widgets
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->drawWidgets', @_);
}
# Create a packing box
my $packingBox = Gtk3::VBox->new(FALSE, 0);
$self->winBox->add($packingBox);
$packingBox->set_border_width(0);
# Create a horizontal pane to divide the window into two, with the treeview on the left, and
# everything else on the right
my $hPaned = Gtk3::HPaned->new();
$packingBox->pack_start($hPaned, TRUE, TRUE, 0);
# Add a treeview on the left of the window
my $treeViewModel = Gtk3::TreeStore->new( ['Glib::String'] );
my $treeView = Gtk3::TreeView->new($treeViewModel);
$treeView->set_enable_search(FALSE);
# Append a single column to the treeview
$treeView->append_column(
Gtk3::TreeViewColumn->new_with_attributes(
'Objects',
Gtk3::CellRendererText->new,
text => 0,
)
);
# Make the treeview scrollable
my $treeViewScroller = Gtk3::ScrolledWindow->new();
$hPaned->pack1($treeViewScroller, FALSE, FALSE);
lib/Games/Axmud/OtherWin.pm view on Meta::CPAN
# [
# [row0_cell0, row0_cell1, row0cell2...],
# [row1_cell0, row1_cell1, row1cell2...],
# [row2_cell0, row2_cell1, row2cell2...],
# ...
# ]
#
# Optional arguments
# $buttonListRef - a reference to a list of buttons, in the format
# [
# 'button_name', 'tooltip', 'callback_sub_ref',
# 'button_name', 'tooltip', 'callback_sub_ref',
# 'button_name', 'tooltip', 'callback_sub_ref',
# ...
# ]
# - if $buttonListRef is 'undef', no buttons are displayed
#
# $scrollFlag - if set to TRUE, the Gtk3::ScrolledWindow is scrolled to the bottom;
# if FALSE (or 'undef'), it remains scrolled to the top
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my (
$self, $tabListRef, $columnListRef, $dataHashRef, $buttonListRef, $scrollFlag,
$check,
) = @_;
# Local variables
my (
$number, $dataListRef,
@tabList, @columnList, @buttonList, @scrollerList,
%dataHash,
);
# Check for improper arguments
if (
! defined $tabListRef || ! defined $columnListRef || ! defined $dataHashRef
|| defined $check
) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->refreshNotebook', @_);
}
# Dereference the supplied arguments
@tabList = @$tabListRef;
@columnList = @$columnListRef;
%dataHash = %$dataHashRef;
if ($buttonListRef) {
@buttonList = @$buttonListRef;
};
# Remove the existing tabs and buttons (if any)
$self->resetNotebook();
# If a button list was not visible, but should now be visible, do some repacking
if (! $self->hPaned2 && $buttonListRef) {
# Unpack existing widgets
$axmud::CLIENT->desktopObj->removeWidget($self->hPaned, $self->treeViewScroller);
$axmud::CLIENT->desktopObj->removeWidget($self->hPaned, $self->notebook);
# Repack the treeview scroller
$self->hPaned->pack1($self->treeViewScroller, FALSE, FALSE);
# Add a second horizontal pane on the right of the first one
# In this pane, a notebook is on the left, and a strip of buttons is on the right
my $hPaned2 = Gtk3::HPaned->new();
$self->hPaned->pack2($hPaned2, TRUE, FALSE);
# Repack the notebook on the left of $hPaned2
$hPaned2->pack1($self->notebook, TRUE, FALSE);
# Add a second vertical packing box for the strip of buttons
my $vBox = Gtk3::VBox->new(FALSE, 0);
$hPaned2->pack2($vBox, FALSE, FALSE);
$self->hPaned->set_position($self->leftWidth);
$hPaned2->set_position($self->centreWidth);
# Update IVs
$self->ivPoke('hPaned2', $hPaned2);
$self->ivPoke('vBox', $vBox);
# Likewise, if the button list was visible and is no longer required, do some repacking
} elsif ($self->hPaned2 && ! $buttonListRef) {
$axmud::CLIENT->desktopObj->removeWidget($self->hPaned, $self->treeViewScroller);
$axmud::CLIENT->desktopObj->removeWidget($self->hPaned2, $self->notebook);
$axmud::CLIENT->desktopObj->removeWidget($self->hPaned, $self->hPaned2);
# Repack the treeview scroller
$self->hPaned->pack1($self->treeViewScroller, FALSE, FALSE);
# Repack the notebook
$self->hPaned->pack2($self->notebook, TRUE, FALSE);
$self->hPaned->set_position($self->leftWidth);
# Update IVs
$self->ivUndef('hPaned2');
$self->ivUndef('vBox');
}
# Create new tabs in the notebook
do {
my (
$tab, $mnemonic, $slWidget, $scroller, $label, $slWidgetRef, $button, $count,
$vAdjust,
@ownColumnList,
);
$tab = shift @tabList;
$mnemonic = shift @tabList;
# Add a simple list
$slWidget = Games::Axmud::Obj::SimpleList->new(@columnList);
# Make each row double-clickable
$slWidget->signal_connect('row_activated' => sub {
# If doubling-clicking on a row is equivalent to something else, call the specified
# function to make it happen
if ($self->notebookSelectRef) {
&{$self->notebookSelectRef};
}
});
# Make the simple list scrollable
$scroller = Gtk3::ScrolledWindow->new();
$scroller->set_policy('automatic', 'automatic');
$scroller->add($slWidget);
push (@scrollerList, $scroller);
# Fill the columns with data
$dataListRef = $dataHash{$tab};
@{$slWidget->{data}} = @$dataListRef;
# Make all columns of type 'bool' (which are composed of checkbuttons) non-activatable,
# so that the user can't click them on and off
if (@columnList) {
$count = -1;
@ownColumnList = @columnList;
do {
my ($title, $type);
lib/Games/Axmud/OtherWin.pm view on Meta::CPAN
$self->ivPoke('notebookMode', 'list');
# Add an strip of buttons at the top of $self->vBox
if (@buttonList) {
do {
my ($name, $tip, $method, $btn);
$name = shift @buttonList;
$tip = shift @buttonList;
$method = shift @buttonList;
$btn = Gtk3::Button->new($name);
$btn->signal_connect('clicked' => sub {
$self->$method();
});
$btn->set_tooltip_text($tip);
$self->vBox->pack_start($btn, FALSE, FALSE, 0);
$self->ivPush('buttonList', $btn);
} until (! @buttonList);
}
# Add a separator just beneath these buttons
my $separator = Gtk3::HSeparator->new();
$self->vBox->pack_start($separator, FALSE, FALSE, 10);
$self->ivPush('buttonList', $separator);
# Add two standard buttons at the bottom of $self->vBox, regardless of the type of list
# displayed
my $btn = Gtk3::Button->new('Refresh list');
$btn->signal_connect('clicked' => sub {
$self->updateNotebook();
});
$btn->set_tooltip_text('Refresh this list');
$self->vBox->pack_start($btn, FALSE, FALSE, 0);
$self->ivPush('buttonList', $btn);
my $btn2 = Gtk3::Button->new('Exit viewer');
$btn2->signal_connect('clicked' => sub {
$self->winDestroy();
});
$btn2->set_tooltip_text('Close the ' . $axmud::SCRIPT . ' data viewer');
$self->vBox->pack_start($btn2, FALSE, FALSE, 0);
$self->ivPush('buttonList', $btn2);
# Set the width of the notebook, depending on whether there are any buttons to display
if ($buttonListRef) {
$self->hPaned2->set_position($self->centreWidth);
} else {
$self->hPaned2->set_position($self->centreWidth + $self->rightWidth);
}
# Render the changes
$self->winShowAll($self->_objClass . '->refreshNotebook');
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->refreshNotebook');
# If $scrollFlag is set, we can now scroll the Gtk3::ScrolledWindow to the bottom
if ($scrollFlag) {
foreach my $scroller (@scrollerList) {
my $vAdjust = $scroller->get_vadjustment();
$vAdjust->set_value(
$vAdjust->get_lower()
+ (($vAdjust->get_upper() - $vAdjust->get_page_size()) - $vAdjust->get_lower())
);
}
$self->winShowAll($self->_objClass . '->refreshNotebook');
}
return 1;
}
sub resetNotebook {
# Called by $self->refreshNotebook
# Resets the notebook, removing tabs and buttons
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if there is no notebook to reset
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my $number;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->resetNotebook', @_);
}
# If the notebook doesn't exist, there's nothing to reset
if (! $self->notebook) {
return undef;
}
# Remove the existing tabs (if any)
if (
$self->notebookMode eq 'list'
|| $self->notebookMode eq 'text'
) {
$number = $self->notebook->get_n_pages();
if ($number) {
for (my $count = 0; $count < $number; $count++) {
$self->notebook->remove_page(0);
}
}
$self->ivEmpty('notebookTabHash');
$self->ivEmpty('notebookTabList');
$self->ivEmpty('notebookDataHash');
}
# Remove the existing buttons (if any)
if ($self->buttonList) {
foreach my $button ($self->buttonList) {
$button->destroy;
}
$self->ivEmpty('buttonList');
}
return 1;
}
sub refreshTextView {
# Called by $self->cmdHeader (etc)
# Creates a Gtk3::TextView in the notebook, and writes the supplied text to it
# (Header functions which need a simple list, rather than a textview, call
# ->refreshNotebook)
#
# Expected arguments
# $tab - The title of the notebook tab
# @list - A list of lines to display in the textview
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $tab, @list) = @_;
# Local variables
my $label;
# Check for improper arguments
if (! defined $tab) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->refreshTextView', @_);
}
# If the button strip is visible, do some repacking
if ($self->hPaned2) {
$axmud::CLIENT->desktopObj->removeWidget($self->hPaned2, $self->notebook);
$axmud::CLIENT->desktopObj->removeWidget($self->hPaned, $self->hPaned2);
$self->hPaned->add2($self->notebook);
$self->hPaned->set_position($self->leftWidth);
}
# Update IVs
$self->ivUndef('hPaned2');
$self->ivUndef('vBox');
# Remove the existing notebook content
$self->resetNotebook();
# Create a scrolled window
my $scrolled = Gtk3::ScrolledWindow->new(undef, undef);
$scrolled->set_shadow_type($axmud::CLIENT->constShadowType);
$scrolled->set_policy('automatic', 'automatic');
$scrolled->set_border_width(5);
# Create a textview with default colours/fonts
my $textView = Gtk3::TextView->new();
my $buffer = Gtk3::TextBuffer->new();
$textView->set_buffer($buffer);
$textView->set_editable(FALSE);
$axmud::CLIENT->desktopObj->setTextViewStyle($self->winType, $textView);
# Copy the text into the textview
$buffer->set_text(join("\n", @list));
# Complete setup
$scrolled->add($textView);
# Add a label
$label = Gtk3::Label->new_with_mnemonic($tab);
$self->notebook->append_page($scrolled, $label);
# Render the changes
$self->winShowAll($self->_objClass . '->refreshTextView');
# Update IVs
$self->ivAdd('notebookTabHash', $tab, $label);
$self->ivPoke('notebookMode', 'text');
return 1;
}
sub updateNotebook {
# Called whenever the current notebook changes (when a new profile or cage is created or
# deleted - eg by $self->refreshNotebook)
# Updates the notebook by calling the same method called when a header in the treeview is
# selected
#
# Expected arguments
# (none besides $self)
#
# Optional arguments
# @list - The rows in the notebook's GA::Obj::SimpleList which should be marked as
# 'selected' (as if the user had clicked on them). If the list is empty,
# no rows are marked as 'selected'
#
# Return values
# 'undef' on improper arguments or if the notebook isn't displaying anything
# 1 otherwise
my ($self, @list) = @_;
# Local variables
my ($method, $currentTab);
# (No improper arguments to check)
if (
$self->notebookCurrentHeader
&& $self->ivExists('headerHash', $self->notebookCurrentHeader)
) {
# Remember the currently selected tab
$currentTab = $self->notebook->get_current_page();
# Call the method specified by $self->headerHash
$method = $self->ivShow('headerHash', $self->notebookCurrentHeader);
$self->$method($self->notebookCurrentHeader);
# If @list isn't empty, mark some of the rows as selected
if (@list) {