view release on metacpan or search on metacpan
lib/Games/Axmud/Generic.pm view on Meta::CPAN
# Operation complete
if (! $pwd) {
return $self->complete(
$session, $standardCmd,
'Added ' . $category . ' profile \'' . $name . '\'',
);
} else {
# Obfuscate the password, using the same number of asterisk characters as elsewhere
return $self->complete(
$session, $standardCmd,
'Added ' . $category . ' profile \'' . $name . '\' with the password \'********\'',
);
}
}
sub setProfile {
# Called by GA::Cmd::SetGuild->do, SetRace->do, SetChar->do
# Sets the current guild/race/char profile
#
# Expected arguments
# $session - The calling function's GA::Session
# $inputString - The command actually typed, e.g. 'sg thief'
# $standardCmd - Standard version of the client command, e.g. 'setguild'
# $name - The profile's name
# $category - The category of profile - 'guild', 'race' or 'char'
#
# Optional arguments
# $pwd - For character profiles only, the password to set. If the character
# also exists, the password is updated. If 'undef', don't set or
# update a password
# $account - For character profiles, only, the associated account name to set. If
# 'undef', don't set an account name
#
# Return values
# 'undef' on improper arguments or if there's an error
# 1 on success
my (
$self, $session, $inputString, $standardCmd, $name, $category, $pwd, $account, $check,
) = @_;
# Local variables
my (
$iv, $currentObj, $obj, $package, $historyObj,
%customProfHash,
);
# Check for improper arguments
if (
! defined $session || ! defined $inputString || ! defined $standardCmd
|| ! defined $name || ! defined $category || defined $check
) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->setProfile', @_);
}
# Check there are no 'free' windows open
if ($axmud::CLIENT->desktopObj->listSessionFreeWins($session, TRUE)) {
return $self->error(
$session, $inputString,
'Can\'t set a current profile while there are \'free\' windows (such as edit,'
. ' preference and wizard windows) open - try closing them first',
);
}
# If the profile already exists, check it isn't already a current profile
if ($session->ivExists('currentProfHash', $category)) {
$currentObj = $session->ivShow('currentProfHash', $category);
if ($currentObj->name eq $name) {
# Error message depends on whether it's the right kind of profile
if ($currentObj->category eq $category) {
return $self->error(
$session, $inputString,
'The profile \'' . $name . '\' is already the current ' . $category
. ' profile',
);
} else {
return $self->error(
$session, $inputString,
'The profile \'' . $name . '\' is the current ' . $currentObj->category
. ' profile',
);
}
}
}
# For character profiles, need to check that another session isn't already using the same
# profile. The TRUE flag means 'ignore sessions whose ->status is 'disconnected')
if (
$category eq 'char'
&& $axmud::CLIENT->testSessions($session->currentWorld->name, $name, TRUE)
) {
return $self->error(
$session, $inputString,
'You are already using \'' . $name . '\' as the current character profile in'
. ' another session',
);
}
# If the profile exists, use it
if ($session->ivExists('profHash', $name)) {
$obj = $session->ivShow('profHash', $name);
# Check it's the right category of profile
if ($obj->category ne $category) {
return $self->error(
$session, $inputString,
'The profile \'' . $name . '\' is a ' . $obj->category . ' profile',
);
}
lib/Games/Axmud/Generic.pm view on Meta::CPAN
}
# If the Status task's counters are running, reset their values, and turn them off
if ($session->statusTask) {
$session->statusTask->update_profiles();
}
# Operation complete
if (! $pwd) {
return $self->complete(
$session, $standardCmd,
'Added \'' . $name . '\' as the current ' . $category . ' profile',
);
} else {
return $self->complete(
$session, $standardCmd,
'Added \'' . $name . '\' with the password \'********\' as the current '
. $category . ' profile',
);
}
}
}
sub unsetProfile {
# Called by GA::Cmd::UnsetGuild->do, UnsetRace->do, UnsetChar->do
# Unsets the current guild/race/char profile (so that it's not a current profile
# any more)
#
# Expected arguments
# $session - The calling function's GA::Session
# $inputString - The command actually typed, e.g. 'ug thief'
# $standardCmd - Standard version of the client command, e.g. 'unsetguild'
# $category - The category of profile - 'guild', 'race' or 'char'
#
# Return values
# 'undef' on improper arguments or if there's an error
# 1 on success
my ($self, $session, $inputString, $standardCmd, $category, $check) = @_;
# Local variables
my (
$obj,
%customProfHash,
);
# Check for improper arguments
if (
! defined $session || ! defined $inputString || ! defined $standardCmd
|| ! defined $category || defined $check
) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->unsetProfile', @_);
}
# Check there are no 'free' windows open in any session
if ($axmud::CLIENT->desktopObj->freeWinHash) {
return $self->error(
$session, $inputString,
'Can\'t delete a profile while there are \'free\' windows (such as edit,'
. ' preference and wizard windows) open in any session - try closing them first',
);
}
# Check there is a current profile of the right category
if (! $session->ivExists('currentProfHash', $category)) {
return $self->error(
$session, $inputString,
'There is no current ' . $category . ' profile',
);
} else {
$obj = $session->ivShow('currentProfHash', $category);
}
# Guild/race profiles only - if there's a current character, inform it it has lost its
# guild/race
if ($category eq 'guild' || $category eq 'char') {
if ($session->currentChar) {
if ($category eq 'guild') {
$session->currentChar->ivUndef('guild');
} elsif ($category eq 'race') {
$session->currentChar->ivUndef('race');
}
}
# Character profiles only - if the character profile specifies a guild, race or custom
# profiles as current profile, unset them, too
} elsif ($category eq 'char') {
if ($obj->guild) {
$obj->ivUndef('guild');
$session->pseudoCmd('unsetguild', 'hide_complete');
}
if ($obj->race) {
$obj->ivUndef('race');
$session->pseudoCmd('unsetrace', 'hide_complete');
}
if ($obj->customProfHash) {
%customProfHash = $obj->customProfHash;
foreach my $customProf (keys %customProfHash) {
$session->pseudoCmd('unsetcustomprofile ' . $customProf, 'hide_complete');
}
$obj->ivEmpty('customProfHash');
}
lib/Games/Axmud/Generic.pm view on Meta::CPAN
'Could not create the cloned ' . $category .' profile \'' . $copy
. '\' - errors while cloning cages',
);
} else {
# Updates IVs
$session->add_prof($copyObj);
# Tell the current world it's acquired a new associated definiton
$session->currentWorld->ivAdd('profHash', $copy, $category);
# If it's a character profile, update more IVs
if ($category eq 'char') {
# Character's password and associated account names not yet known
$session->currentWorld->ivAdd('passwordHash', $copy, undef);
$session->currentWorld->ivAdd('accountHash', $copy, undef);
}
return $self->complete(
$session, $standardCmd,
'Created cloned ' . $category . ' profile \'' . $copy . '\'',
);
}
}
sub deleteProfile {
# Called by GA::Cmd::DeleteGuild->do, DeleteRace->do, DeleteChar->do or
# DeleteCustomProfile->do
# Deletes a guild/race/char or custom profile
#
# Expected arguments
# $session - The calling function's GA::Session
# $inputString - The command actually typed, e.g. 'ug thief'
# $standardCmd - Standard version of the client command, e.g. 'unsetguild'
# $name - The profile's name
# $category - The category of profile - 'guild', 'race' or 'char' or a custom
# profile category
#
# Return values
# 'undef' on improper arguments or if there's an error
# 1 on success
my ($self, $session, $inputString, $standardCmd, $name, $category, $check) = @_;
# Local variables
my (
$obj,
%customProfHash,
);
# Check for improper arguments
if (
! defined $session || ! defined $inputString || ! defined $standardCmd
|| ! defined $name || ! defined $category || defined $check
) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->deleteProfile', @_);
}
# Check there are no 'free' windows open in any session
if ($axmud::CLIENT->desktopObj->freeWinHash) {
return $self->error(
$session, $inputString,
'Can\'t delete a profile while there are \'free\' windows (such as edit,'
. ' preference and wizard windows) open in any session - try closing them first',
);
}
# Check the profile exists
if (! $session->ivExists('profHash', $name)) {
return $self->error(
$session, $inputString,
'The profile \'' . $name . '\' doesn\'t exist',
);
} else {
$obj = $session->ivShow('profHash', $name);
}
# Check the profile is the right category
if ($obj->category ne $category) {
return $self->error(
$session, $inputString,
'The profile \'' . $name . '\' is a ' . $obj->category . ' profile',
);
}
# Delete a current profile
if (defined $session->currentGuild && $session->currentGuild eq $obj) {
# Remove this profile's interfaces
$session->resetProfileInterfaces($obj->name);
# Destroy its cages
$session->destroyCages($obj, TRUE);
# Unset the profile as a current defintition
$session->del_currentProf($category);
# Remove the profile
$session->del_prof($obj);
# Guild/race profiles only - if there's a current character, inform it that it has lost
# its associated profile
if ($category eq 'guild' || $category eq 'race') {
if ($session->currentChar) {
if ($category eq 'guild') {
$session->currentChar->ivUndef('guild');
} elsif ($category eq 'race') {
$session->currentChar->ivUndef('race');
}
}
# Character profiles only - if the character profile specifies a guild, race or custom
# profiles as current profiles, unset them
} elsif ($category eq 'char') {
if ($obj->guild) {
lib/Games/Axmud/Generic.pm view on Meta::CPAN
# ->editHash{iv_name} = list_reference;
# ->editHash{iv_name} = hash_reference;
# For 'pref' windows, a hash of key-value pairs set by the window's widgets;
# $self->enableButtons can access this hash to perform any necessary actions
# ('pref' windows don't make a call to ->saveChanges)
editHash => {},
# Hash containing any number of key-value pairs needed for this particular
# 'edit'/'pref' window; for example, GA::PrefWin::TaskStart uses it to specify a task
# name and type. Set to an empty hash if not required
editConfigHash => \%configHash,
# In the index on the left-hand side of the window, the pointer (Gtk3::TreeIter) for
# the $self->notebook tab that's currently being drawn
indexPointer => undef,
# A hash of inner Gtk3::Notebooks. Keys are a tab number in the outer notebook (first
# tab is #0); the corresponding values are the inner notebook for that tab, or
# 'undef' if the tab has no inner notebook
innerNotebookHash => {},
};
# 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 or if $self->editObj is the wrong type of object
# 1 on success
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->winEnable', @_);
}
# For 'edit' windows, check that $self->editObj is of the right type. For 'pref' windows,
# $self->editObj is not set, so the check always succeeds
if (! $self->checkEditObj()) {
return undef;
}
# Make the window appear on the desktop
$self->winShowAll($self->_objClass . '->winEnable');
$self->ivPoke('enabledFlag', TRUE);
return 1;
}
# 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 'edit'/'pref' 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', @_);
}
if (! $axmud::CLIENT->configWinIndexFlag) {
# Create a packing box
my $packingBox = Gtk3::VBox->new(FALSE, 0);
$self->winBox->add($packingBox);
$packingBox->set_border_width(0);
# Add a notebook at the top
my $notebook = Gtk3::Notebook->new();
$packingBox->pack_start($notebook, TRUE, TRUE, 0);
$notebook->set_scrollable(TRUE);
$notebook->popup_enable();
# Add a button strip at the bottom, in a horizontal packing box
my $hBox = Gtk3::HBox->new(FALSE, 0);
$packingBox->pack_end($hBox, FALSE, FALSE, $self->spacingPixels);
# Create Reset/Save/Cancel/OK buttons
my ($okButton, $cancelButton, $resetButton, $saveButton) = $self->enableButtons($hBox);
# Update IVs
$self->ivPoke('packingBox', $packingBox);
$self->ivPoke('notebook', $notebook);
$self->ivPoke('hBox', $hBox);
$self->ivPoke('okButton', $okButton);
$self->ivPoke('cancelButton', $cancelButton);
$self->ivPoke('resetButton', $resetButton);
$self->ivPoke('saveButton', $saveButton);
lib/Games/Axmud/Generic.pm view on Meta::CPAN
) = @_;
# Check for improper arguments
if (
! defined $grid || ! defined $editableFlag || ! defined $leftAttach
|| ! defined $rightAttach || ! defined $topAttach || defined $check
) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->addTextView', @_);
}
# Check that the position in the grid makes sense
if (! $self->checkPosn($leftAttach, $rightAttach, $topAttach, $bottomAttach)) {
return undef;
}
# Set defaults
if (! defined $listFlag) {
$listFlag = TRUE;
}
if (! defined $removeEmptyFlag) {
$removeEmptyFlag = TRUE;
}
if (! defined $removeSpaceFlag) {
$removeSpaceFlag = TRUE;
}
if (! defined $width) {
$width = -1; # Let Gtk3 set the width
}
if (! defined $height) {
$height = -1; # Let Gtk3 set the height
}
# Creating a containing Gtk3::Frame and Gtk3::ScrolledWindow
my $scroll = Gtk3::ScrolledWindow->new(undef, undef);
$scroll->set_shadow_type($axmud::CLIENT->constShadowType);
$scroll->set_policy('automatic', 'automatic');
$scroll->set_size_request($width, $height);
# $scroll->set_border_width($self->spacingPixels);
# Create a textview with default colours/fonts
my $textView = Gtk3::TextView->new();
$scroll->add($textView);
my $buffer = Gtk3::TextBuffer->new();
$textView->set_buffer($buffer);
if ($noScrollFlag) {
$textView->set_wrap_mode('word-char'); # Wrap words if possible, characters if not
$textView->set_justification('left');
}
$axmud::CLIENT->desktopObj->setTextViewStyle($self->winType, $textView);
if ($iv) {
# Display the existing value of the IV (the call to $buffer->set_text requires a
# defined value, so don't try to display 'undef')
if ($self->editObj->$iv) {
if ($listFlag) {
# The call to ->ivPeek returns the contents of the IV as a flat list
$buffer->set_text(join("\n", $self->editObj->ivPeek($iv)));
} else {
$buffer->set_text($self->editObj->$iv);
}
}
$buffer->signal_connect('changed' => sub {
my (
$text,
@list, @finalList,
);
$text = $axmud::CLIENT->desktopObj->bufferGetText($buffer);
if ($listFlag) {
# Split the contents of the textview into a list of lines, separated by
# newline characters
@list = split("\n", $text);
# Remove any empty lines and leading/trailing whitespace, if allowed
foreach my $line (@list) {
if ($line && $removeSpaceFlag) {
$line =~ s/^\s+//; # Remove leading whitespace
$line =~ s/\s+$//; # Remove trailing whitespace
}
if ($line || ! $removeEmptyFlag) {
push (@finalList, $line);
}
}
# Set the IV
$self->ivAdd('editHash', $iv, \@finalList);
} else {
# Treat the contents of the IV as a single string
$self->ivAdd('editHash', $iv, $text);
}
});
}
# Make the textview editable or not editable
$textView->set_editable($editableFlag);
# Add the textview to the grid
$scroll->set_hexpand(TRUE);
$scroll->set_vexpand(TRUE);
$grid->attach(
$scroll,
$leftAttach,
$topAttach,
($rightAttach - $leftAttach),
($bottomAttach - $topAttach),
);
return $textView;
}
sub addSimpleList {
# Adds a GA::Obj::SimpleList at the specified position in the window's Gtk3::Grid
#
# Example calls:
# my $slWidget = $self->addSimpleList($grid, 'some_IV', \@columnList,
# 0, 6, 0, 1);
# my $slWidget = $self->addSimpleList($grid, 'some_IV', \@columnList,
# 0, 6, 0, 1,
# -1, -1,
# GA::Client->getMethodRef('function_name'));
lib/Games/Axmud/Generic.pm view on Meta::CPAN
} else {
push (@patternList, $key);
}
}
}
}
} until (! @list);
if (! @patternList) {
$self->showMsgDialogue(
'Check patterns',
'info',
'There are no patterns on this page',
'ok',
);
} else {
# Check every pattern in turn. GA::Client->regexCheck returns 'undef' if the
# regex is valid, or an error message if it's not valid
foreach my $pattern (@patternList) {
my $error = $axmud::CLIENT->regexCheck($pattern);
if (defined $error) {
push (@errorList, $pattern, $error);
}
}
if (! @errorList) {
$self->showMsgDialogue(
'Check patterns',
'info',
'All patterns on this page are valid',
'ok',
);
} else {
$msg = 'Patterns checked: ' . (scalar @patternList) . ', errors: '
. ((scalar @errorList) / 2);
$count = 0;
do {
my ($pattern, $error);
$pattern = shift @errorList;
$error = shift @errorList;
$count++;
chomp $pattern;
chomp $error;
$msg .= "\n\n$pattern\n$error";
# (Only show the first 2 errors - don't want a dialogue window as big as
# the desktop)
if ($count >= 2 && @errorList) {
$msg .= "\n\n...";
@errorList = ();
}
} until (! @errorList);
$self->showMsgDialogue(
'Check patterns',
'error',
$msg,
'ok',
undef,
TRUE, # Preserve newline characters in $msg
);
}
}
});
}
# Add the button to the grid
$button->set_hexpand(TRUE);
$button->set_vexpand(FALSE);
$grid->attach(
$button,
$leftAttach,
$topAttach,
($rightAttach - $leftAttach),
($bottomAttach - $topAttach),
);
return $button;
}
# Add widgets - special functions for GA::EditWin::Generic::Interface and
# GA::EditWin::Interface::Active
sub useCheckButton {
# Adapted from $self->addCheckButton
# Adds a Gtk3::CheckButton with an accompnaying label at the specified position in the
# window's Gtk3::Grid. Instead of setting an IV in $self->editHash, sets a key-value pair
# in $self->attribHash
#
# Example calls:
# my $checkButton = $self->useCheckButton($grid, 'Click me', 'some_attribute', TRUE,
# 0, 6, 0, 1);
# my $checkButton = $self->useCheckButton($grid, undef, 'some_attribute', TRUE,
# 0, 6, 0, 1);
#
# Expected arguments
# $grid - The tab's Gtk3::Grid object
# $name - A 'name' for the checkbutton (displayed next to the button); if 'undef',
# no name is displayed
# $attrib - The name of the attribute set when the check button is toggled (matches
# a key in $self->attribHash and GA::Interface::Trigger->attribHash)
# $stateFlag - Flag set to FALSE if the checkbutton's state should be 'insensitive',
# TRUE if it should be 'normal'
# $leftAttach, $rightAttach, $topAttach, $bottomAttach
lib/Games/Axmud/Generic.pm view on Meta::CPAN
# $readOnlyFlag
# - If set to TRUE, the scalar is read-only (so can't be edited); otherwise set
# to FALSE (or 'undef')
# $callFunc
# - If specified, $self->$funcName is called when the IV is updated instead of the
# usual call to $self->updateListDataWithKey (useful if we don't want the
# simple list sorted alphabetically, as normally happens); otherwise set to
# 'undef'
# @callFuncArgs
# - Optional list of args to be passed if $callFunc is called; otherwise an empty
# list
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $iv, $key, $deRefFlag, $slWidget, $readOnlyFlag, $callFunc, @callFuncArgs) = @_;
# Local variables
my (
$title, $labelText, $outerHashRef, $value, $response,
%outerHash,
);
# Check for improper arguments
if (! defined $iv) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->promptScalar', @_);
}
# Set the window title
if ($readOnlyFlag) {
$title = 'View Scalar';
} else {
$title = 'Edit Scalar';
}
# Show the 'dialogue' window
my $dialogueWin;
if (! $readOnlyFlag) {
$dialogueWin = Gtk3::Dialog->new(
$title,
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
'gtk-cancel' => 'reject',
'gtk-ok' => 'accept',
);
} else {
$dialogueWin = Gtk3::Dialog->new(
$title,
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
'gtk-ok' => 'accept',
);
}
$dialogueWin->set_position('center-always');
$dialogueWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
$dialogueWin->signal_connect('delete-event' => sub {
$dialogueWin->destroy();
$self->restoreFocus();
# (In case TTS is being used and another 'dialogue' window is about to open, make sure
# the window is visibly closed)
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->promptScalar');
});
# Add widgets to the 'dialogue' window
my $vBox = $dialogueWin->get_content_area();
# The call to ->addDialogueIcon splits $vBox in two, with an icon on the left, and a new
# Gtk3::VBox on the right, into which we put everything
my $vBox2 = $self->addDialogueIcon($vBox);
# Create a label, which will shortly show which IV is being edited (a second label,
# $undefLabel, is sometimes used immediately below it)
my $label = Gtk3::Label->new();
$label->set_alignment(0, 0.5);
# Create an entry, in which the user supplies a new value
my $entry = Gtk3::Entry->new;
if ($readOnlyFlag) {
$entry->set_state('insensitive');
}
# Set the contents of the entry box, and prepare the label text
if (! defined $key) {
# Mode 1 - edit the value of $self->editObj->$iv or $self->editHash->$iv
$labelText = 'Value of IV \'' . $iv . '\'';
# If the IV hasn't yet been edited, use the original value
if (! $self->ivExists('editHash', $iv)) {
if (defined $self->editObj->{$iv}) {
# Put the current value in the entry box
$entry->set_text($self->editObj->{$iv});
} else {
# Add more text to the label, to show that the value is 'undef'
$labelText .= ' <i>(currently \'undef\')</i>';
}
# If the IV has been edited, use the edited value
} else {
# Use an edited value
if (defined $self->ivShow('editHash', $iv)) {
$entry->set_text($self->ivShow('editHash', $iv));
} else {
# Add more text to the label, to show that the value is 'undef'
$labelText .= ' <i>(currently \'undef\')</i>';
}
}
} else {
# Mode 2 - edit the scalar stored in a key-value pair; the pair is in the hash
# stored as $self->editObj->$iv or $self->editHash->$iv
$labelText = 'Value of key \'' . $key . '\' stored in IV \'' . $iv . '\'';
lib/Games/Axmud/Generic.pm view on Meta::CPAN
# Pack the label and entry box
$vBox2->pack_start($label, TRUE, TRUE, $self->spacingPixels);
$vBox2->pack_start($entry, TRUE, TRUE, $self->spacingPixels);
# Optionally add a button strip in the lower area, containing a single button
if (! $readOnlyFlag) {
my $hBox = Gtk3::HBox->new(FALSE, 0);
$vBox2->pack_start($hBox, TRUE, TRUE, $self->spacingPixels);
# Create the 'use undef' button
my $button3 = Gtk3::Button->new('Use \'undef\' value');
$hBox->pack_end($button3, FALSE, FALSE, $self->spacingPixels);
$button3->signal_connect('clicked' => sub {
# Store an 'undef' scalar value
# Mode 1 - edit the scalar stored in $self->editObj->$iv or $self->editHash->$iv
if (! defined $key) {
$self->ivAdd('editHash', $iv, undef);
# Update the simple list displayed in the parent window, if a list was specified
if ($slWidget) {
$self->updateListDataWithKey($slWidget, $iv, undef);
}
# Mode 2 - edit the scalar stored in a key-value pair; the pair is in the hash
# stored as $self->editObj->$iv or $self->editHash->$iv
} else {
# Update the hash stored in the IV with a new key-value pair. The key is $key,
# the corresponding value is the new scalar
$outerHash{$key} = undef;
# Store the modified outer hash as the IV
$self->ivAdd('editHash', $iv, \%outerHash);
# Update the simple list displayed in the parent window, if a list was specified
if ($slWidget) {
$self->updateListDataWithKey($slWidget, $key, undef);
}
}
# Call a function to re-display the simple list in the parent window, if a function
# was specified
if ($callFunc) {
$self->$callFunc(@callFuncArgs);
}
# Close the window and return success value
$dialogueWin->destroy();
$self->restoreFocus();
# (In case TTS is being used and another 'dialogue' window is about to open, make
# sure the window is visibly closed)
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->promptScalar');
return 1;
});
}
# Widget drawing complete
$vBox->show_all();
# Get the response
$response = $dialogueWin->run();
if ($response eq 'accept') {
my $scalar;
# Don't save anything for read-only values
if (! $readOnlyFlag) {
$scalar = $entry->get_text();
# Mode 1 - edit the value stored in of $self->editObj->$iv or $self->editHash->$iv
if (! defined $key) {
# Store the edited scalar
$self->ivAdd('editHash', $iv, $scalar);
# Update the simple list displayed in the parent window, if a list was specified
if ($slWidget) {
$self->updateListDataWithKey($slWidget, $iv, $scalar);
}
# Mode 2 - edit the scalar stored in a key-value pair; the pair is in the hash
# stored as $self->editObj->$iv or $self->editHash->$iv
} else {
# Update the hash stored in the IV with a new key-value pair. The key is $key,
# the corresponding value is the new scalar
if ($deRefFlag) {
# Cage masks: $value is a scalar reference
$value = \$scalar;
} else {
# Everything else: $value is a normal scalar
$value = $scalar;
}
$outerHash{$key} = $value;
# Store the modified outer hash as the IV
$self->ivAdd('editHash', $iv, \%outerHash);
# Update the simple list displayed in the parent window, if a list was specified
if ($slWidget) {
$self->updateListDataWithKey($slWidget, $key, $value);
}
}
# Call a function to re-display the simple list in the parent window, if a function
# was specified
if ($callFunc) {
$self->$callFunc(@callFuncArgs);
}
}
}
# Destroy the window
$dialogueWin->destroy();
$self->restoreFocus();
# (In case TTS is being used and another 'dialogue' window is about to open, make sure the
# window is visibly closed)
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->promptScalar');
# Operation complete
return 1;
}
sub promptList {
# Creates a 'dialogue' window to prompt the user to view, enter (or edit) a list of values
# If the user supplies any values, sets the IV then closes the window
#
# Operates in two modes
# Mode 1 - the supplied IV is a list, i.e.
# $self->editObj->$iv = [some_list]
# $self->editHash->$iv = [some_list]
# - the values supplied by the user are saved in place of [some_list]
#
# Mode 2 - the supplied IV is a hash, i.e.
# $self->editObj->$iv = {some_hash}
# $self->editHash->$iv = {some_hash}
# - the calling function also supplies a key in {some_hash}
# - a reference to the list supplied by the user is saved as the key's
# corresponding value
#
# Expected arguments
# $iv - The IV to set in $self->editHash
#
# Optional arguments
# $key - In mode 1, 'undef'; in mode 2, a key in {some_hash}
# $slWidget
# - In mode 1, 'undef'; in mode 2, 'undef' or the GA::Obj::SimpleList in which the
# IV's data is being displayed (if specified, the simple list is updated when
# this window is closed)
# $readOnlyFlag
# - If set to TRUE, the list is read-only (so can't be edited); otherwise set
# to FALSE (or 'undef')
# $callFunc
# - If specified, $self->$funcName is called when the IV is updated instead of the
# usual call to $self->updateListDataWithKey (useful if we don't want the
# simple list sorted alphabetically, as normally happens); otherwise set to
# 'undef'
# @callFuncArgs
# - Optional list of args to be passed if $callFunc is called; otherwise an empty
# list
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $iv, $key, $slWidget, $readOnlyFlag, $callFunc, @callFuncArgs) = @_;
# Local variables
my (
$title, $replaceListRef, $outerHashRef, $response,
%outerHash,
);
# Check for improper arguments
if (! defined $iv) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->promptList', @_);
}
# Set the window title
if ($readOnlyFlag) {
$title = 'View List';
} else {
$title = 'Edit List';
}
# Show the 'dialogue' window
my $dialogueWin;
if (! $readOnlyFlag) {
$dialogueWin = Gtk3::Dialog->new(
$title,
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
'gtk-cancel' => 'reject',
'gtk-ok' => 'accept',
);
} else {
$dialogueWin = Gtk3::Dialog->new(
$title,
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
'gtk-ok' => 'accept',
);
}
$dialogueWin->set_position('center-always');
$dialogueWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
$dialogueWin->signal_connect('delete-event' => sub {
$dialogueWin->destroy();
$self->restoreFocus();
# (In case TTS is being used and another 'dialogue' window is about to open, make sure
# the window is visibly closed)
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->promptList');
});
# Add widgets to the 'dialogue' window
my $vBox = $dialogueWin->get_content_area();
# The call to ->addDialogueIcon splits $vBox in two, with an icon on the left, and a new
# Gtk3::VBox on the right, into which we put everything
my $vBox2 = $self->addDialogueIcon($vBox);
# Create a label, which will shortly show which IV is being edited
my $label = Gtk3::Label->new();
$vBox2->pack_start($label, TRUE, TRUE, $self->spacingPixels);
$label->set_alignment(0, 0.5);
# Create a textview, in which the user supplies a list of values
my $scroll = Gtk3::ScrolledWindow->new(undef, undef);
$vBox2->pack_start($scroll, TRUE, TRUE, $self->spacingPixels);
$scroll->set_shadow_type($axmud::CLIENT->constShadowType);
$scroll->set_policy('automatic', 'automatic');
$scroll->set_size_request(200, 150); # Minimum size
$scroll->set_border_width($self->spacingPixels);
# Create a textview with default colours/fonts
my $textView = Gtk3::TextView->new();
$scroll->add($textView);
my $buffer = Gtk3::TextBuffer->new();
$textView->set_buffer($buffer);
if ($readOnlyFlag) {
$textView->set_editable(FALSE);
} else {
$textView->set_editable(TRUE);
}
$axmud::CLIENT->desktopObj->setTextViewStyle($self->winType, $textView);
# Set the contents of the label and the textview
if (! defined $key) {
# Mode 1 - edit the list stored in $self->editObj->$iv or $self->editHash->$iv
$label->set_markup('List stored in IV \'' . $iv . '\'');
# If the IV hasn't yet been edited, use the original stored list
if (! $self->ivExists('editHash', $iv)) {
$replaceListRef = $self->editObj->{$iv}; # (Profile templates have no accessors)
$buffer->set_text(join("\n", @$replaceListRef));
# If the IV has been edited, use the edited list
} else {
$replaceListRef = $self->ivShow('editHash', $iv);
$buffer->set_text(join("\n", @$replaceListRef));
}
} else {
# Mode 2 - edit the list stored in a key-value pair; the pair is in the hash
# stored as $self->editObj->$iv or $self->editHash->$iv
$label->set_markup('List stored in key \'' . $key . '\' in IV \'' . $iv . '\'');
# Get a copy of the hash being edited
if (! $self->ivExists('editHash', $iv)) {
$outerHashRef = $self->editObj->{$iv}; # (Profile templates have no accessors)
%outerHash = %$outerHashRef;
} else {
$outerHashRef = $self->ivShow('editHash', $iv);
%outerHash = %$outerHashRef;
}
# Put the current contents of the list in the textview
if (exists $outerHash{$key} && defined $outerHash{$key}) {
$replaceListRef = $outerHash{$key};
$buffer->set_text(join("\n", @$replaceListRef));
}
}
# Widget drawing complete
$vBox->show_all();
# Get the response
$response = $dialogueWin->run();
if ($response eq 'accept') {
my (
$text,
@dataList,
);
# Don't save anything for read-only values
if (! $readOnlyFlag) {
$text = $axmud::CLIENT->desktopObj->bufferGetText($buffer);
# Split the contents of the textview into a list of lines, separated by
# newline characters
@dataList = split("\n", $text);
# Mode 1 - edit the list stored in of $self->editObj->$iv or $self->editHash->$iv
if (! defined $key) {
# Store the list we've been editing
$self->ivAdd('editHash', $iv, \@dataList);
# Update the simple list displayed in the parent window, if a list was specified
if ($slWidget) {
$self->updateListDataWithKey($slWidget, $iv, \@dataList);
}
# Mode 2 - edit the list stored in a key-value pair; the pair is in the hash
# stored as $self->editObj->$iv or $self->editHash->$iv
} else {
# Update the hash stored in the IV with a new key-value pair. The key is
# $key, the corresponding value is a reference to the list we've
# been editing, @dataList
$outerHash{$key} = \@dataList;
# Store the modified outer hash as the IV
$self->ivAdd('editHash', $iv, \%outerHash);
# Update the simple list displayed in the parent window, if a list was specified
if ($slWidget) {
$self->updateListDataWithKey($slWidget, $key, \@dataList);
}
}
# Call a function to re-display the simple list in the parent window, if a function
# was specified
if ($callFunc) {
$self->$callFunc(@callFuncArgs);
}
}
}
# Destroy the window
$dialogueWin->destroy();
$self->restoreFocus();
# (In case TTS is being used and another 'dialogue' window is about to open, make sure the
# window is visibly closed)
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->promptList');
# Operation complete
return 1;
}
sub promptHash {
# Creates a 'dialogue' window to prompt the user to view, enter (or edit) a hash of
# key-value pairs
# If the user supplies any pairs, sets the IV then closes the window
#
# Operates in two modes
# Mode 1 - the supplied IV is a hash, i.e.
# $self->editObj->$iv = {some_hash}
# $self->editHash->$iv = {some_hash}
# - the key-value pairs supplied by the user are saved in place of {some_hash}
#
# Mode 2 - the supplied IV is a hash, i.e.
# $self->editObj->$iv = {some_hash}
# $self->editHash->$iv = {some_hash}
# - the calling function also supplies a key in {some_hash}
# - a reference to the hash supplied by the user is saved as the key's
# corresponding value
#
# Expected arguments
# $iv - The IV to set in $self->editObj
#
# Optional arguments
# $key - In mode 1, 'undef'; in mode 2, a key in {some_hash}
# $slWidget
# - In mode 1, 'undef'; in mode 2, 'undef' or the GA::Obj::SimpleListin which the
# IV's data is being displayed (if specified, the simple list is updated when
# this window is closed)
# $readOnlyFlag
# - If set to TRUE, the scalar is read-only (so can't be edited); otherwise set to
# FALSE (or 'undef')
# $callFunc
# - If specified, $self->$funcName is called when the IV is updated instead of the
# usual call to $self->updateListDataWithKey (useful if we don't want the
# simple list sorted alphabetically, as normally happens); otherwise set to
# 'undef'
# @callFuncArgs
# - Optional list of args to be passed if $callFunc is called; otherwise an empty
# list
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $iv, $key, $slWidget, $readOnlyFlag, $callFunc, @callFuncArgs) = @_;
# Local variables
my (
$title, $response, $outerHashRef,
%outerHash, %replaceHash, %innerHash,
);
# Check for improper arguments
if (! defined $iv) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->promptHash', @_);
}
# Set the window title
if ($readOnlyFlag) {
$title = 'View Hash';
} else {
$title = 'Edit Hash';
}
# Show the 'dialogue' window
my $dialogueWin;
if (! $readOnlyFlag) {
$dialogueWin = Gtk3::Dialog->new(
$title,
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
'gtk-cancel' => 'reject',
'gtk-ok' => 'accept',
);
} else {
$dialogueWin = Gtk3::Dialog->new(
$title,
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
'gtk-ok' => 'accept',
);
}
$dialogueWin->set_position('center-always');
$dialogueWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
$dialogueWin->signal_connect('delete-event' => sub {
$dialogueWin->destroy();
$self->restoreFocus();
# (In case TTS is being used and another 'dialogue' window is about to open, make sure
# the window is visibly closed)
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->promptHash');
});
# Add widgets to the 'dialogue' window
my $vBox = $dialogueWin->get_content_area();
# The call to ->addDialogueIcon splits $vBox in two, with an icon on the left, and a new
# Gtk3::VBox on the right, into which we put everything
my $vBox2 = $self->addDialogueIcon($vBox);
# Create a label, which will shortly show which IV is being edited
my $label = Gtk3::Label->new();
$vBox2->pack_start($label, TRUE, TRUE, $self->spacingPixels);
$label->set_alignment(0, 0.5);
# Create a scroller
my $scroller = Gtk3::ScrolledWindow->new;
$vBox2->pack_start($scroller, TRUE, TRUE, $self->spacingPixels);
$scroller->set_policy('automatic', 'automatic');
$scroller->set_size_request(200, 150); # Minimum size
# Create a simple list with two columns representing a hash, for which the user
# supplies key-value pairs
my $slWidget2 = Games::Axmud::Obj::SimpleList->new(
# Give the first column a minimum width; don't want the columns moving around too
# much when the user enter new key-value pairs
'Key ' => 'text',
'Value' => 'text',
);
$scroller->add($slWidget2);
# Set the contents of the label and the simple list. We don't want to overwrite the hash
# until the user clicks the 'ok' button, so we'll edit a copy of the hash
if (! defined $key) {
# Mode 1 - edit the hash stored in $self->editObj->$iv or $self->editHash->$iv
$label->set_markup('Hash stored in IV \'' . $iv . '\'');
%outerHash = $self->promptHash_displayDataMode1($slWidget2, $iv);
# Edit a copy, so that we can revert to the original copy if we want to
%replaceHash = %outerHash;
} else {
# Mode 2 - edit the hash stored in a key-value pair; the pair is in the hash
# stored as $self->editObj->$iv or $self->editHash->$iv
$label->set_markup('Hash stored in key \'' . $key . "\'\nin IV \'" . $iv . "\'");
%innerHash = $self->promptHash_displayDataMode2($slWidget2, $iv, $key);
# Edit a copy, so that we can revert to the original copy if we want to
%replaceHash = %innerHash;
}
# If the hash is editable, we have a lot more widgets to add
if (! $readOnlyFlag) {
# Add a grid containing entry boxes for new key-value pairs. The grid ensures that
# the two entry boxes are aligned with each other
my $grid = Gtk3::Grid->new();
$vBox2->pack_start($grid, TRUE, TRUE, $self->spacingPixels);
my $label2 = Gtk3::Label->new();
$label2->set_alignment(0, 0.5);
$label2->set_markup('Key');
lib/Games/Axmud/Generic.pm view on Meta::CPAN
# Don't save anything for read-only values
if (! $readOnlyFlag) {
# Mode 1 - edit the hash stored in $self->editObj->$iv or $self->editHash->$iv
if (! defined $key) {
# Store the hash we've been editing
$self->ivAdd('editHash', $iv, \%replaceHash);
# Update the simple list displayed in the parent window, if a list was specified
if ($slWidget) {
$self->updateListDataWithKey($slWidget, $iv, \%replaceHash);
}
# Mode 2 - edit the hash stored in a key-value pair; the pair is in the hash stored
# as $self->editObj->$iv or $self->editHash->$iv
} else {
# Get a copy of the hash stored in the IV
if (! $self->ivExists('editHash', $iv)) {
%outerHash = $self->editObj->$iv;
# If the IV has been edited, use the edited hash
} else {
$outerHashRef = $self->ivShow('editHash', $iv);
%outerHash = %$outerHashRef;
}
# Now update that hash with a new key-value pair. The key is $key, the
# corresponding value is a reference to the hash we've been editing,
# %replaceHash
$outerHash{$key} = \%replaceHash;
# Store the modified outer hash as the IV
$self->ivAdd('editHash', $iv, \%outerHash);
# Update the displayed list, if one was specified
if ($slWidget) {
$self->updateListDataWithKey($slWidget, $key, \%replaceHash);
}
}
# Call a function to re-display the simple list, if one was specified
if ($callFunc) {
$self->$callFunc(@callFuncArgs);
}
}
}
# Destroy the window
$dialogueWin->destroy();
$self->restoreFocus();
# (In case TTS is being used and another 'dialogue' window is about to open, make sure the
# window is visibly closed)
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->promptHash');
# Operation complete
return 1;
}
sub promptHash_displayDataMode1 {
# Called by $self->promptHash when we want to edit a hash IV in $self->editObj or
# $self->editHash
# The calling function had created a GA::Obj::SimpleList; this function's job is to fill
# it with data
#
# Expected arguments
# $slWidget - The GA::Obj::SimpleList where the IV's data is displayed
# $iv - The IV being edited
#
# Return values
# An empty hash on improper arguments
# Otherwise returns a copy of the hash being edited
my ($self, $slWidget, $iv, $check) = @_;
# Local variables
my (
$hashRef,
%emptyHash, %dataHash,
);
# Check for improper arguments
if (! defined $slWidget || ! defined $iv || defined $check) {
$axmud::CLIENT->writeImproper(
$self->_objClass . '->promptHash_displayDataMode1',
@_,
);
return %emptyHash;
}
# If the IV hasn't yet been edited, use the original stored hash
if (! $self->ivExists('editHash', $iv)) {
$hashRef = $self->editObj->{$iv}; # (Profile templates have no accessors)
%dataHash = %$hashRef;
# If the IV has been edited, use the edited hash
} else {
$hashRef = $self->ivShow('editHash', $iv);
%dataHash = %$hashRef;
}
# Update the GA::Obj::SimpleList (which currently stores no data)
foreach my $key (sort {lc($a) cmp lc($b)} (keys %dataHash)) {
push (
@{$slWidget->{data}},
[$key, $dataHash{$key}],
);
}
lib/Games/Axmud/Generic.pm view on Meta::CPAN
##################
# Constructors
# sub new {} # Defined in window objects which inherit this one
##################
# 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', @_);
}
# 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 {
# 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);
return 1;
}
sub winDisengage {
# Should not be called, in general (provides compatibility with other types of windows,
# whose window objects can be destroyed without closing the windows themselves)
# If called, this function just calls $self->winDestroy and returns the result
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if the window can't be disengaged
# 1 on success
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->winDisengage', @_);
}
return $self->winDestroy();
}
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);
}
return 1;
}
# sub winShowAll {} # Inherited from GA::Generic::Win
# sub drawWidgets {} # Inherited from GA::Generic::Win
# sub redrawWidgets {} # Inherited from GA::Generic::Win
# ->signal_connects
sub setDeleteEvent {
# Called by $self->winSetup
# Set up a ->signal_connect to watch out for the user manually closing the 'free' window
#
# 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 . '->setDeleteEvent', @_);
}
$self->winBox->signal_connect('delete-event' => sub {
# Prevent Gtk3 from taking action directly. Instead redirect the request to
# $self->winDestroy
return $self->winDestroy();
});
return 1;
}
# Other functions
##################
# Accessors - set
##################
# Accessors - get
sub widthPixels
{ $_[0]->{widthPixels} }
sub heightPixels
{ $_[0]->{heightPixels} }
sub borderPixels
{ $_[0]->{borderPixels} }
lib/Games/Axmud/Generic.pm view on Meta::CPAN
# Called by GA::Obj::Workspace->createGridWin or ->createSimpleGridWin
# This generic function merely creates a Gtk3::Window
# Your own window object code should either create a function based on
# GA::Win::Internal->winSetup, or your code should inherit that function directly
#
# Expected arguments
# (none besides $self)
#
# Optional arguments
# $title - The window title or 'undef'. Ignored in this generic function
# $listRef - Reference to a list of functions to call, just after the Gtk3::Window is
# created (can be used to set up further ->signal_connects, if this
# window needs them)
#
# Return values
# 'undef' on improper arguments or if the window can't be opened
# 1 on success
my ($self, $title, $listRef, $check) = @_;
# Local variables
my $iv;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->winSetup', @_);
}
# Don't create a new window, if it already exists
if ($self->enabledFlag) {
return undef;
}
# Create the Gtk3::Window
my $winWidget = Gtk3::Window->new('toplevel');
if (! $winWidget) {
return undef;
} else {
# Store the IV now, as everything needs it
$self->ivPoke('winWidget', $winWidget);
$self->ivPoke('winBox', $winWidget);
}
# Set up ->signal_connects specified by the calling function, if any
if ($listRef) {
foreach my $func (@$listRef) {
$self->$func();
}
}
# 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($winWidget)) {
return undef;
}
# The calling function can now move the window into position, before calling
# $self->winEnable to make it visible, and to set up any more ->signal_connects()
return 1;
}
sub winEnable {
# Called by GA::Obj::Workspace->createGridWin or ->createSimpleGridWin
# This generic function merely makes the Gtk3::Window visible
# Your own window object code should either create a function based on
# GA::Win::Internal->winEnable, or your code should inherit that function directly
#
# Expected arguments
# (none besides $self)
#
# Optional arguments
# $listRef - Reference to a list of functions to call, just after the Gtk3::Window is
# created (can be used to set up further ->signal_connects, if this
# window needs them)
#
# Return values
# 'undef' on improper arguments
# 1 on success
my ($self, $title, $listRef, $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);
# For windows about to be placed on a grid, briefly minimise the window so it doesn't
# appear in the centre of the desktop before being moved to its correct workspace, size
# and position
if ($self->workspaceGridObj && $self->winWidget eq $self->winBox) {
$self->minimise();
}
# Set up ->signal_connects specified by the calling function, if any
if ($listRef) {
foreach my $func (@$listRef) {
$self->$func();
}
}
return 1;
}
# sub winDisengage {} # Defined in window objects which inherit this one
# sub winDestroy {} # Defined in window objects which inherit this one
# sub winShowAll {} # Inherited from GA::Win::Generic
# sub drawWidgets {} # Inherited from GA::Win::Generic
# sub redrawWidgets {} # Inherited from GA::Win::Generic
# ->signal_connects
sub setDeleteEvent {
# Called by GA::Obj::Workspace->createGridWin (for 'external' windows only)
# Called by $self->winSetup (for other 'grid' windows)
# This generic function doesn't actually create any ->signal_connects
#
# 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 . '->setDeleteEvent', @_);
}
# (Do nothing)
return 1;
}
sub setKeyPressEvent {
# Called by $self->winSetup
# This generic function doesn't actually create any ->signal_connects
lib/Games/Axmud/Generic.pm view on Meta::CPAN
}
# Open a task window, giving up after the first successful attempt
if (! @preferList) {
@preferList = $self->winPreferList;
}
OUTER: foreach my $item (@preferList) {
if ($item eq 'grid') {
$result = $self->openGridWin($winmapObj);
} elsif ($item eq 'pane') {
$result = $self->openPaneWin($winmapObj, FALSE);
} elsif ($item eq 'entry') {
$result = $self->openPaneWin($winmapObj, TRUE);
} elsif ($item eq 'pseudo') {
$result = $self->openPseudoWin($winmapObj);
}
if ($result) {
last OUTER;
}
}
return $result;
}
sub openGridWin {
# Called by the $self->openWin (only)
# Tries to open a task window as a 'grid' window (in response to 'grid' in
# $self->winPreferList)
#
# Expected arguments
# $winmapObj - The winmap object to use in the task window (matches a value in
# GA::Client->winmapHash)
#
# Return values
# 'undef' on improper arguments or if a 'grid' window is not opened
# 1 if a 'grid' window is opened
my ($self, $winmapObj, $check) = @_;
# Local variables
my (
$winObj,
@workspaceList,
);
# Check for improper arguments
if (! defined $winmapObj || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->openGridWin', @_);
}
# Compile a list of workspaces, with the workspace containing the parent session's 'main'
# window first
@workspaceList
= $axmud::CLIENT->desktopObj->listWorkspaces($self->session->mainWin->workspaceObj);
OUTER: foreach my $workspaceObj (@workspaceList) {
$winObj = $workspaceObj->createGridWin(
'custom', # All task windows are 'custom' windows
$self->name, # Window name is the same as the task name
$self->prettyName, # Window title
$winmapObj->name,
'Games::Axmud::Win::Internal',
# Package name
undef, # No windows exists yet
undef, # Ditto
$self, # Owner
$self->session,
$workspaceObj->findWorkspaceGrid($self->session),
# Session's workspace grid object
);
if ($winObj) {
last OUTER;
}
}
if (! $winObj) {
# Window not opened
return undef;
} else {
# Window created and enabled
$self->ivPoke('winObj', $winObj);
$self->ivPoke('taskWinFlag', TRUE);
# Set its title
$self->setTaskWinTitle();
# In Axmud 'blind' mode, make sure the session's 'main' window is not obscured by the
# newly-opened task window
if ($axmud::BLIND_MODE_FLAG) {
$self->session->mainWin->restoreFocus();
}
}
# Add a tab, if required. The TRUE argument indicates window setup
$self->addTab(undef, TRUE);
# Set up the entry box, if present
$self->setupEntry();
return 1;
}
sub openPaneWin {
# Called by the $self->openWin (only)
# Tries to open a task window as a pane object (GA::Table::Pane) inside the session's 'main'
# window (in response to 'pane' or 'entry' in $self->winPreferList)
#
# Expected arguments
lib/Games/Axmud/Generic.pm view on Meta::CPAN
{ package Games::Axmud::Generic::Win;
use strict;
use warnings;
# use diagnostics;
use Glib qw(TRUE FALSE);
our @ISA = qw(Games::Axmud);
##################
# Constructors
# sub new {} # Defined in window objects which inherit this one
##################
# Methods
# Standard window object functions
# sub winSetup {} # Defined in window objects which inherit this one
# sub winEnable {} # Defined in window objects which inherit this one
# sub winDisengage {} # Defined in window objects which inherit this one
# sub winDestroy {} # Defined in window objects which inherit this one
sub winShowAll {
# Generic function to update the window itself to make any changes visible
# If some code has called $self->setInvisible, then nothing happens (and the window
# remains invisible)
#
# Expected arguments
# (none besides $self)
#
# Optional arguments
# $string - For debugging purposes. Describes the calling function, e.g.
# ->winShowAll($self->_objClass . '->callingFunction');
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $string, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->winShowAll', @_);
}
if ($self->winWidget && $self->visibleFlag) {
$self->winWidget->show_all();
# Any textview objects (GA::Obj::TextView) which are waiting to update their size IVs
# can now do so
foreach my $textViewObj ($axmud::CLIENT->desktopObj->ivValues('textViewHash')) {
if ($textViewObj->sizeUpdateFlag && $textViewObj->winObj eq $self) {
$textViewObj->updateVisibleSize();
}
}
# Optionally, write information about the calling function to the terminal (for
# debugging)
# if ($string) {
#
# print "->winShowAll() call from " . $string . " at " . $axmud::CLIENT->getTime()
# . "\n";
#
# } else {
#
# print "->winShowAll() call from unspecified function at "
# . $axmud::CLIENT->getTime() . "\n";
# }
}
return 1;
}
sub drawWidgets {
# Generic function to draw widgets within the window, usually called by $self->winSetup or
# $self->winEnable
#
# 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 . '->drawWidgets', @_);
}
# (Do nothing)
return 1;
}
sub redrawWidgets {
# Generic function to redraw widgets within the window
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 on success
lib/Games/Axmud/Generic.pm view on Meta::CPAN
my ($self, $flag, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->resetUrgent', @_);
}
if (
$self->winWidget eq $self->winBox
&& (! $flag || $self->winWidget->get_urgency_hint())
) {
$self->winWidget->set_urgency_hint(FALSE);
# The line above doesn't work (in Linux Mint with Cinnamon), so we'll do it the brutal
# way, too
$self->restoreFocus();
if ($self->session) {
$self->session->mainWin->restoreFocus();
}
return 1;
} else {
# Hint not reset
return undef;
}
}
sub restoreFocus {
# Can be called by any function (often after creating a 'dialogue' window or after
# re-stacking 'grid' windows)
# Activates this window object's Gtk3::Window, if it is known. For 'internal' windows,
# returns the focus to the entry box in the 'Games::Axmud::Strip::Entry' strip object, if
# there is one
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or $self->winWidget is not set
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my $stripObj;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->restoreFocus', @_);
}
# Activate the Gtk3::Window, if it is known (for pseudo-windows, activate the parent window)
if ($self->winType eq 'external') {
# Activate the window
$axmud::CLIENT->desktopObj->wmCtrlObj->wmctrl(
'-a',
$self->internalID,
'-i',
);
} else {
if (! $self->winWidget) {
return undef;
} else {
$self->winWidget->present();
}
# For 'internal' windows, returns the focus to the entry box in the
# 'Games::Axmud::Strip::Entry' strip object, if there is one
if (
$self->winType eq 'main'
|| $self->winType eq 'protocol'
|| $self->winType eq 'custom'
) {
$stripObj = $self->ivShow('firstStripHash', 'Games::Axmud::Strip::Entry');
if ($stripObj) {
$stripObj->entry->grab_focus();
}
}
}
return 1;
}
sub setVisible {
# Can be called by any function
# Makes the Gtk3::Window itself visible, and sets a flag so that calls to $self->winShowAll
# are carried out
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or $self->winWidget is not set
# 1 otherwise
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->setVisible', @_);
}
if (! $self->winWidget) {
return undef;
} else {
lib/Games/Axmud/Generic.pm view on Meta::CPAN
# added to any registry (usually because the user needs to name it
# first). Set to FALSE (or 'undef') otherwise. Ignored if $editObj is
# not specified
# %configHash - Hash containing any number of key-value pairs needed for this
# particular 'free' 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
#
# Return values
# 'undef' on improper arguments or if the child 'free' window can't be created
# Otherwise returns the blessed reference to the child window
my ($self, $packageName, $owner, $session, $title, $editObj, $tempFlag, %configHash) = @_;
# Local variables
my ($pluginName, $pluginObj, $class, $winObj);
# Check for improper arguments
if (! defined $packageName) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->createFreeWin', @_);
}
# All windows except 'external' and 'dialogue' windows can have a child 'free' window
if ($self->winType eq 'external' || $self->winType eq 'dialogue') {
return undef;
}
# If the window package was added by a plugin and the plugin is disabled, don't create the
# window
$pluginName = $axmud::CLIENT->ivShow('pluginFreeWinHash', $packageName);
if ($pluginName) {
$pluginObj = $axmud::CLIENT->ivShow('pluginHash', $pluginName);
if ($pluginObj && ! $pluginObj->enabledFlag) {
return undef;
}
}
# If no owner is specified, it's this window
if (! $owner) {
$owner = $self;
# If an owner is specified, it must be a window object (inheriting from GA::Generic::Win)
} elsif (! $owner->isa('Games::Axmud::Generic::Win')) {
return undef;
}
# If no session is specified, it's the owner's session
if (! $session) {
$session = $owner->session;
}
# Create the 'free' window object
$winObj = $packageName->new(
$axmud::CLIENT->desktopObj->freeWinCount,
$self->workspaceObj,
$owner,
$session,
$title,
$editObj,
$tempFlag,
%configHash,
);
# Check it's any 'free' window besides a 'dialogue' window
if (! $winObj || $winObj->winCategory ne 'free' || $winObj->winType eq 'dialogue') {
return undef;
}
# Make the window visible
if (! $winObj->winSetup()) {
return undef;
}
if (! $winObj->winEnable()) {
return undef;
}
# Update IVs
$axmud::CLIENT->desktopObj->add_freeWin($winObj);
$self->add_childFreeWin($winObj);
return $winObj;
}
sub quickFreeWin {
# Shortcut to $self->createFreeWin, allowing the calling code to specify only the bare
# minimum of arguments
#
# Expected arguments
# $packageName - The Perl object for the child 'free' window
#
# Optional arguments
# $session - The GA::Session from which this function was called. If 'undef',
# the new window's ->session is the same as this window's session
# (which might be 'undef', too)
# %configHash - Hash containing any number of key-value pairs needed for this
# particular 'free' 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
#
# Return values
# 'undef' on improper arguments or if the child 'free' window can't be created
# Otherwise returns the blessed reference to the child window
my ($self, $packageName, $session, %configHash) = @_;
# Check for improper arguments
if (! defined $packageName) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->quickFreeWin', @_);
}
return $self->createFreeWin(
$packageName, # Compulsory
undef,
$session, # May be 'undef'
undef,
undef,
undef,
%configHash,
);
}
# 'dialogue' windows
sub closeDialogueWin {
# Can be called by anything to close a 'dialogue' window early (especially one that won't
# close itself)
# For example, called by GA::Client->start and GA::Session->setupProfiles after an earlier
# call to the 'dialogue' window created by $self->showBusyWin
#
# Expected arguments
# $dialogueWin - The 'dialogue' window to close
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
lib/Games/Axmud/Generic.pm view on Meta::CPAN
@argList, @list,
%buttonHash,
);
# Check for improper arguments
if (
! defined $title || ! defined $icon || ! defined $text || ! defined $buttonType
|| defined $check
) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->showMsgDialogue', @_);
}
# If an earlier call to $self->showBusyWin created a popup window, close it (otherwise it'll
# be visible above the new dialogue window)
if ($axmud::CLIENT->busyWin) {
$self->closeDialogueWin($axmud::CLIENT->busyWin);
}
# Set the correct spacing size for 'dialogue' windows
$spacing = $axmud::CLIENT->constFreeSpacingPixels;
# Check that $icon and $buttonType are valid values
if (
$icon ne 'info' && $icon ne 'warning' && $icon ne 'error' && $icon ne 'question'
) {
return $axmud::CLIENT->writeError(
'Unrecognised value \'' . $icon . '\' for icon argument',
$self->_objClass . '->showMsgDialogue',
);
}
# Convert $buttonType into an argument list
if ($buttonType eq 'ok') {
@argList = ('gtk-ok', 'ok');
} elsif ($buttonType eq 'close') {
@argList = ('gtk-close', 'close');
} elsif ($buttonType eq 'cancel') {
@argList = ('gtk-cancel', 'cancel');
} elsif ($buttonType eq 'yes-no') {
@argList = ('gtk-no', 'no', 'gtk-yes', 'yes');
} elsif ($buttonType eq 'ok-cancel') {
@argList = ('gtk-cancel', 'cancel', 'gtk-ok', 'ok');
} elsif ($buttonType ne 'none') {
return $axmud::CLIENT->writeError(
'Unrecognised value \'' . $icon . '\' for button type argument',
$self->_objClass . '->showMsgDialogue',
);
}
# Show the 'dialogue' window
my $dialogueWin = Gtk3::Dialog->new(
$title,
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
@argList,
);
$dialogueWin->set_position('center-always');
$dialogueWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
$dialogueWin->signal_connect('delete-event' => sub {
$dialogueWin->destroy();
$self->restoreFocus();
# (In case TTS is being used and another 'dialogue' window is about to open, make sure
# the window is visibly closed)
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->showMsgDialogue');
});
# Set the default response, if specified
if (defined $defaultResponse) {
$dialogueWin->set_default_response($defaultResponse);
}
# Add widgets to the 'dialogue' window
my $vBox = $dialogueWin->get_content_area();
# The call to ->addDialogueIcon splits $vBox in two, with an icon on the left, and a new
# Gtk3::VBox on the right, into which we put everything
my $vBox2 = $self->addDialogueIcon(
$vBox,
$axmud::SHARE_DIR . '/icons/replace/dialogue_replace_' . $icon . '.png',
TRUE, # Don't draw the image inside a frame
);
my $label = Gtk3::Label->new();
$vBox2->pack_start($label, FALSE, FALSE, $spacing);
$label->set_alignment(0, 0);
# If $text is long, it produces a wider window than was produced in earlier version of Gtk.
# This doesn't look very nice, so split $text into lines with a maximum length
# At the same time, we need to escape any < or > characters, or we'll get a Pango error)
if (! $noSplitFlag) {
$label->set_markup(
Glib::Markup::escape_text(
$axmud::CLIENT->splitText(
$text,
0, # No maximum rows
$axmud::CLIENT->constDialogueLabelSize,
# Maximum characters per line
FALSE, # No ellipsis required
TRUE, # Don't use hyphens when splitting words
)
),
);
} else {
# Calling function has already added newline characters, so no split required
$label->set_markup(Glib::Markup::escape_text($text));
}
# For the benefit of visually-impaired users who are using the 'tab' key to switch buttons,
# don't allow the label to receive focus
$label->set_can_focus(FALSE);
# Display the 'dialogue' window. Without this combination of Gtk calls, the window is not
# consistently active (don't know why this works; it just does)
$dialogueWin->show_all();
$dialogueWin->present();
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->showComboDialogue');
# Prepare text-to-speech (TTS) code. Get a hash of possible response buttons, in the form
# $buttonHash{'response'} = Gtk3::Button (if the button is used), or 'undef' (if not)
%buttonHash = (
'ok', $dialogueWin->get_widget_for_response('ok'),
'close', $dialogueWin->get_widget_for_response('close'),
'cancel', $dialogueWin->get_widget_for_response('cancel'),
'yes', $dialogueWin->get_widget_for_response('yes'),
'no', $dialogueWin->get_widget_for_response('no'),
);
if ($axmud::CLIENT->systemAllowTTSFlag && $axmud::CLIENT->ttsDialogueFlag) {
# Perform TTS for this window
$axmud::CLIENT->ttsAddUrgentJob($title, 'dialogue');
$axmud::CLIENT->ttsAddUrgentJob($text, 'dialogue');
foreach my $response (keys %buttonHash) {
my $button = $buttonHash{$response};
if (defined $button) {
# Handy list of responses that are available in this dialogue
push (@list, $response);
$button->signal_connect('grab-focus' => sub {
my $label = $button->get_label();
# $label is in the form 'gtk-yes', 'gtk-no' etc
$axmud::CLIENT->ttsAddUrgentJob(
substr($label, 4) . ' button',
'dialogue',
# Override other TTS urgent jobs, such as the $title and $text above
TRUE,
);
});
}
}
# (No need to read this message, if there's only one button)
if (@list == 1) {
$axmud::CLIENT->ttsAddUrgentJob(
$list[0] . ' button selected',
'dialogue',
);
} else {
$axmud::CLIENT->ttsAddUrgentJob(
'Select ' . join (', or, ', @list),
'dialogue',
);
}
}
# (end of TTS code)
# Get the response
$response = $dialogueWin->run();
if ($axmud::CLIENT->systemAllowTTSFlag && $axmud::CLIENT->ttsDialogueFlag) {
if ($response && exists $buttonHash{$response}) {
$axmud::CLIENT->ttsAddUrgentJob(
$response . ' selected',
'dialogue',
TRUE,
);
} else {
$axmud::CLIENT->ttsAddUrgentJob(
'Cancelled',
'dialogue',
TRUE,
);
}
}
# Destroy the window and return the response
$dialogueWin->destroy();
$self->restoreFocus();
# (In case TTS is being used and another 'dialogue' window is about to open, make sure the
# window is visibly closed)
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->showMsgDialogue');
return $response;
}
sub showFileChooser {
# Can be called by any function
# Creates a standard Gtk3::FileChooserDialog and returns the response (if any)
#
# Expected arguments
# $title - The title of the window, e.g. 'Select file to load'
# $type - 'open', 'save', 'select-folder', 'create-folder'
#
# Optional arguments
# $arg - If $type = 'open', set the current folder (this behaviour is
# discouraged, but it's sometimes appropriate for Axmud code). If
# $type = 'save', suggest a filename using $arg. Ignored if 'undef' or
# if $type is not 'open' or 'save'
#
# Return values
# 'undef' on improper arguments, if $type is invalid, if the file chooser window can't be
# opened or if no file is selected
# Otherwise returns a path to the selected file
my ($self, $title, $type, $arg, $check) = @_;
# Local variables
my $fileName;
# Check for improper arguments
if (! defined $title || ! defined $type || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->showFileChooser', @_);
}
# If an earlier call to $self->showBusyWin created a popup window, close it (otherwise it'll
# be visible above the new dialogue window)
if ($axmud::CLIENT->busyWin) {
$self->closeDialogueWin($axmud::CLIENT->busyWin);
}
# Check that $type is a valid type
if (
$type ne 'open' && $type ne 'save' && $type ne 'select-folder'
&& $type ne 'create-folder'
) {
return $self->writeError(
'Unrecognised file choose type \'' . $type . '\'',
$self->_objClass . '->showFileChooser',
);
}
# Open the file chooser window
my $dialogueWin = Gtk3::FileChooserDialog->new(
$title,
$self->winWidget,
$type,
'gtk-cancel' => 'cancel',
'gtk-ok' => 'ok'
);
if (! $dialogueWin) {
return undef;
}
$dialogueWin->set_position('center-always');
$dialogueWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
$dialogueWin->signal_connect('delete-event' => sub {
$dialogueWin->destroy();
$self->restoreFocus();
});
if (defined $arg) {
# If loading a file, set the current folder
if ($type eq 'open') {
$dialogueWin->set_current_folder($arg);
# If saving a file, suggest a filename
} elsif ($type eq 'save' && defined $arg) {
$dialogueWin->set_current_name($arg);
}
}
# Get the file
if ($dialogueWin->run eq 'ok') {
$fileName = $dialogueWin->get_filename();
}
# Close the window
$dialogueWin->destroy();
$self->restoreFocus();
# For saving, show a confirmation message
if (defined $fileName){
if (-f $fileName && $type eq 'save') {
my $choice = $self->showMsgDialogue(
'Replace existing file',
'question',
'Overwrite existing file ' . $fileName . ' ?',
'yes-no',
);
# If the user selects 'no', return false
if ($choice eq 'no') {
return undef;
}
}
# Return the path of the selected file
return $fileName;
} else {
# No file selected
return undef;
}
}
lib/Games/Axmud/Generic.pm view on Meta::CPAN
# $text is split into lines of no more than 40 characters
# $singleFlag - Set when called by GA::CLIENT->connectBlind (or by any other code that
# might want to remove the 'Cancel' button). If TRUE, only an 'OK'
# button is used. If FALSE (or 'undef'), both an 'OK' and 'Cancel'
# buttons are used
#
# Return values
# 'undef' on improper arguments or if the user doesn't enter some text
# Otherwise returns the user response (the contents of the entry box)
my (
$self, $title, $text, $maxChars, $entryText, $obscureModeFlag, $noSplitFlag,
$singleFlag, $check
) = @_;
# Local variables
my (
$spacing, $starText, $lastThing, $response, $responseText, $confirmMsg,
%buttonHash,
);
# Check for improper arguments
if (! defined $title || ! defined $text || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->showEntryDialogue', @_);
}
# If an earlier call to $self->showBusyWin created a popup window, close it (otherwise it'll
# be visible above the new dialogue window)
if ($axmud::CLIENT->busyWin) {
$self->closeDialogueWin($axmud::CLIENT->busyWin);
}
# Set the correct spacing size for 'dialogue' windows
$spacing = $axmud::CLIENT->constFreeSpacingPixels;
# Show the dialogue window
my $dialogueWin;
if ($singleFlag) {
$dialogueWin = Gtk3::Dialog->new(
$title,
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
'gtk-ok' => 'accept',
);
} else {
$dialogueWin = Gtk3::Dialog->new(
$title,
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
'gtk-cancel' => 'reject',
'gtk-ok' => 'accept',
);
}
$dialogueWin->set_position('center-always');
$dialogueWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
$dialogueWin->signal_connect('delete-event' => sub {
$dialogueWin->destroy();
$self->restoreFocus();
# (In case TTS is being used and another 'dialogue' window is about to open, make sure
# the window is visibly closed)
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->showEntryDialogue');
});
# Add widgets to the 'dialogue' window
my $vBox = $dialogueWin->get_content_area();
# The call to ->addDialogueIcon splits $vBox in two, with an icon on the left, and a new
# Gtk3::VBox on the right, into which we put everything
my $vBox2 = $self->addDialogueIcon($vBox);
my $label = Gtk3::Label->new();
$vBox2->pack_start($label, FALSE, FALSE, $spacing);
$label->set_alignment(0, 0);
if (! $noSplitFlag) {
$label->set_markup(
Glib::Markup::escape_text(
$axmud::CLIENT->splitText(
$text,
0, # No maximum rows
$axmud::CLIENT->constDialogueLabelSize,
# Maximum characters per line
FALSE, # No ellipsis required
TRUE, # Don't use hyphens when splitting words
)
),
);
} else {
$label->set_markup(Glib::Markup::escape_text($text));
}
my $entry = Gtk3::Entry->new();
$vBox2->pack_start($entry, FALSE, FALSE, $spacing);
if (defined $maxChars && $axmud::CLIENT->intCheck($maxChars, 1)) {
$entry->set_max_length($maxChars);
}
if ($obscureModeFlag) {
$entry->set_visibility(FALSE);
if ($entryText) {
# Set the string to be used to disguise the number of characters in $entryText
$starText = '********';
# Just in case $entryText happens to be the same string, use a different string!
if ($entryText eq $starText) {
$starText = 'xxxxxxxx';
}
$entry->set_text($starText);
} else {
# (Don't hide the fact that $entryText is an empty string, if it is so)
$starText = '';
}
} elsif ($entryText) {
# $obscureModeFlag is not set, so display $entryText
$entry->set_text($entryText);
}
$entry->signal_connect('button_press_event' => sub {
# In obscure mode, user can change the entry box's text in two ways - clicking on the
# box itself, in which case this event occurs (and we need to empty the box), or by
# tabbing focus through widgets, until the focus falls onto the box, in which case
# the box is emptied and replaced with the first keypress
if ($obscureModeFlag && defined $starText) {
$entry->set_text('');
# When this function returns a value (below), we need to know whether the
# obscured text has been modified. Only need to do this once
$starText = undef;
}
});
$entry->signal_connect('changed' => sub {
# If the text in the entry box has been modified, then we reset $starText (for the
# reasons described just above)
$starText = undef;
});
$entry->signal_connect('activate' => sub {
# Get the entry's text, because the code at the bottom of this function won't be
# able to retrieve it...
$responseText = $entry->get_text();
# ...after we destroy the 'dialogue' window
$dialogueWin->destroy();
$self->restoreFocus();
});
# Display the 'dialogue' window. Without this combination of Gtk calls, the window is not
# consistently active (don't know why this works; it just does)
$dialogueWin->show_all();
$dialogueWin->present();
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->showEntryDialogue');
# Prepare text-to-speech (TTS) code. Get a hash of the response buttons, in the form
# $buttonHash{'response'} = Gtk3::Button
$buttonHash{'ok'} = $dialogueWin->get_widget_for_response('accept');
if (! $singleFlag) {
$buttonHash{'cancel'} = $dialogueWin->get_widget_for_response('reject');
}
if ($axmud::CLIENT->systemAllowTTSFlag && $axmud::CLIENT->ttsDialogueFlag) {
# Perform TTS for this window
$axmud::CLIENT->ttsAddUrgentJob($title, 'dialogue');
$axmud::CLIENT->ttsAddUrgentJob($text, 'dialogue');
# Read out buttons, when in focus
foreach my $response (keys %buttonHash) {
my $button = $buttonHash{$response};
$button->signal_connect('grab-focus' => sub {
my $label = $button->get_label();
if (! defined $lastThing || $lastThing ne $button) {
$axmud::CLIENT->ttsAddUrgentJob(
# ($label is in the form 'gtk-yes', 'gtk-no' etc)
substr($label, 4) . ' button',
'dialogue',
# Override other TTS urgent jobs, such as the $title and $text above
TRUE,
);
}
# Don't use TTS to read out the same widget consecutively
$lastThing = $button;
});
}
$entry->signal_connect('grab-focus' => sub {
# (Don't read anything out the first time, but if the user cycles through the keys
# and returns to the entry, using the tab key, read out something)
if ($lastThing) {
if (! $entry->get_text()) {
$axmud::CLIENT->ttsAddUrgentJob(
'Type something here',
'dialogue',
TRUE,
);
} else {
$axmud::CLIENT->ttsAddUrgentJob(
'Entered: ' . $entry->get_text(),
'dialogue',
TRUE,
);
}
}
# Don't use TTS to read out the same widget consecutively
$lastThing = $entry;
});
}
# Get the response
$response = $dialogueWin->run();
if ($response eq 'accept' || $response eq 'none') {
# If the user pressed the ENTER key, the entry's ->signal_connect for 'activate' stored
# the entry's text in $responseText, before destroying the window
if (! $responseText) {
$responseText = $entry->get_text();
}
if ($axmud::CLIENT->systemAllowTTSFlag && $axmud::CLIENT->ttsDialogueFlag) {
if ($obscureModeFlag) {
$axmud::CLIENT->ttsAddUrgentJob(
'Text accepted',
'dialogue',
TRUE,
);
} else {
$axmud::CLIENT->ttsAddUrgentJob(
'Entered: ' . $responseText,
'dialogue',
TRUE,
);
}
}
} else {
if ($axmud::CLIENT->systemAllowTTSFlag && $axmud::CLIENT->ttsDialogueFlag) {
$axmud::CLIENT->ttsAddUrgentJob('Cancelled', 'dialogue', TRUE);
}
}
# Destroy the window
$dialogueWin->destroy();
$self->restoreFocus();
# (In case TTS is being used and another 'dialogue' window is about to open, make sure the
# window is visibly closed)
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->showEntryDialogue');
# Return the response
if ($obscureModeFlag && defined $starText) {
# The obscured '********' text has not been modified, so we can return the original
# unmodified $entryText
return $entryText;
} else {
# Otherwise, return the contents of the entry box
return $responseText;
}
}
sub showDoubleEntryDialogue {
# Can be called by any function
# Similar to $self->showEntryDialogue, but contains two entry boxes; returns the contents of
# both boxes
#
# Expected arguments
# $title - The title to display, e.g. 'File Save'
# $labelText - The label above the first entry box. Can be pango markup text, or just
# plain text
#
# Optional arguments
# $labelText2 - The label above the second entry box. If 'undef', no second label is
# used (but the second entry box is still used)
# $maxChars - The maximum number of chars allowed in both entry boxes (if 'undef',
# no maximum)
# $obscureMode - Sets which of the entry boxes has its text obscured
# - 'default' (or 'undef') - no text is obscured
# - 'first' - first box is obscured
# - 'second' - second box is obscured
# - 'both' - both boxes are obscured
# $noSplitFlag - If TRUE, the message $text is not automatically split into shorter
# lines (because the calling function has already added newline
# characters as it requires). If FALSE (or 'undef'), the message
# $text is split into lines of no more than 40 characters
#
# Return values
# An empty list on improper arguments or if the user doesn't enter some text in either
# entry box
# Otherwise a list of two elements, containing the text in both entry boxes
my (
$self, $title, $labelText, $labelText2, $maxChars, $obscureMode, $noSplitFlag, $check
) = @_;
# Local variables
my (
$spacing, $response, $responseText, $responseText2,
@emptyList,
);
# If an earlier call to $self->showBusyWin created a popup window, close it (otherwise it'll
# be visible above the new dialogue window)
if ($axmud::CLIENT->busyWin) {
$self->closeDialogueWin($axmud::CLIENT->busyWin);
}
# Set the correct spacing size for 'dialogue' windows
$spacing = $axmud::CLIENT->constFreeSpacingPixels;
# Check for improper arguments
if (! defined $title || ! defined $labelText || defined $check) {
$axmud::CLIENT->writeImproper($self->_objClass . '->showDoubleEntryDialogue', @_);
return @emptyList;
}
# Show the 'dialogue' window
my $dialogueWin = Gtk3::Dialog->new(
$title,
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
'gtk-cancel' => 'reject',
'gtk-ok' => 'accept',
);
$dialogueWin->set_position('center-always');
$dialogueWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
$dialogueWin->signal_connect('delete-event' => sub {
$dialogueWin->destroy();
$self->restoreFocus();
return @emptyList;
});
# Add widgets to the 'dialogue' window
my $vBox = $dialogueWin->get_content_area();
# The call to ->addDialogueIcon splits $vBox in two, with an icon on the left, and a new
# Gtk3::VBox on the right, into which we put everything
my $vBox2 = $self->addDialogueIcon($vBox);
# First label and entry
my $label = Gtk3::Label->new();
$vBox2->pack_start($label, FALSE, FALSE, $spacing);
$label->set_alignment(0, 0);
if (! $noSplitFlag) {
$label->set_markup(
Glib::Markup::escape_text(
$axmud::CLIENT->splitText(
$labelText,
0, # No maximum rows
$axmud::CLIENT->constDialogueLabelSize,
# Maximum characters per line
FALSE, # No ellipsis required
TRUE, # Don't use hyphens when splitting words
)
),
);
} else {
$label->set_markup(Glib::Markup::escape_text($labelText));
}
my $entry = Gtk3::Entry->new();
$vBox2->pack_start($entry, FALSE, FALSE, $spacing);
if (defined $maxChars && $axmud::CLIENT->intCheck($maxChars, 1)) {
$entry->set_max_length($maxChars);
}
# Second label and entry
if ($labelText2) {
my $label2 = Gtk3::Label->new();
$vBox2->pack_start($label2, FALSE, FALSE, $spacing);
$label2->set_alignment(0, 0);
if (! $noSplitFlag) {
$label2->set_markup(
Glib::Markup::escape_text(
$axmud::CLIENT->splitText(
$labelText2,
0, # No maximum rows
$axmud::CLIENT->constDialogueLabelSize,
# Maximum characters per line
FALSE, # No ellipsis required
TRUE, # Don't use hyphens when splitting words
)
),
);
} else {
$label2->set_markup(Glib::Markup::escape_text($labelText2));
}
}
my $entry2 = Gtk3::Entry->new();
$vBox2->pack_start($entry2, FALSE, FALSE, $spacing);
if (defined $maxChars && $axmud::CLIENT->intCheck($maxChars, 1)) {
$entry2->set_max_length($maxChars);
}
# Obscure text in the entry boxes, if necessary
if ($obscureMode && $obscureMode ne 'default') {
if ($obscureMode eq 'first' || $obscureMode eq 'both') {
$entry->set_visibility(FALSE);
}
if ($obscureMode eq 'second' || $obscureMode eq 'both') {
$entry2->set_visibility(FALSE);
}
}
# Display the 'dialogue' window. Without this combination of Gtk calls, the window is not
# consistently active (don't know why this works; it just does)
$dialogueWin->show_all();
$dialogueWin->present();
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->showDoubleEntryDialogue');
# Get the response. If the user clicked 'cancel', $response will be 'reject'
# Otherwise, user clicked 'ok', and we need to get the contents of the two boxes
$response = $dialogueWin->run();
if ($response eq 'accept') {
$responseText = $entry->get_text();
$responseText2 = $entry2->get_text();
# Destroy the window
$dialogueWin->destroy();
$self->restoreFocus();
# Return the response
return ($responseText, $responseText2);
} else {
# Destroy the window
$dialogueWin->destroy();
$self->restoreFocus();
# Return the response
return @emptyList;
}
}
sub showTripleEntryDialogue {
# Can be called by any function
# Similar to $self->showEntryDialogue, but contains three entry boxes; returns the contents
# of all three boxes
#
# Expected arguments
# $title - The title to display, e.g. 'File Save'
# $labelText - The label above the first entry box. Can be pango markup text, or just
# plain text
#
# Optional arguments
# $labelText2 - The label above the second entry box. If 'undef', no second label is
# used (but the second entry box is still used)
# $labelText3 - The label above the third entry box. If 'undef', no third label is
# used (but the third entry box is still used)
# $maxChars - The maximum number of chars allowed in all entry boxes (if 'undef',
# no maximum)
# $obscureMode - Sets which of the entry boxes has its text obscured
# - 0 (or 'undef') - no text is obscured (000)
# - 1 - first box is obscured (001)
# - 2 - second box is obscured (010)
# - 3 - first/second boxes are obscured (011)
# - 4 - third box is obscured (100)
# - 5 - first/third boxes are obscured (101)
# - 6 - second/third boxes are obscured (110)
# - 7 - all boxes are obscured (111)
# $noSplitFlag - If TRUE, the message $text is not automatically split into shorter
# lines (because the calling function has already added newline
# characters as it requires). If FALSE (or 'undef'), the message
# $text is split into lines of no more than 40 characters
#
# Return values
# An empty list on improper arguments or if the user doesn't enter some text in either
# entry box
# Otherwise a list of three elements, containing the text in both entry boxes
my (
$self, $title, $labelText, $labelText2, $labelText3, $maxChars, $obscureMode,
$noSplitFlag, $check,
) = @_;
# Local variables
my (
$spacing, $response, $responseText, $responseText2, $responseText3,
@emptyList,
);
# Check for improper arguments
if (! defined $title || ! defined $labelText || defined $check) {
$axmud::CLIENT->writeImproper($self->_objClass . '->showTripleEntryDialogue', @_);
return @emptyList;
}
# If an earlier call to $self->showBusyWin created a popup window, close it (otherwise it'll
# be visible above the new dialogue window)
if ($axmud::CLIENT->busyWin) {
$self->closeDialogueWin($axmud::CLIENT->busyWin);
}
# Set the correct spacing size for 'dialogue' windows
$spacing = $axmud::CLIENT->constFreeSpacingPixels;
# Show the 'dialogue' window
my $dialogueWin = Gtk3::Dialog->new(
$title,
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
'gtk-cancel' => 'reject',
'gtk-ok' => 'accept',
);
$dialogueWin->set_position('center-always');
$dialogueWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
$dialogueWin->signal_connect('delete-event' => sub {
$dialogueWin->destroy();
$self->restoreFocus();
return @emptyList;
});
# Add widgets to the 'dialogue' window
my $vBox = $dialogueWin->get_content_area();
# The call to ->addDialogueIcon splits $vBox in two, with an icon on the left, and a new
# Gtk3::VBox on the right, into which we put everything
my $vBox2 = $self->addDialogueIcon($vBox);
# First label and entry
my $label = Gtk3::Label->new();
$vBox2->pack_start($label, FALSE, FALSE, $spacing);
$label->set_alignment(0, 0);
if (! $noSplitFlag) {
$label->set_markup(
Glib::Markup::escape_text(
$axmud::CLIENT->splitText(
$labelText,
0, # No maximum rows
$axmud::CLIENT->constDialogueLabelSize,
# Maximum characters per line
FALSE, # No ellipsis required
TRUE, # Don't use hyphens when splitting words
)
),
);
} else {
$label->set_markup(Glib::Markup::escape_text($labelText));
}
my $entry = Gtk3::Entry->new();
$vBox2->pack_start($entry, FALSE, FALSE, $spacing);
if (defined $maxChars && $axmud::CLIENT->intCheck($maxChars, 1)) {
$entry->set_max_length($maxChars);
}
# Second label and entry
if ($labelText2) {
my $label2 = Gtk3::Label->new();
$vBox2->pack_start($label2, FALSE, FALSE, $spacing);
$label2->set_alignment(0, 0);
if (! $noSplitFlag) {
$label2->set_markup(
Glib::Markup::escape_text(
$axmud::CLIENT->splitText(
$labelText2,
0, # No maximum rows
lib/Games/Axmud/Generic.pm view on Meta::CPAN
}
# Third label and entry
if ($labelText3) {
my $label3 = Gtk3::Label->new();
$vBox2->pack_start($label3, FALSE, FALSE, $spacing);
$label3->set_alignment(0, 0);
if (! $noSplitFlag) {
$label3->set_markup(
Glib::Markup::escape_text(
$axmud::CLIENT->splitText(
$labelText3,
0, # No maximum rows
$axmud::CLIENT->constDialogueLabelSize,
# Maximum characters per line
FALSE, # No ellipsis required
TRUE, # Don't use hyphens when splitting words
)
),
);
} else {
$label3->set_markup(Glib::Markup::escape_text($labelText3));
}
}
my $entry3 = Gtk3::Entry->new();
$vBox2->pack_start($entry3, FALSE, FALSE, $spacing);
if (defined $maxChars && $axmud::CLIENT->intCheck($maxChars, 1)) {
$entry3->set_max_length($maxChars);
}
# Obscure text in the entry boxes, if necessary
if ($obscureMode) {
if ($obscureMode == 1 || $obscureMode == 3 || $obscureMode == 5 || $obscureMode == 7) {
$entry->set_visibility(FALSE);
}
if ($obscureMode == 2 || $obscureMode == 3 || $obscureMode >= 6) {
$entry2->set_visibility(FALSE);
}
if ($obscureMode >= 4) {
$entry3->set_visibility(FALSE);
}
}
# Display the 'dialogue' window. Without this combination of Gtk calls, the window is not
# consistently active (don't know why this works; it just does)
$dialogueWin->show_all();
$dialogueWin->present();
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->showTripleComboDialogue');
# Get the responses. If the user clicked 'cancel', $response will be 'reject'
# Otherwise, user clicked 'ok', and we need to get the contents of the two boxes
$response = $dialogueWin->run();
if ($response eq 'accept') {
$responseText = $entry->get_text();
$responseText2 = $entry2->get_text();
$responseText3 = $entry3->get_text();
# Destroy the window
$dialogueWin->destroy();
$self->restoreFocus();
# Return the response
return ($responseText, $responseText2, $responseText3);
} else {
# Destroy the window
$dialogueWin->destroy();
$self->restoreFocus();
# Return the response
return @emptyList;
}
}
sub showComboDialogue {
# Can be called by any function
# Shows a short message in a 'dialogue' window with the buttons 'ok' and 'cancel'
# Prompts the user to choose a line from a combobox; returns the chosen line if the 'ok'
# button is pressed, but 'undef' if either the cancel button is pressed or the window is
# closed
#
# Expected arguments
# $title - The title to display, e.g. 'File Save'
# $text - The message to display. Can be pango markup text, or just plain text
#
# Optional arguments
# $listRef - Reference to a list of scalars to be used in the combo box. If
# 'undef', the combo box will be empty
# $singleFlag - Set when called by GA::CLIENT->connectBlind (or by any other code that
# might want to remove the 'Cancel' button). If TRUE, only an 'OK'
# button is used. If FALSE (or 'undef'), both an 'OK' and 'Cancel'
# buttons are used
# $noSplitFlag - If TRUE, the message $text is not automatically split into shorter
# lines (because the calling function has already added newline
# characters as it requires). If FALSE (or 'undef'), the message
# $text is split into lines of no more than 40 characters
#
# Return values
# 'undef' on improper arguments, if the user doesn't choose a line or if @lineList is
# empty
# Otherwise returns the user response (the text of the selected line)
my ($self, $title, $text, $listRef, $singleFlag, $noSplitFlag, $check) = @_;
# Local variables
my (
$spacing, $lastThing, $response, $responseText,
%buttonHash,
);
# Check for improper arguments
if (! defined $title || ! defined $text || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->showComboDialogue', @_);
}
# If an earlier call to $self->showBusyWin created a popup window, close it (otherwise it'll
# be visible above the new dialogue window)
if ($axmud::CLIENT->busyWin) {
$self->closeDialogueWin($axmud::CLIENT->busyWin);
}
# Set the correct spacing size for 'dialogue' windows
$spacing = $axmud::CLIENT->constFreeSpacingPixels;
# If $listRef was not specified, use an empty list
if (! defined $listRef) {
@$listRef = ();
}
# Show the 'dialogue' window. If $listRef is empty, don't show a 'cancel' button
my $dialogueWin;
if (! @$listRef || $singleFlag) {
$dialogueWin = Gtk3::Dialog->new(
$title,
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
'gtk-ok' => 'accept',
);
} else {
$dialogueWin = Gtk3::Dialog->new(
$title,
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
'gtk-cancel' => 'reject',
'gtk-ok' => 'accept',
);
}
$dialogueWin->set_position('center-always');
$dialogueWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
$dialogueWin->signal_connect('delete-event' => sub {
$dialogueWin->destroy();
$self->restoreFocus();
# (In case TTS is being used and another 'dialogue' window is about to open, make sure
# the window is visibly closed)
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->showComboDialogue');
});
# Add widgets to the 'dialogue' window
my $vBox = $dialogueWin->get_content_area();
# The call to ->addDialogueIcon splits $vBox in two, with an icon on the left, and a new
# Gtk3::VBox on the right, into which we put everything
my $vBox2 = $self->addDialogueIcon($vBox);
my $label = Gtk3::Label->new();
$vBox2->pack_start($label, FALSE, FALSE, $spacing);
$label->set_alignment(0, 0);
if (! $noSplitFlag) {
$label->set_markup(
Glib::Markup::escape_text(
$axmud::CLIENT->splitText(
$text,
0, # No maximum rows
$axmud::CLIENT->constDialogueLabelSize,
# Maximum characters per line
FALSE, # No ellipsis required
TRUE, # Don't use hyphens when splitting words
)
),
);
} else {
$label->set_markup(Glib::Markup::escape_text($text));
}
my $comboBox = Gtk3::ComboBoxText->new();
$vBox2->pack_start($comboBox, FALSE, FALSE, $spacing);
# Fill the combobox with the specified lines, and display the first line
foreach my $line (@$listRef) {
$comboBox->append_text($line);
}
$comboBox->set_active(0);
# Display the 'dialogue' window. Without this combination of Gtk calls, the window is not
# consistently active (don't know why this works; it just does)
$dialogueWin->show_all();
$dialogueWin->present();
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->showComboDialogue');
# Prepare text-to-speech (TTS) code. Get a hash of the response buttons, in the form
# $buttonHash{'response'} = Gtk3::Button
$buttonHash{'ok'} = $dialogueWin->get_widget_for_response('accept');
if (@$listRef && ! $singleFlag) {
$buttonHash{'cancel'} = $dialogueWin->get_widget_for_response('reject');
}
if ($axmud::CLIENT->systemAllowTTSFlag && $axmud::CLIENT->ttsDialogueFlag) {
# Perform TTS for this window
$axmud::CLIENT->ttsAddUrgentJob($title, 'dialogue');
$axmud::CLIENT->ttsAddUrgentJob($text, 'dialogue');
# Read out buttons, when in focus
foreach my $response (keys %buttonHash) {
my $button = $buttonHash{$response};
$button->signal_connect('grab-focus' => sub {
my $label = $button->get_label();
if (! defined $lastThing || $lastThing ne $button) {
$axmud::CLIENT->ttsAddUrgentJob(
# ($label is in the form 'gtk-yes', 'gtk-no' etc)
substr($label, 4) . ' button',
'dialogue',
# Override other TTS urgent jobs, such as the $title and $text above
TRUE,
);
}
# Don't use TTS to read out the same button label consecutively
$lastThing = $button;
});
}
# Intercept page up/page down, and make it skip 10 lines, rather than going to the
# top/bottom
$comboBox->signal_connect('key-press-event' => sub {
my ($widget, $event) = @_;
# Local variables
my ($keycode, $standard, $index);
# Get the system keycode for this keypress
$keycode = Gtk3::Gdk::keyval_name($event->keyval);
# Translate it into a standard Axmud keycode
$standard = $axmud::CLIENT->reverseKeycode($keycode);
if ($standard eq 'page_up' || $standard eq 'page_down') {
$index = $comboBox->get_active();
if ($index > -1) {
if ($standard eq 'page_up') {
lib/Games/Axmud/Generic.pm view on Meta::CPAN
$lastThing = $text;
return undef;
});
# Make sure that the first item in the combobox has been read out
if (! defined $lastThing || (@$listRef && $lastThing ne $$listRef[0])) {
if (@$listRef) {
$axmud::CLIENT->ttsAddUrgentJob(
$$listRef[0] . ' selected',
'dialogue',
);
} else {
$axmud::CLIENT->ttsAddUrgentJob(
'There is nothing to select',
'dialogue',
);
}
}
# Don't use TTS to read out the same combo item consecutively
if (@$listRef) {
$lastThing = $$listRef[0];
}
}
# Get the response
$response = $dialogueWin->run();
if ($response eq 'accept') {
$responseText = $comboBox->get_active_text();
if ($axmud::CLIENT->systemAllowTTSFlag && $axmud::CLIENT->ttsDialogueFlag) {
$axmud::CLIENT->ttsAddUrgentJob(
$responseText . ' entered',
'dialogue',
TRUE,
);
}
} else {
if ($axmud::CLIENT->systemAllowTTSFlag && $axmud::CLIENT->ttsDialogueFlag) {
$axmud::CLIENT->ttsAddUrgentJob('Cancelled', 'dialogue', TRUE);
}
}
# Destroy the window
$dialogueWin->destroy();
$self->restoreFocus();
# (In case TTS is being used and another 'dialogue' window is about to open, make sure the
# window is visibly closed)
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->showComboDialogue');
return $responseText;
}
sub showDoubleComboDialogue {
# Can be called by any function
# Similar to $self->showDoubleEntryDialogue, but contains two combo boxes; returns the
# contents of both boxes
#
# Expected arguments
# $title - The title to display, e.g. 'File Save'
#
# Optional arguments
# $labelText - The label above the first combo box. Can be pango markup text, or just
# plain text. If 'undef', no first label is used (but the combo box is
# still used)
# $labelText2 - The label above the second combo box. If 'undef', no second label is
# used (but the combo box is still used)
# $listRef - Reference to a list of scalars to be used in the first combo box. If
# 'undef', the first combo box will be empty
# $listRef2 - Reference to a list of scalars to be used in the second combo box. If
# 'undef', the second combo box will be empty
# $noSplitFlag - If TRUE, the message $text is not automatically split into shorter
# lines (because the calling function has already added newline
# characters as it requires). If FALSE (or 'undef'), the message
# $text is split into lines of no more than 40 characters
#
# Return values
# An empty list on improper arguments
# Otherwise a list of two elements, containing the contents of the two combo boxes
my ($self, $title, $labelText, $labelText2, $listRef, $listRef2, $noSplitFlag, $check) = @_;
# Local variables
my (
$spacing, $response, $responseText, $responseText2,
@emptyList,
);
# Check for improper arguments
if (! defined $title || defined $check) {
$axmud::CLIENT->writeImproper($self->_objClass . '->showDoubleComboDialogue', @_);
return @emptyList;
}
# If an earlier call to $self->showBusyWin created a popup window, close it (otherwise it'll
# be visible above the new dialogue window)
if ($axmud::CLIENT->busyWin) {
$self->closeDialogueWin($axmud::CLIENT->busyWin);
}
# Set the correct spacing size for 'dialogue' windows
$spacing = $axmud::CLIENT->constFreeSpacingPixels;
# If $listRef/$listRef2 were not specified, use empty lists
if (! defined $listRef) {
@$listRef = ();
}
if (! defined $listRef2) {
@$listRef2 = ();
}
# Show the 'dialogue' window
my $dialogueWin = Gtk3::Dialog->new(
$title,
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
'gtk-cancel' => 'reject',
'gtk-ok' => 'accept',
);
$dialogueWin->set_position('center-always');
$dialogueWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
$dialogueWin->signal_connect('delete-event' => sub {
$dialogueWin->destroy();
$self->restoreFocus();
return @emptyList;
});
# Add widgets to the 'dialogue' window
my $vBox = $dialogueWin->get_content_area();
# The call to ->addDialogueIcon splits $vBox in two, with an icon on the left, and a new
# Gtk3::VBox on the right, into which we put everything
my $vBox2 = $self->addDialogueIcon($vBox);
# First label (optional) and combo (not optional)
my $label;
if ($labelText) {
$label = Gtk3::Label->new();
$label->set_alignment(0, 0);
if (! $noSplitFlag) {
$label->set_markup(
Glib::Markup::escape_text(
$axmud::CLIENT->splitText(
$labelText,
0, # No maximum rows
$axmud::CLIENT->constDialogueLabelSize,
# Maximum characters per line
FALSE, # No ellipsis required
TRUE, # Don't use hyphens when splitting words
)
),
);
} else {
$label->set_markup(Glib::Markup::escape_text($labelText));
}
$vBox2->pack_start($label, FALSE, FALSE, $spacing);
}
my $combo = Gtk3::ComboBoxText->new();
$vBox2->pack_start($combo, FALSE, FALSE, $spacing);
# Fill the combo box with the specified lines, and display the first line
if (@$listRef) {
foreach my $line (@$listRef) {
$combo->append_text($line);
}
$combo->set_active(0);
}
# Second label (optional) and combo (not optional)
lib/Games/Axmud/Generic.pm view on Meta::CPAN
# 'undef'), shows an entry above a combo box
# $quickFlag - If set to TRUE, pressing the ENTER key while the cursor is in the
# entry box closes the window; FALSE or 'undef' if the user must
# actually click the 'OK' or 'Cancel' buttons
# buttons are used
# $noSplitFlag - If TRUE, the message $text is not automatically split into shorter
# lines (because the calling function has already added newline
# characters as it requires). If FALSE (or 'undef'), the message
# $text is split into lines of no more than 40 characters
#
# Return values
# An empty list on improper arguments or if the user doesn't enter some text in the entry
# box
# Otherwise a list of two elements, containing the contents of the entry box and the
# active contents of the combo box
my (
$self, $title, $labelText, $labelText2, $listRef, $maxChars, $reverseFlag, $quickFlag,
$noSplitFlag, $check,
) = @_;
# Local variables
my (
$spacing, $response, $responseText, $responseText2,
@emptyList,
);
# Check for improper arguments
if (! defined $title || defined $check) {
$axmud::CLIENT->writeImproper($self->_objClass . '->showEntryComboDialogue', @_);
return @emptyList;
}
# If an earlier call to $self->showBusyWin created a popup window, close it (otherwise it'll
# be visible above the new dialogue window)
if ($axmud::CLIENT->busyWin) {
$self->closeDialogueWin($axmud::CLIENT->busyWin);
}
# Set the correct spacing size for 'dialogue' windows
$spacing = $axmud::CLIENT->constFreeSpacingPixels;
# If $listRef was not specified, use an empty list
if (! defined $listRef) {
@$listRef = ();
}
# Show the 'dialogue' window
my $dialogueWin = Gtk3::Dialog->new(
$title,
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
'gtk-cancel' => 'reject',
'gtk-ok' => 'accept',
);
$dialogueWin->set_position('center-always');
$dialogueWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
$dialogueWin->signal_connect('delete-event' => sub {
$dialogueWin->destroy();
$self->restoreFocus();
return @emptyList;
});
# Add widgets to the 'dialogue' window
my $vBox = $dialogueWin->get_content_area();
# The call to ->addDialogueIcon splits $vBox in two, with an icon on the left, and a new
# Gtk3::VBox on the right, into which we put everything
my $vBox2 = $self->addDialogueIcon($vBox);
# First label (optional) and entry (not optional)
my $label;
if ($labelText) {
$label = Gtk3::Label->new();
$label->set_alignment(0, 0);
if (! $noSplitFlag) {
$label->set_markup(
Glib::Markup::escape_text(
$axmud::CLIENT->splitText(
$labelText,
0, # No maximum rows
$axmud::CLIENT->constDialogueLabelSize,
# Maximum characters per line
FALSE, # No ellipsis required
TRUE, # Don't use hyphens when splitting words
)
),
);
} else {
$label->set_markup(Glib::Markup::escape_text($labelText));
}
}
my $entry = Gtk3::Entry->new();
if (defined $maxChars && $axmud::CLIENT->intCheck($maxChars, 1)) {
$entry->set_max_length($maxChars);
}
# Second label (optional) and combo (not optional)
my $label2;
if ($labelText2) {
$label2 = Gtk3::Label->new();
$label2->set_alignment(0, 0);
if (! $noSplitFlag) {
$label2->set_markup(
lib/Games/Axmud/Generic.pm view on Meta::CPAN
if (@$listRef) {
foreach my $line (@$listRef) {
$combo->append_text($line);
}
$combo->set_active(0);
}
# Arrange the entry and combo in the specified order
if (! $reverseFlag) {
if ($labelText) {
$vBox2->pack_start($label, FALSE, FALSE, $spacing);
}
$vBox2->pack_start($entry, FALSE, FALSE, $spacing);
if ($labelText2) {
$vBox2->pack_start($label2, FALSE, FALSE, $spacing);
}
$vBox2->pack_start($combo, FALSE, FALSE, $spacing);
} else {
if ($labelText2) {
$vBox2->pack_start($label2, FALSE, FALSE, $spacing);
}
$vBox2->pack_start($combo, FALSE, FALSE, $spacing);
if ($labelText) {
$vBox2->pack_start($label, FALSE, FALSE, $spacing);
}
$vBox2->pack_start($entry, FALSE, FALSE, $spacing);
}
if ($quickFlag) {
$entry->signal_connect('activate' => sub {
$responseText = $entry->get_text();
$responseText2 = $combo->get_active_text();
# Destroy the window
$dialogueWin->destroy();
});
}
# Display the 'dialogue' window. Without this combination of Gtk calls, the window is not
# consistently active (don't know why this works; it just does)
$dialogueWin->show_all();
$dialogueWin->present();
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->showEntryComboDialogue');
# Get the response. If the user clicked 'cancel', $response will be 'reject'
# Otherwise, user clicked 'ok', and we need to get the contents of the two boxes
$response = $dialogueWin->run();
if (defined $responseText) {
# (User pressed their ENTER key when $quickFlag is TRUE)
# Destroy the window
$dialogueWin->destroy();
$self->restoreFocus();
# Return the response
return ($responseText, $responseText2);
} elsif ($response eq 'accept' || defined $responseText) {
$responseText = $entry->get_text();
$responseText2 = $combo->get_active_text();
# Destroy the window
$dialogueWin->destroy();
$self->restoreFocus();
# Return the response
return ($responseText, $responseText2);
} else {
# Destroy the window
$dialogueWin->destroy();
$self->restoreFocus();
# Return the response
return @emptyList;
}
}
sub showColourSelectionDialogue {
# Can be called by any function
# Creates a standard Gtk3::ColorSelectionDialog and returns the response (if any)
#
# Expected arguments
# $title - The title to display, e.g. 'Select colour'
#
# Optional arguments
# $initialColour - The initial colour to use, in the form '#FFFFFF'. If not specified,
# the dialogue's default colour ('#FFFFFF') is used
#
# Return values
# 'undef' on expected arguments or if the user doesn't close the 'dialogue' window by
# clicking the 'ok' button
# Otherwise, returns the colour selected, in the form '#FFFFFF'
my ($self, $title, $initialColour, $check) = @_;
# Local variables
my ($colorSelectionObj, $red, $green, $blue, $colorObj, $response, $hex);
# Check for improper arguments
if (! defined $title || defined $check) {
return $axmud::CLIENT->writeImproper(
$self->_objClass . '->showColourSelectionDialogue',
@_,
);
}
# If an earlier call to $self->showBusyWin created a popup window, close it (otherwise it'll
# be visible above the new dialogue window)
if ($axmud::CLIENT->busyWin) {
$self->closeDialogueWin($axmud::CLIENT->busyWin);
}
# Show the 'dialogue' window
my $dialogueWin = Gtk3::ColorSelectionDialog->new($title);
$dialogueWin->set_transient_for($self->winWidget);
$dialogueWin->set_position('center-always');
$dialogueWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
$colorSelectionObj = $dialogueWin->get_color_selection();
if ($initialColour) {
# Split a string like '#FFFFFF' into three seperate colours (red, green and blue),
# convert them to decimals (in the range 0-255), and then convert that to a range of
# 0-65535 - which is what Gtk3::Gdk::Color expects
$red = hex(substr($initialColour, 1, 2)) * 257;
$green = hex(substr($initialColour, 3, 2)) * 257;
$blue = hex(substr($initialColour, 5, 2)) * 257;
$colorObj = Gtk3::Gdk::Color->new($red, $green, $blue, 0);
# Tell the Gtk3::ColorSelectionDialog to use this colour, initially
$colorSelectionObj->set_current_color($colorObj);
}
# Get the response
$response = $dialogueWin->run();
if ($response eq 'ok') {
# This is probably not the best way of converting #ffff25812581 to #FF2525, but it will
# have to do, for now
$hex = '#' . uc(
sprintf('%02x', int($colorSelectionObj->get_current_color->red() / 256))
. sprintf('%02x', int($colorSelectionObj->get_current_color->green() / 256))
. sprintf('%02x', int($colorSelectionObj->get_current_color->blue() / 256))
);
}
# Destroy the window
$dialogueWin->destroy();
# Return the colour (or 'undef' if no colour was selected)
return $hex;
}
sub showFontSelectionDialogue {
# Can be called by any function
# Creates a standard Gtk3::FontSelectionDialog and returns the response (if any)
#
# Expected arguments
# $title - The title to display, e.g. 'Select font'
#
# Optional arguments
# $initialFont - The initial font and size to use, a string in the form 'Monospace 10'
#
# Return values
# 'undef' on expected arguments or if the user doesn't close the 'dialogue' window by
# clicking the 'ok' button
# Otherwise, returns the font selected as a string in the form 'Monospace 10'
my ($self, $title, $initialFont, $check) = @_;
# Local variables
my ($response, $newFont);
# Check for improper arguments
if (! defined $title || defined $check) {
return $axmud::CLIENT->writeImproper(
$self->_objClass . '->showFontSelectionDialogue',
@_,
);
}
# If an earlier call to $self->showBusyWin created a popup window, close it (otherwise it'll
# be visible above the new dialogue window)
if ($axmud::CLIENT->busyWin) {
$self->closeDialogueWin($axmud::CLIENT->busyWin);
}
# Show the 'dialogue' window
my $dialogueWin = Gtk3::FontChooserDialog->new($title, $self->winWidget);
$dialogueWin->set_position('center-always');
$dialogueWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
if ($initialFont) {
$dialogueWin->set_font($initialFont);
}
# Get the response
$response = $dialogueWin->run();
if ($response eq 'ok') {
# Get the selected font
$newFont = $dialogueWin->get_font();
}
# Close the 'dialogue' window
$dialogueWin->destroy();
# Return the font (or 'undef' if no font was selected)
return $newFont;
}
sub promptRoomFlag {
# Called by GA::EditWin::WorldModel->roomFlags1Tab
# Prompts the user for the attributes of a new custom room flag
#
# Expected arguments
# (none besides $self)
#
# Return values
# An empty list on improper arguments or if the user closes the window without clicking
# the 'OK' button
# Otherwise returns a list in the form
# (name, short_name, descrip, colour)
# ...roughly corresponding to IVs in the new GA::Obj::RoomFlag object
my ($self, $check) = @_;
# Local variables
my (
$colour, $response,
@emptyList, @returnList,
);
# Check for improper arguments
if (defined $check) {
$axmud::CLIENT->writeImproper($self->_objClass . '->promptRoomFlag', @_);
return @emptyList;
}
# Show the 'dialogue' window
my $dialogueWin = Gtk3::Dialog->new(
'Add custom room flag',
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
'gtk-cancel' => 'reject',
'gtk-ok' => 'accept',
);
$dialogueWin->set_position('center-always');
$dialogueWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
$dialogueWin->signal_connect('delete-event' => sub {
$dialogueWin->destroy();
$self->restoreFocus();
return @emptyList;
});
# Add widgets to the 'dialogue' window
my $vBox = $dialogueWin->get_content_area();
# The call to ->addDialogueIcon splits $vBox in two, with an icon on the left, and a new
# Gtk3::VBox on the right, into which we put everything
my $vBox2 = $self->addDialogueIcon($vBox);
# Need a grid as it's the quicket way to draw the room flag colour
my $grid = Gtk3::Grid->new();
$vBox2->pack_start($grid, TRUE, TRUE, $axmud::CLIENT->constFreeSpacingPixels);
$grid->set_column_spacing($axmud::CLIENT->constFreeSpacingPixels);
$grid->set_row_spacing($axmud::CLIENT->constFreeSpacingPixels);
# Name
my $label = Gtk3::Label->new();
$grid->attach($label, 0, 0, 3, 1);
$label->set_alignment(0, 0);
$label->set_markup('Room flag name (max 16 chars)');
my $entry = Gtk3::Entry->new();
$grid->attach($entry, 0, 1, 3, 1);
$entry->set_width_chars(16);
$entry->set_max_length(16);
# Short name
my $label2 = Gtk3::Label->new();
$grid->attach($label2, 0, 2, 3, 1);
$label2->set_alignment(0, 0);
$label2->set_markup('Short name (max 2 chars)');
my $entry2 = Gtk3::Entry->new();
$grid->attach($entry2, 0, 3, 3, 1);
$entry2->set_width_chars(2);
$entry2->set_max_length(2);
# Description
my $label3 = Gtk3::Label->new();
$grid->attach($label3, 0, 4, 3, 1);
$label3->set_alignment(0, 0);
$label3->set_markup('Description');
my $entry3 = Gtk3::Entry->new();
$grid->attach($entry3, 0, 5, 3, 1);
# Colour
$colour = '#FFFFFF'; # Default new colour is white
my $label4 = Gtk3::Label->new();
$grid->attach($label4, 0, 6, 1, 1);
$label4->set_markup('Use colour');
$label4->set_alignment(0, 0.5);
lib/Games/Axmud/Generic.pm view on Meta::CPAN
# If the user clicked 'cancel', $response will be 'reject'
$response = $dialogueWin->run();
if ($response ne 'accept') {
$dialogueWin->destroy();
$self->restoreFocus();
return @emptyList;
# Otherwise, user clicked 'ok'
} else {
@returnList = ($entry->get_text(), $entry2->get_text(), $entry3->get_text(), $colour);
$dialogueWin->destroy();
$self->restoreFocus();
return @returnList;
}
}
sub showIrreversibleTest {
# Called by GA::Cmd::ToggleIrreversible->do
# Shows a 'dialogue' window with a non-functional button that contains both an icon and
# some text, to test whether the user's system allows both (some systems will show only
# the text)
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if the user closes the 'dialogue' window
# 1 otherwise
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->showIrreversibleTest', @_);
}
# If an earlier call to $self->showBusyWin created a popup window, close it (otherwise it'll
# be visible above the new dialogue window)
if ($axmud::CLIENT->busyWin) {
$self->closeDialogueWin($axmud::CLIENT->busyWin);
}
# Show the 'dialogue' window
my $dialogueWin = Gtk3::Dialog->new(
'Irreversible icon test',
$self->winWidget,
Gtk3::DialogFlags->new([qw/modal destroy-with-parent/]),
'gtk-ok' => 'accept',
);
$dialogueWin->set_position('center-always');
$dialogueWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
$dialogueWin->signal_connect('delete-event' => sub {
$dialogueWin->destroy();
$self->restoreFocus();
return undef;
});
# Add widgets to the 'dialogue' window
my $vBox = $dialogueWin->get_content_area();
# The call to ->addDialogueIcon splits $vBox in two, with an icon on the left, and a new
# Gtk3::VBox on the right, into which we put everything
my $vBox2 = $self->addDialogueIcon($vBox);
my $label = Gtk3::Label->new();
$vBox2->pack_start($label, FALSE, FALSE, $axmud::CLIENT->constFreeSpacingPixels);
$label->set_alignment(0, 0);
$label->set_markup(
"<i>If button icons are available on your\nsystem, the button below contains\nboth an"
. " icon and some text</i>"
);
my $button = Gtk3::Button->new('Hello world!');
$vBox2->pack_start($button, FALSE, FALSE, $axmud::CLIENT->constFreeSpacingPixels);
my $image = Gtk3::Image->new_from_file(
$axmud::SHARE_DIR . '/icons/system/irreversible.png',
);
$button->set_image($image);
my $label2 = Gtk3::Label->new();
$vBox2->pack_start($label2, FALSE, FALSE, $axmud::CLIENT->constFreeSpacingPixels);
$label2->set_alignment(0, 0);
$label2->set_markup(
"<i>Click 'OK' to end the test</i>"
);
# Display the 'dialogue' window. Without this combination of Gtk calls, the window is not
# consistently active (don't know why this works; it just does)
$dialogueWin->show_all();
$dialogueWin->present();
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->showIrreversibleTest');
# If the user clicked 'cancel', $response will be 'reject'
# Otherwise, user clicked 'ok', and we might need to add initial tasks
$dialogueWin->run();
$dialogueWin->destroy();
$self->restoreFocus();
return 1;
}
sub showBusyWin {
# Displays a temporary popup window (still an Axmud 'dialogue' window)
# By default, displays the Axmud icon and the caption 'Loading...', but the calling function
# can specify a different logo and caption, if required
# The popup window must be closed by the calling function, when no longer required (via a
# call to $self->closeDialogueWin)
#
# Expected arguments
# (none besides $self)
#
# Optional arguments
# $path - Path of the file containing the image to show as an icon. If not
# specified, the standard Axmud icon
# $caption - A short piece of text to show next to the image. If not specified, the
# caption 'Loading...' is used
#
# Return values
# 'undef' on improper arguments or if the window is not opened
# 1 otherwise
my ($self, $path, $caption, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->showBusyWin', @_);
}
# Don't show the popup window at all, if not allowed
if (! $axmud::CLIENT->allowBusyWinFlag) {
return undef;
}
# Only one of these temporary popup windows can exist at a time. If one already exists,
# close it
if ($axmud::CLIENT->busyWin) {
$self->closeDialogueWin($axmud::CLIENT->busyWin);
}
# Set the file path and caption text, if not specified
if (! defined $path || ! (-e $path)) {
$path = $axmud::CLIENT->getDialogueIcon('medium');
}
if (! $caption) {
$caption = 'Loading...';
}
# Show the window widget
my $dialogueWin = Gtk3::Window->new('popup');
$dialogueWin->set_position('center-always');
$dialogueWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
$dialogueWin->set_title($axmud::SCRIPT);
$dialogueWin->set_border_width(0);
$dialogueWin->set_transient_for($self->winWidget);
$dialogueWin->signal_connect('delete-event' => sub {
$dialogueWin->destroy();
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->showBusyWin');
});
# Add widgets to the 'dialogue' window
my $frame = Gtk3::Frame->new();
$dialogueWin->add($frame);
my $hBox = Gtk3::HBox->new(FALSE, 0);
$frame->add($hBox);
$hBox->set_border_width(10);
my $image = Gtk3::Image->new_from_file($path);
$hBox->pack_start($image, FALSE, FALSE, 5);
my $label = Gtk3::Label->new();
$hBox->pack_start($label, FALSE, FALSE, 5);
$label->set_markup('<i><big>' . $caption . '</big></i>');
$label->set_alignment(0.5, 0.5);
$dialogueWin->show_all();
# For some reason, during certain operations the icon and text are not shown in the
# window; the following lines make them appear
$dialogueWin->present();
# Update Gtk3's events queue
$axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->showBusyWin');
# Update the Client IV
$axmud::CLIENT->set_busyWin($dialogueWin);
return $dialogueWin;
}
# Functions to add widgets to a Gtk3::Grid
sub addLabel {
# Adds a Gtk3::Label at the specified position in a Gtk3::Grid
#
# Example calls:
# my $label = $self->addLabel($grid, 'Some plain text',
# 0, 6, 0, 1);
# my $label = $self->addLabel($grid, '<b>Some pango markup text</b>',
# 0, 6, 0, 1,
# 0, 0.5);
#
# Expected arguments
# $grid - The Gtk3::Grid itself
# $text - The text to display (plain text or pango markup text)
# $leftAttach, $rightAttach, $topAttach, $bottomAttach
# - The position of the label in the table
#
# Optional arguments
# $alignLeft, $alignRight
# - Used in the call to ->set_alignment; two values in the range 0-1
# - If not specified, $alignLeft is set to 0, $alignRight to 0.5
#
# Return values
# 'undef' on improper arguments or if the widget's position in the Gtk3::Grid is invalid
# Otherwise the Gtk3::Label created
my (
$self, $grid, $text, $leftAttach, $rightAttach, $topAttach, $bottomAttach, $alignLeft,
$alignRight, $check
) = @_;
# Check for improper arguments
if (
! defined $grid || ! defined $text || ! defined $leftAttach || ! defined $rightAttach
|| ! defined $topAttach || ! defined $bottomAttach || defined $check
) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->addLabel', @_);
}
# Check that the position in the table makes sense
if (! $self->checkPosn($leftAttach, $rightAttach, $topAttach, $bottomAttach)) {
return undef;
}
# Set default alignment, if none specified
if (! defined $alignLeft) {
$alignLeft = 0;
}
if (! defined $alignRight) {
lib/Games/Axmud/Generic.pm view on Meta::CPAN
#
# Return values
# 'undef' on improper arguments or if the widget's position in the Gtk3::Grid is invalid
# Otherwise the Gtk3::TextView created (inside a Gtk::ScrolledWindow)
my (
$self, $grid, $colourScheme, $funcRef, $string, $editableFlag, $leftAttach,
$rightAttach, $topAttach, $bottomAttach, $width, $height, $check,
) = @_;
# Check for improper arguments
if (
! defined $grid || ! defined $editableFlag || ! defined $leftAttach
|| ! defined $rightAttach || ! defined $topAttach || ! defined $bottomAttach
|| defined $check
) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->addTextView', @_);
}
# Check that the position in the table makes sense
if (! $self->checkPosn($leftAttach, $rightAttach, $topAttach, $bottomAttach)) {
return undef;
}
# Set defaults
if (! defined $width) {
$width = -1; # Let Gtk3 set the width
}
if (! defined $height) {
$height = -1; # Let Gtk3 set the height
}
# Creating a containing Gtk3::ScrolledWindow
my $scroll = Gtk3::ScrolledWindow->new(undef, undef);
$scroll->set_shadow_type($axmud::CLIENT->constShadowType);
$scroll->set_policy('automatic', 'automatic');
$scroll->set_size_request($width, $height);
# $scroll->set_border_width($self->spacingPixels);
# Create a textview and apply a CSS style
my $textView = Gtk3::TextView->new();
$scroll->add($textView);
my $buffer = Gtk3::TextBuffer->new();
$textView->set_buffer($buffer);
$textView->set_cursor_visible(FALSE);
if ($string) {
$buffer->set_text(join("\n", $string));
}
# Make the textview editable or not editable
$textView->set_editable($editableFlag);
# Apply a CSS style to the textview
if (defined $colourScheme && $axmud::CLIENT->ivExists('colourSchemeHash', $colourScheme)) {
$axmud::CLIENT->desktopObj->setTextViewStyle($colourScheme, $textView);
} else {
$axmud::CLIENT->desktopObj->setTextViewStyle($self->winType, $textView);
}
# If a callback function was specified, apply it
if ($funcRef) {
$buffer->signal_connect('changed' => sub {
&$funcRef(
$self,
$textView,
$buffer,
$axmud::CLIENT->desktopObj->bufferGetText($buffer),
);
});
}
# Add the textview to the grid
$scroll->set_hexpand(TRUE);
$scroll->set_vexpand(TRUE);
$grid->attach(
$scroll,
$leftAttach,
$topAttach,
($rightAttach - $leftAttach),
($bottomAttach - $topAttach),
);
return $textView;
}
sub addSimpleList {
# Adds a GA::Obj::SimpleList at the specified position in a Gtk3::Grid
# NB This function does not contain a ->signal_connect method - the calling function must
# specify its own one
#
# Example calls:
# my $slWidget = $self->addSimpleList($grid, \@columnList, $dataRef,
# 0, 6, 0, 1);
# my $slWidget = $self->addSimpleList($grid, \@columnList, undef,
# 0, 6, 0, 1,
# -1, 120);
# my $slWidget = $self->addSimpleList($grid, \@columnList, $dataRef,
# 0, 6, 0, 1,
# -1, -1,
# GA::Client->getMethodRef('function_name'));
#
# Expected arguments
# $grid - The Gtk3::Grid itself
# $columnListRef - Reference to a list of column headings and types, in the form
# ('heading', 'column_type', 'heading', 'column_type'...)
# - 'column_type' is one of the column types specified by
# GA::Obj::SimpleList, e.g. 'scalar', 'int'
# - 'column_type' can also be 'bool' for a non-clickable checkbox, or
# 'bool_editable' for a clickable checkbox
# $dataRef - Reference to a list of values, used to fill the simple list. If
# 'undef', it's up to the calling function to add data
# $leftAttach, $rightAttach, $topAttach, $bottomAttach
# - The position of the simple list in the table
#
# Optional arguments
# $width, $height - The width and height (in pixels) of the scroller containing the list.
# If specified, values of -1 mean 'don't set this value'. The default
# values are (-1, -1)
# $funcRef - Reference to the function to call when a (sensitised) checkbutton is
# clicked. If 'undef', it's up to the calling function to create a
# ->signal_connect method. Function references can be obtained by a
# call to GA::Client->getMethodRef
#
# Return values
# 'undef' on improper arguments or if the widget's position in the Gtk3::Grid is invalid
# Otherwise the GA::Obj::SimpleList created
lib/Games/Axmud/Generic.pm view on Meta::CPAN
# Add the frame to the table (even if a Gtk3::Image wasn't created)
$frame->set_hexpand(FALSE);
$frame->set_vexpand(FALSE);
$grid->attach(
$frame,
$leftAttach,
$topAttach,
($rightAttach - $leftAttach),
($bottomAttach - $topAttach),
);
return ($image, $frame, $viewPort);
}
sub changeImage {
# Changes the image shown as the result of a call to $self->addImage
#
# Expected arguments
# (none besides $self)
#
# Optional arguments
# $viewPort - The Gtk3::Viewport which contains the image ('undef' if no scrolling
# viewport was used)
# $frame - The Gtk3::Frame which contains the image ('undef' if a scrolling
# viewport was used; ignored if $viewPort is defined)
# $oldImage - The Gtk3::Image it currently contains. If it contains no image, set to
# 'undef'
# $filePath - Full path to the file containing the image to be displayed (or 'undef' if
# not using a file)
# $pixBuffer - A Gtk3::Gdk::Pixbuf containing the image to be displayed (or 'undef'
# if not using a pixbuf)
#
# Return values
# 'undef' on improper arguments, if the specified file doesn't exist or if a Gtk3::Image
# can't be created
# Otherwise returns the Gtk3::Image created, or 'undef' if none is created
my ($self, $viewPort, $frame, $oldImage, $filePath, $pixBuffer, $check) = @_;
# Check for improper arguments
if ((! defined $viewPort && ! defined $frame) || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->changeImage', @_);
}
# Create a new Gtk3::Image
my $newImage;
if ($filePath) {
$newImage = Gtk3::Image->new_from_file($filePath);
} elsif ($pixBuffer) {
$newImage = Gtk3::Image->new_from_pixbuf($pixBuffer);
}
if ($viewPort) {
# Remove the old image from its viewport, if an old image was specified
if ($oldImage) {
$axmud::CLIENT->desktopObj->removeWidget($viewPort, $oldImage);
}
# Add the new image to the viewport, if a new image was created
if ($newImage) {
$viewPort->add($newImage);
}
} else {
# Remove the old image from its frame, if an old image was specified
if ($oldImage) {
$axmud::CLIENT->desktopObj->removeWidget($frame, $oldImage);
}
# Add the new image to the frame, if a new image was created
if ($newImage) {
$frame->add($newImage);
}
}
# Update the window to show the changes
$self->winShowAll($self->_objClass . '->changeImage');
return $newImage; # May be 'undef'
}
sub addSimpleImage {
# Adds a Gtk3::Image from a specified file at the specified position in a Gtk3::Grid (but
# not inside a frame: call ->addImage to do that)
#
# Example calls:
# my $image = $self->addImage($grid, $filePath, $pixBuffer,
# 0, 12, 1, 12);
# my $image = $self->addImage($grid, undef, undef,
# 0, 12, 1, 12);
#
# Expected arguments
# $grid - The Gtk3::Grid itself
# $filePath - Full path to the file containing the image to be displayed (or 'undef'
# if not using a file)
# $pixBuffer - A Gtk3::Gdk::Pixbuf containing the image to be displayed (or 'undef'
# if not using a pixbuf)
# $leftAttach, $rightAttach, $topAttach, $bottomAttach
# - The position of the frame in the table
#
# Return values
# 'undef' on improper arguments or if a $filePath is specified which doesn't exist
# Otherwise the Gtk3::Image created
my (
$self, $grid, $filePath, $pixBuffer, $leftAttach, $rightAttach, $topAttach,
$bottomAttach, $check,
) = @_;
# Check for improper arguments
if (
! defined $grid || ! defined $leftAttach || ! defined $rightAttach
|| ! defined $topAttach || ! defined $bottomAttach || defined $check
) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->addSimpleImage', @_);
}
# Check that the position in the table makes sense, and that filename (if specified) exists
if (
! $self->checkPosn($leftAttach, $rightAttach, $topAttach, $bottomAttach)
|| (defined $filePath && ! -e $filePath)
) {
return undef;
}
lib/Games/Axmud/Generic.pm view on Meta::CPAN
# Three flags that can be set by any page, to prevent one of three buttons from being
# made sensitive (temporarily)
disableNextButtonFlag => FALSE,
disablePreviousButtonFlag => FALSE,
disableCancelButtonFlag => FALSE,
# The names of pages, in order of appearance
pageList => [
# 'example', # Corresponds to function $self->examplePage
# 'example2',
# 'example3',
],
# The number of the current page (first page is 0)
currentPage => 0,
# Two hashes for using the 'Next' / 'Previous' buttons to skip around the pages, rather
# than going to the actual next or previous page (as normal)
# The current page should add an entry to the hash, if necessary; the entry is removed
# by ->buttonPrevious or ->buttonNext as soon as either button is clicked
# Hashes in the form
# $hash{current_page_number} = page_number_if_button_clicked
# NB The first page's number is 0, so the fourth page will be page 3, not page 4
specialNextButtonHash => {},
specialPreviousButtonHash => {},
};
# 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 usually unique to its GA::Session (only one can be open at any
# time, per session); inform the session it has opened
# Exception - if $self->session isn't set at all (presumably because there are no sessions
# running), then there's no-one to inform
if ($self->session) {
$self->session->set_wizWin($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 usually unique to its GA::Session (only one can be open at any
# time, per session); inform the session it has closed
# Exception - if $self->session isn't set at all (presumably because there are no sessions
# running), then there's no-one to inform
if ($self->session) {
$self->session->set_wizWin();
}
return 1;
}
# sub winShowAll {} # Inherited from GA::Generic::Win
sub drawWidgets {
# Called by $self->winSetup
# Sets up the 'wiz' 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);
# Add a grid (inside a scrolled window) in the higher area
my $frame = Gtk3::Frame->new(undef);
$packingBox->pack_start($frame, TRUE, TRUE, 0);
$frame->set_border_width($self->spacingPixels);
my $scroller = Gtk3::ScrolledWindow->new(undef, undef);
$frame->add($scroller);
$scroller->set_policy('automatic', 'automatic');
$scroller->set_border_width(0);
my $grid = Gtk3::Grid->new();
$scroller->add_with_viewport($grid);
$grid->set_column_spacing($self->spacingPixels);
$grid->set_row_spacing($self->spacingPixels);
$grid->set_border_width($self->borderPixels);
lib/Games/Axmud/Generic.pm view on Meta::CPAN
sub setupGrid {
# Called by $self->winEnable
# Creates the first page for the wizard (not really necessary to have a whole function
# dedicated to this task, but having one keeps the design of 'wiz' windows consistent
# with the design of 'edit'/'pref' windows)
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my ($func, $rows);
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->setupGrid', @_);
}
# Get the name of the function for the first page
$func = $self->ivIndex('pageList', $self->currentPage) . 'Page';
# Call the function
$rows = $self->$func();
return 1;
}
sub updateGrid {
# Called by $self->buttonPrevious and ->buttonNext
# Changes the page currently visible in the 'wiz' window
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my ($func, $rows);
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->updateGrid', @_);
}
# Empty the grid used for the existing page
foreach my $widget ($self->grid->get_children()) {
$axmud::CLIENT->desktopObj->removeWidget($self->grid, $widget);
}
# Get the name of the function for the new current page
$func = $self->ivIndex('pageList', $self->currentPage) . 'Page';
# Call the function
$rows = $self->$func();
# Set button sensititives ($self->disableNextButtonFlag, etc, override the usual rules, if
# they are set)
# If it's the first page, the 'Previous' button must not be sensitive
if ($self->currentPage == 0) {
$self->previousButton->set_sensitive(FALSE);
if (! $self->disableNextButtonFlag) {
$self->nextButton->set_sensitive(TRUE);
} else {
$self->nextButton->set_sensitive(FALSE);
}
# Make sure the 'Next' button has the right label
$self->nextButton->set_label('Next');
$self->nextButton->get_child->set_width_chars(10);
# If it's the last page, the 'Next' button must be converted to a 'Finish' button
} elsif ($self->currentPage >= ((scalar $self->pageList) - 1)) {
if (! $self->disablePreviousButtonFlag) {
$self->previousButton->set_sensitive(TRUE);
} else {
$self->previousButton->set_sensitive(FALSE);
}
$self->nextButton->set_sensitive(TRUE);
$self->nextButton->set_label('Finish');
$self->nextButton->get_child->set_width_chars(10);
# For all other pages, both buttons are sensitised
} else {
if (! $self->disableNextButtonFlag) {
$self->nextButton->set_sensitive(TRUE);
} else {
$self->nextButton->set_sensitive(FALSE);
}
if (! $self->disablePreviousButtonFlag) {
$self->previousButton->set_sensitive(TRUE);
} else {
$self->previousButton->set_sensitive(FALSE);
}
# Make sure the 'Next' button has the right label
$self->nextButton->set_label('Next');
$self->nextButton->get_child->set_width_chars(10);
}
# Reset the disable flags. It's up to individual pages to set them, when they're needed
$self->ivPoke('disableNextButtonFlag', FALSE);