view release on metacpan or search on metacpan
lib/Games/Axmud/Win/Map.pm view on Meta::CPAN
my $item_alignVertical = Gtk3::CheckMenuItem->new('Align _vertically');
$item_alignVertical->set_active($self->worldModelObj->mapLabelAlignYFlag);
$item_alignVertical->signal_connect('toggled' => sub {
# Use $alignFlag to avoid an infinite loop, if we have to toggle the button back to
# its original state because the user declined to confirm the operation
if (! $alignFlag) {
if (! $self->toggleAlignCallback('vertical')) {
$alignFlag = TRUE;
if (! $item_alignVertical->get_active()) {
$item_alignVertical->set_active(TRUE);
} else {
$item_alignVertical->set_active(FALSE);
}
$alignFlag = FALSE;
}
}
});
$subMenu_alignment->append($item_alignVertical);
my $item_alignment = Gtk3::MenuItem->new('_Label alignment');
$item_alignment->set_submenu($subMenu_alignment);
$column_labels->append($item_alignment);
$column_labels->append(Gtk3::SeparatorMenuItem->new()); # Separator
my $item_deleteLabel = Gtk3::ImageMenuItem->new('_Delete labels');
my $img_deleteLabel = Gtk3::Image->new_from_stock('gtk-delete', 'menu');
$item_deleteLabel->set_image($img_deleteLabel);
$item_deleteLabel->signal_connect('activate' => sub {
# Callback to prompt for confirmation, before deleting multiple labels
$self->deleteLabelsCallback();
});
$column_labels->append($item_deleteLabel);
# (Requires $self->currentRegionmap & either $self->selectedLabel or
# $self->selectedLabelHash)
$self->ivAdd('menuToolItemHash', 'delete_label', $item_deleteLabel);
my $item_quickDelete = Gtk3::ImageMenuItem->new('_Quick label deletion...');
my $img_quickDelete = Gtk3::Image->new_from_stock('gtk-delete', 'menu');
$item_quickDelete->set_image($img_quickDelete);
$item_quickDelete->signal_connect('activate' => sub {
$self->session->pseudoCmd('quicklabeldelete', $self->pseudoCmdMode);
});
$column_labels->append($item_quickDelete);
# Setup complete
return $column_labels;
}
# Popup menu widget methods
sub enableCanvasPopupMenu {
# Called by $self->canvasEventHandler
# Creates a popup-menu for the Gtk3::Canvas when no rooms, exits, room tags or labels are
# selected
#
# Expected arguments
# $clickXPosPixels, $clickYPosPixels
# - Coordinates of the pixel that was right-clicked on the map
# $clickXPosBlocks, $clickYPosBlocks
# - Coordinates of the gridblock that was right-clicked on the map
#
# Return values
# 'undef' on improper arguments or if the widget can't be created
# Otherwise returns the Gtk3::Menu created
my (
$self, $clickXPosPixels, $clickYPosPixels, $clickXPosBlocks, $clickYPosBlocks, $check,
) = @_;
# Check for improper arguments
if (
! defined $clickXPosPixels || ! defined $clickYPosPixels
|| ! defined $clickXPosBlocks || ! defined $clickYPosBlocks || defined $check
) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->enableCanvasPopupMenu', @_);
}
# Set up the popup menu
my $menu_canvas = Gtk3::Menu->new();
if (! $menu_canvas) {
return undef;
}
# (Everything here assumes $self->currentRegionmap)
my $item_addFirstRoom = Gtk3::ImageMenuItem->new('Add _first room');
my $img_addFirstRoom = Gtk3::Image->new_from_stock('gtk-add', 'menu');
$item_addFirstRoom->set_image($img_addFirstRoom);
$item_addFirstRoom->signal_connect('activate' => sub {
$self->addFirstRoomCallback();
});
$menu_canvas->append($item_addFirstRoom);
# (Also requires empty $self->currentRegionmap->gridRoomHash)
if ($self->currentRegionmap->gridRoomHash) {
$item_addFirstRoom->set_sensitive(FALSE);
}
my $item_addRoomHere = Gtk3::ImageMenuItem->new('Add _room here');
my $img_addRoomHere = Gtk3::Image->new_from_stock('gtk-add', 'menu');
$item_addRoomHere->set_image($img_addRoomHere);
$item_addRoomHere->signal_connect('activate' => sub {
my $roomObj;
# The 'Add room at click' operation from the main menu resets the value of
# ->freeClickMode; we must do the same here
$self->reset_freeClickMode();
# Create the room
$roomObj = $self->mapObj->createNewRoom(
$self->currentRegionmap,
$clickXPosBlocks,
$clickYPosBlocks,
$self->currentRegionmap->currentLevel,
);
# When using the 'Add room at block' menu item, the new room is selected to make it
# easier to see where it was drawn. To make things consistent, select this new room,
# too
if ($roomObj) {
$self->setSelectedObj(
[$roomObj, 'room'],
FALSE, # Select this object; unselect all other objects
);
}
});
$menu_canvas->append($item_addRoomHere);
$menu_canvas->append(Gtk3::SeparatorMenuItem->new()); # Separator
my $item_addLabelHere = Gtk3::ImageMenuItem->new('Add _label here');
my $img_addLabelHere = Gtk3::Image->new_from_stock('gtk-add', 'menu');
$item_addLabelHere->set_image($img_addLabelHere);
$item_addLabelHere->signal_connect('activate' => sub {
lib/Games/Axmud/Win/Map.pm view on Meta::CPAN
$menu_canvas->append($item_addLabelHere);
$menu_canvas->append(Gtk3::SeparatorMenuItem->new()); # Separator
my $item_centreMap = Gtk3::MenuItem->new('_Centre map here');
$item_centreMap->signal_connect('activate' => sub {
$self->centreMapOverRoom(
undef, # Centre the map, not over a room...
$clickXPosBlocks, # ...but over this gridblock
$clickYPosBlocks,
);
});
$menu_canvas->append($item_centreMap);
$menu_canvas->append(Gtk3::SeparatorMenuItem->new()); # Separator
my $item_editRegionmap = Gtk3::ImageMenuItem->new('_Edit regionmap...');
my $img_editRegionmap = Gtk3::Image->new_from_stock('gtk-edit', 'menu');
$item_editRegionmap->set_image($img_editRegionmap);
$item_editRegionmap->signal_connect('activate' => sub {
# Open an 'edit' window for the regionmap
$self->createFreeWin(
'Games::Axmud::EditWin::Regionmap',
$self,
$self->session,
'Edit \'' . $self->currentRegionmap->name . '\' regionmap',
$self->currentRegionmap,
FALSE, # Not temporary
);
});
$menu_canvas->append($item_editRegionmap);
my $item_preferences = Gtk3::ImageMenuItem->new('Edit world _model...');
my $img_preferences = Gtk3::Image->new_from_stock('gtk-edit', 'menu');
$item_preferences->set_image($img_preferences);
$item_preferences->signal_connect('activate' => sub {
# Open an 'edit' window for the world model
$self->createFreeWin(
'Games::Axmud::EditWin::WorldModel',
$self,
$self->session,
'Edit world model',
$self->session->worldModelObj,
FALSE, # Not temporary
);
});
$menu_canvas->append($item_preferences);
# Setup complete
$menu_canvas->show_all();
return $menu_canvas;
}
sub enableRoomsPopupMenu {
# Called by $self->canvasObjEventHandler
# Creates a popup-menu for the selected room
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if the widget can't be created
# Otherwise returns the Gtk3::Menu created
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->enableRoomsPopupMenu', @_);
}
# Set up the popup menu
my $menu_rooms = Gtk3::Menu->new();
if (! $menu_rooms) {
return undef;
}
# (Everything here assumes $self->currentRegionmap and $self->selectedRoom)
my $item_setCurrentRoom = Gtk3::MenuItem->new('_Set current room');
$item_setCurrentRoom->signal_connect('activate' => sub {
$self->mapObj->setCurrentRoom($self->selectedRoom);
});
$menu_rooms->append($item_setCurrentRoom);
my $item_centreMap = Gtk3::MenuItem->new('_Centre map over room');
$item_centreMap->signal_connect('activate' => sub {
$self->centreMapOverRoom($self->selectedRoom);
});
$menu_rooms->append($item_centreMap);
my $item_executeScripts = Gtk3::MenuItem->new('Run _Axbasic scripts');
$item_executeScripts->signal_connect('activate' => sub {
$self->executeScriptsCallback();
});
$menu_rooms->append($item_executeScripts);
# (Also requires $self->mapObj->currentRoom that's the same as $self->selectedRoom)
if (! $self->mapObj->currentRoom || $self->mapObj->currentRoom ne $self->selectedRoom) {
$item_executeScripts->set_sensitive(FALSE);
}
$menu_rooms->append(Gtk3::SeparatorMenuItem->new()); # Separator
# 'Pathfinding' submenu
my $subMenu_pathFinding = Gtk3::Menu->new();
my $item_highlightPath = Gtk3::MenuItem->new('_Highlight path');
$item_highlightPath->signal_connect('activate' => sub {
$self->processPathCallback('select_room');
});
$subMenu_pathFinding->append($item_highlightPath);
my $item_displayPath = Gtk3::MenuItem->new('_Edit path...');
$item_displayPath->signal_connect('activate' => sub {
$self->processPathCallback('pref_win');
});
$subMenu_pathFinding->append($item_displayPath);
my $item_goToRoom = Gtk3::MenuItem->new('_Go to room');
$item_goToRoom->signal_connect('activate' => sub {
$self->processPathCallback('send_char');
});
$subMenu_pathFinding->append($item_goToRoom);
lib/Games/Axmud/Win/Map.pm view on Meta::CPAN
# Edit virtual area file
$self->editFileCallback(TRUE);
}
}
});
$subSubMenu_sourceCode->append($item_editSource);
# (Also requires either $self->selectedRoom->sourceCodePath or
# $self->selectedRoom->virtualAreaPath)
if (
! $self->selectedRoom->sourceCodePath
&& ! $self->selectedRoom->virtualAreaPath
) {
$item_editSource->set_sensitive(FALSE);
}
my $item_sourceCode = Gtk3::MenuItem->new('Source _code');
$item_sourceCode->set_submenu($subSubMenu_sourceCode);
$subMenu_roomFeatures->append($item_sourceCode);
$subMenu_roomFeatures->append(Gtk3::SeparatorMenuItem->new()); # Separator
my $item_setInteriorOffsets = Gtk3::MenuItem->new('_Synchronise grid coordinates...');
$item_setInteriorOffsets->signal_connect('activate' => sub {
$self->setInteriorOffsetsCallback();
});
$subMenu_roomFeatures->append($item_setInteriorOffsets);
my $item_resetInteriorOffsets = Gtk3::MenuItem->new('_Reset grid coordinates');
$item_resetInteriorOffsets->signal_connect('activate' => sub {
$self->resetInteriorOffsetsCallback();
});
$subMenu_roomFeatures->append($item_resetInteriorOffsets);
my $item_roomFeatures = Gtk3::MenuItem->new('Ot_her room features');
$item_roomFeatures->set_submenu($subMenu_roomFeatures);
$menu_rooms->append($item_roomFeatures);
$menu_rooms->append(Gtk3::SeparatorMenuItem->new()); # Separator
my $item_deleteRoom = Gtk3::ImageMenuItem->new('_Delete room');
my $img_deleteRoom = Gtk3::Image->new_from_stock('gtk-delete', 'menu');
$item_deleteRoom->set_image($img_deleteRoom);
$item_deleteRoom->signal_connect('activate' => sub {
$self->deleteRoomsCallback();
});
$menu_rooms->append($item_deleteRoom);
# Setup complete
$menu_rooms->show_all();
return $menu_rooms;
}
sub enableRoomTagsPopupMenu {
# Called by $self->canvasObjEventHandler
# Creates a popup-menu for the selected room tag
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if the widget can't be created
# Otherwise returns the Gtk3::Menu created
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper(
$self->_objClass . '->enableRoomTagsPopupMenu',
@_,
);
}
# Set up the popup menu
my $menu_tags = Gtk3::Menu->new();
if (! $menu_tags) {
return undef;
}
# (Everything here assumes $self->currentRegionmap and $self->selectedRoomTag)
my $item_editTag = Gtk3::MenuItem->new('_Set room tag...');
$item_editTag->signal_connect('activate' => sub {
$self->setRoomTagCallback();
});
$menu_tags->append($item_editTag);
my $item_resetPosition = Gtk3::MenuItem->new('_Reset position');
$item_resetPosition->signal_connect('activate' => sub {
if ($self->selectedRoomTag) {
$self->worldModelObj->resetRoomOffsets(
TRUE, # Update Automapper windows now
1, # Mode 1 - reset room tag only
$self->selectedRoomTag, # Set to the parent room's blessed reference
);
}
});
$menu_tags->append($item_resetPosition);
# Setup complete
$menu_tags->show_all();
return $menu_tags;
}
sub enableRoomGuildsPopupMenu {
# Called by $self->canvasObjEventHandler
# Creates a popup-menu for the selected room guild
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if the widget can't be created
# Otherwise returns the Gtk3::Menu created
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper(
$self->_objClass . '->enableRoomGuildsPopupMenu',
@_,
);
}
# Set up the popup menu
my $menu_guilds = Gtk3::Menu->new();
if (! $menu_guilds) {
return undef;
}
# (Everything here assumes $self->currentRegionmap and $self->selectedRoomGuild)
my $item_editGuild = Gtk3::MenuItem->new('_Set room guild...');
$item_editGuild->signal_connect('activate' => sub {
$self->setRoomGuildCallback();
});
$menu_guilds->append($item_editGuild);
my $item_resetPosition = Gtk3::MenuItem->new('_Reset position');
$item_resetPosition->signal_connect('activate' => sub {
if ($self->selectedRoomGuild) {
$self->worldModelObj->resetRoomOffsets(
TRUE, # Update Automapper windows now
2, # Mode 2 - reset room guild only
$self->selectedRoomGuild, # Set to the parent room's blessed reference
);
}
});
$menu_guilds->append($item_resetPosition);
# Setup complete
$menu_guilds->show_all();
return $menu_guilds;
}
sub enableExitsPopupMenu {
# Called by $self->canvasObjEventHandler
# Creates a popup-menu for the selected exit
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if the widget can't be created
# Otherwise returns the Gtk3::Menu created
my ($self, $check) = @_;
# Local variables
my @titleList;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->enableExitsPopupMenu', @_);
}
# Set up the popup menu
my $menu_exits = Gtk3::Menu->new();
if (! $menu_exits) {
return undef;
}
# (Everything here assumes $self->currentRegionmap and $self->selectedExit)
# 'Allocate map direction' submenu
my $subMenu_setDir = Gtk3::Menu->new();
my $item_changeDir = Gtk3::MenuItem->new('_Change direction...');
$item_changeDir->signal_connect('activate' => sub {
$self->changeDirCallback();
});
$subMenu_setDir->append($item_changeDir);
# (Also requires $self->selectedExit->drawMode is 'primary' or 'perm_alloc'
if (
$self->selectedExit->drawMode ne 'primary'
&& $self->selectedExit->drawMode ne 'perm_alloc'
) {
$item_changeDir->set_sensitive(FALSE);
}
my $item_altDir = Gtk3::MenuItem->new('Set _alternative direction(s)...');
$item_altDir->signal_connect('activate' => sub {
$self->setAltDirCallback();
});
$subMenu_setDir->append($item_altDir);
my $item_setDir = Gtk3::MenuItem->new('Set di_rection');
$item_setDir->set_submenu($subMenu_setDir);
$menu_exits->append($item_setDir);
my $item_setAssisted = Gtk3::MenuItem->new('Set assisted _move...');
$item_setAssisted->signal_connect('activate' => sub {
$self->setAssistedMoveCallback();
});
$menu_exits->append($item_setAssisted);
# (Also requires $self->selectedExit->drawMode 'primary', 'temp_unalloc' or 'perm_unalloc')
if ($self->selectedExit->drawMode eq 'temp_alloc') {
$item_setAssisted->set_sensitive(FALSE);
}
# 'Allocate map direction' submenu
my $subMenu_allocateMapDir = Gtk3::Menu->new();
my $item_allocatePrimary = Gtk3::MenuItem->new('Choose _direction...');
$item_allocatePrimary->signal_connect('activate' => sub {
$self->allocateMapDirCallback();
});
$subMenu_allocateMapDir->append($item_allocatePrimary);
my $item_confirmTwoWay = Gtk3::MenuItem->new('Confirm _two-way exit...');
lib/Games/Axmud/Win/Map.pm view on Meta::CPAN
$self->editExitTagCallback();
});
$subMenu_exitTags->append($item_editTag);
my $item_toggleExitTag = Gtk3::MenuItem->new('_Toggle exit tag');
$item_toggleExitTag->signal_connect('activate' => sub {
$self->toggleExitTagCallback();
});
$subMenu_exitTags->append($item_toggleExitTag);
$subMenu_exitTags->append(Gtk3::SeparatorMenuItem->new()); # Separator
my $item_resetPosition = Gtk3::MenuItem->new('_Reset text position');
$item_resetPosition->signal_connect('activate' => sub {
$self->resetExitOffsetsCallback();
});
$subMenu_exitTags->append($item_resetPosition);
my $item_exitTags = Gtk3::MenuItem->new('Exit _tags');
$item_exitTags->set_submenu($subMenu_exitTags);
$menu_exits->append($item_exitTags);
# (Also requires either a $self->selectedExit which is a region exit)
if (! $self->selectedExit->regionFlag) {
$item_exitTags->set_sensitive(FALSE);
}
$menu_exits->append(Gtk3::SeparatorMenuItem->new()); # Separator
my $item_editExit = Gtk3::ImageMenuItem->new('Edit e_xit...');
my $img_editExit = Gtk3::Image->new_from_stock('gtk-edit', 'menu');
$item_editExit->set_image($img_editExit);
$item_editExit->signal_connect('activate' => sub {
$self->editExitCallback();
});
$menu_exits->append($item_editExit);
$menu_exits->append(Gtk3::SeparatorMenuItem->new()); # Separator
my $item_deleteExit = Gtk3::ImageMenuItem->new('_Delete exit');
my $img_deleteExit = Gtk3::Image->new_from_stock('gtk-add', 'menu');
$item_deleteExit->set_image($img_deleteExit);
$item_deleteExit->signal_connect('activate' => sub {
$self->deleteExitCallback();
});
$menu_exits->append($item_deleteExit);
# Setup complete
$menu_exits->show_all();
return $menu_exits;
}
sub enableExitTagsPopupMenu {
# Called by $self->canvasObjEventHandler
# Creates a popup-menu for the selected exit tag
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if the widget can't be created
# Otherwise returns the Gtk3::Menu created
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper(
$self->_objClass . '->enableExitTagsPopupMenu',
@_,
);
}
# Set up the popup menu
my $menu_tags = Gtk3::Menu->new();
if (! $menu_tags) {
return undef;
}
# (Everything here assumes $self->currentRegionmap and $self->selectedExitTag)
my $item_editTag = Gtk3::MenuItem->new('_Edit exit tag');
$item_editTag->signal_connect('activate' => sub {
$self->editExitTagCallback();
});
$menu_tags->append($item_editTag);
my $item_cancelTag = Gtk3::MenuItem->new('_Cancel exit tag');
$item_cancelTag->signal_connect('activate' => sub {
$self->toggleExitTagCallback();
});
$menu_tags->append($item_cancelTag);
$menu_tags->append(Gtk3::SeparatorMenuItem->new()); # Separator
my $item_viewDestination = Gtk3::MenuItem->new('_View destination');
$item_viewDestination->signal_connect('activate' => sub {
$self->viewExitDestination();
});
$menu_tags->append($item_viewDestination);
$menu_tags->append(Gtk3::SeparatorMenuItem->new()); # Separator
my $item_resetPosition = Gtk3::MenuItem->new('_Reset position');
$item_resetPosition->signal_connect('activate' => sub {
$self->resetExitOffsetsCallback();
});
$menu_tags->append($item_resetPosition);
# Setup complete
$menu_tags->show_all();
return $menu_tags;
}
sub enableLabelsPopupMenu {
# Called by $self->canvasObjEventHandler
# Creates a popup-menu for the selected label
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if the widget can't be created
# Otherwise returns the Gtk3::Menu created
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->enableLabelsPopupMenu', @_);
}
# Set up the popup menu
my $menu_labels = Gtk3::Menu->new();
if (! $menu_labels) {
return undef;
}
# (Everything here assumes $self->currentRegionmap and $self->selectedLabel)
my $item_setLabel = Gtk3::ImageMenuItem->new('_Set label...');
my $img_setLabel = Gtk3::Image->new_from_stock('gtk-edit', 'menu');
$item_setLabel->set_image($img_setLabel);
$item_setLabel->signal_connect('activate' => sub {
$self->setLabelCallback(FALSE)
});
$menu_labels->append($item_setLabel);
my $item_customiseLabel = Gtk3::ImageMenuItem->new('_Customise label...');
my $img_customiseLabel = Gtk3::Image->new_from_stock('gtk-edit', 'menu');
$item_customiseLabel->set_image($img_customiseLabel);
$item_customiseLabel->signal_connect('activate' => sub {
$self->setLabelCallback(TRUE);
});
$menu_labels->append($item_customiseLabel);
$menu_labels->append(Gtk3::SeparatorMenuItem->new()); # Separator
# 'Set label style' submenu
my $subMenu_setStyle = Gtk3::Menu->new();
foreach my $style (
sort {lc($a) cmp lc($b)} ($self->worldModelObj->ivKeys('mapLabelStyleHash'))
) {
my $item_thisStyle = Gtk3::MenuItem->new($style);
$item_thisStyle->signal_connect('activate' => sub {
$self->setLabelDirectCallback($style);
});
$subMenu_setStyle->append($item_thisStyle);
}
my $item_setStyle = Gtk3::MenuItem->new('S_et label style');
$item_setStyle->set_submenu($subMenu_setStyle);
$menu_labels->append($item_setStyle);
# (Also requires at least one label style)
if (! $self->worldModelObj->mapLabelStyleHash) {
$item_setStyle->set_sensitive(FALSE);
}
$menu_labels->append(Gtk3::SeparatorMenuItem->new()); # Separator
my $item_deleteLabel = Gtk3::ImageMenuItem->new('_Delete label');
my $img_deleteLabel = Gtk3::Image->new_from_stock('gtk-delete', 'menu');
$item_deleteLabel->set_image($img_deleteLabel);
$item_deleteLabel->signal_connect('activate' => sub {
if ($self->selectedLabel) {
lib/Games/Axmud/Win/Map.pm view on Meta::CPAN
OUTER: foreach my $set (@afterList, @beforeList) {
if (! $self->ivShow('buttonSetHash', $set)) {
$nextSet = $set;
last OUTER;
}
}
if (! $nextSet) {
# All button sets are visible; cannot switch set
return undef;
}
# Remove the existing button set (preserving the switcher and add buttons, and the separator
# that follows them)
foreach my $widget ($self->toolbarButtonList) {
$axmud::CLIENT->desktopObj->removeWidget($toolbar, $widget);
}
# After the separator, we draw the specified button set. This function decides which
# specific function to call, and returns the result
@buttonList = $self->chooseButtonSet($toolbar, $nextSet);
# Add the buttons/separators to the toolbar
foreach my $button (@buttonList) {
my $label;
# (Separators don't have labels, so we need to check for that)
if (! $axmud::CLIENT->toolbarLabelFlag && $button->isa('Gtk3::ToolButton')) {
$button->set_label(undef);
}
$toolbar->insert($button, -1);
}
# Sensitise/desensitise menu bar/toolbar items, depending on current conditions
$self->restrictWidgets();
# Update IVs
$self->ivAdd('buttonSetHash', $currentSet, FALSE);
$self->ivAdd('buttonSetHash', $nextSet, TRUE);
$self->ivAdd('toolbarHash', $toolbar, $nextSet);
$self->ivPoke('toolbarButtonList', @buttonList);
$self->ivPoke('toolbarOriginalSet', $nextSet);
# Not worth calling $self->redrawWidgets, so must do a ->show_all()
$toolbar->show_all();
return 1;
}
sub addToolbar {
# Called by a ->signal_connect in $self->drawToolbar whenever the user clicks the original
# toolbar's add button
# Creates a popup menu containing all of the button sets that aren't currently visible, then
# imlements the user's choice
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if there's an error
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my (
@list,
%hash,
);
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->addToolbar', @_);
}
# Get a list of button sets that aren't already visible
# NB The 'default' set can only be viewed in the original (first) toolbar, so it's not added
# to this list
foreach my $set ($self->constButtonSetList) {
my $descrip = $self->ivShow('constButtonDescripHash', $set);
if ($set ne $self->constToolbarDefaultSet && ! $self->ivShow('buttonSetHash', $set)) {
push (@list, $descrip);
$hash{$descrip} = $set;
}
}
if (! @list) {
# All button sets are visible (this shouldn't happen)
return undef;
}
# Set up the popup menu
my $popupMenu = Gtk3::Menu->new();
if (! $popupMenu) {
return undef;
}
# Add a title menu item, which does nothing
my $title_item = Gtk3::MenuItem->new('Add button set:');
$title_item->signal_connect('activate' => sub {
return undef;
});
$title_item->set_sensitive(FALSE);
$popupMenu->append($title_item);
$popupMenu->append(Gtk3::SeparatorMenuItem->new()); # Separator
# Fill the popup menu with button sets
foreach my $descrip (@list) {
my $menu_item = Gtk3::MenuItem->new($descrip);
$menu_item->signal_connect('activate' => sub {
# Add the set to the world model's list of button sets...
$self->worldModelObj->add_buttonSet($hash{$descrip});
# ...then redraw the window component containing the toolbar(s)
$self->redrawWidgets('toolbar');
});
$popupMenu->append($menu_item);
}
# Also add a 'Cancel' menu item, which does nothing
$popupMenu->append(Gtk3::SeparatorMenuItem->new()); # Separator
my $cancel_item = Gtk3::MenuItem->new('Cancel');
$cancel_item->signal_connect('activate' => sub {
return undef;
});
$popupMenu->append($cancel_item);
# Display the popup menu
$popupMenu->popup(
undef, undef, undef, undef,
1, # Left mouse button
Gtk3::get_current_event_time(),
);
$popupMenu->show_all();
# Operation complete. Now wait for the user's response
return 1;
}
sub removeToolbar {
# Called by a ->signal_connect in $self->drawToolbar whenever the user clicks on the remove
# button in any toolbar except the original one
# Removes the specified toolbar and updates IVs
#
# Expected arguments
# $toolbar - The toolbar widget to be removed
#
# Return values
# 'undef' on improper arguments or if there's an error
# 1 otherwise
my ($self, $toolbar, $check) = @_;
# Local variables
my (
$set,
@modList,
);
# Check for improper arguments
if (! defined $toolbar || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->removeToolbar', @_);
}
# Check the toolbar widget still exists (no reason it shouldn't, but it doesn't hurt to
# check)
if (! $self->ivExists('toolbarHash', $toolbar)) {
return undef;
} else {
# Get the button set that was drawn in this toolbar
$set = $self->ivShow('toolbarHash', $toolbar);
}
# Add the set to the world model's list of button sets...
$self->worldModelObj->del_buttonSet($set);
# ...then redraw the window component containing the toolbar(s)
$self->redrawWidgets('toolbar');
return 1;
}
sub chooseButtonSet {
# Called by $self->drawToolbar and ->switchToolbarButtons
# Calls the right function for the specified button set, and returns the result
#
# Expected arguments
# $toolbar - The toolbar widget on which the buttons are drawn
# $set - The button set to use (one of the items in $self->constButtonSetList)
lib/Games/Axmud/Win/Map.pm view on Meta::CPAN
push (@interiorList, $mode);
$interiorHash{$mode} = $descrip;
$iconHash{$mode} = $icon;
} until (! @initList);
for (my $count = 0; $count < (scalar @interiorList); $count++) {
my ($icon, $mode);
$mode = $interiorList[$count];
# (For $count = 0, $buttonGroup is 'undef')
my $radioButton;
if ($mode eq 'none') {
$radioButton = Gtk3::RadioToolButton->new(undef);
} else {
$radioButton = Gtk3::RadioToolButton->new_from_widget($lastButton);
}
if ($self->worldModelObj->roomInteriorMode eq $mode) {
$radioButton->set_active(TRUE);
}
$radioButton->set_icon_widget(
Gtk3::Image->new_from_file($axmud::SHARE_DIR . '/icons/map/' . $iconHash{$mode}),
);
$radioButton->set_label($interiorHash{$mode});
$radioButton->set_tooltip_text($interiorHash{$mode});
$radioButton->signal_connect('toggled' => sub {
if (! $self->ignoreMenuUpdateFlag && $radioButton->get_active()) {
$self->worldModelObj->switchRoomInteriorMode($mode);
}
});
push (@buttonList, $radioButton);
# (Never desensitised)
$self->ivAdd('menuToolItemHash', 'icon_interior_mode_' . $mode, $radioButton);
$lastButton = $radioButton;
# (Add a separator after the first toolbar button)
if ($mode eq 'none') {
# Separator
my $separator = Gtk3::SeparatorToolItem->new();
push (@buttonList, $separator);
}
}
return @buttonList;
}
sub addRoomFlagButton {
# Called by a ->signal_connect in $self->drawPaintingButtonSet whenever the user clicks the
# 'add room flag' button in the 'painting' button set
# Creates a popup menu containing all room flags, then implements the user's choice
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if there's an error
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my %checkHash;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->addRoomFlagButton', @_);
}
# Compile a hash of existing preferred room flags (we don't want the user to add the same
# room flag twice)
foreach my $roomFlag ($self->worldModelObj->preferRoomFlagList) {
$checkHash{$roomFlag} = undef;
}
# Set up the popup menu
my $popupMenu = Gtk3::Menu->new();
if (! $popupMenu) {
return undef;
}
# Add a title menu item, which does nothing
my $title_item = Gtk3::MenuItem->new('Add preferred room flag:');
$title_item->signal_connect('activate' => sub {
return undef;
});
$title_item->set_sensitive(FALSE);
$popupMenu->append($title_item);
$popupMenu->append(Gtk3::SeparatorMenuItem->new()); # Separator
# Fill the popup menu with room flags
foreach my $filter ($axmud::CLIENT->constRoomFilterList) {
# A sub-sub menu for $filter
my $subSubMenu_filter = Gtk3::Menu->new();
my @nameList = $self->worldModelObj->getRoomFlagsInFilter($filter);
foreach my $name (@nameList) {
my $obj = $self->worldModelObj->ivShow('roomFlagHash', $name);
if ($obj) {
my $menuItem = Gtk3::MenuItem->new($obj->descrip);
$menuItem->signal_connect('activate' => sub {
# Add the room flag to the world model's list of preferred room flags...
$self->worldModelObj->add_preferRoomFlag($name);
# ...then redraw the window component containing the toolbar(s), toggling
# the button for the new room flag
$self->redrawWidgets('toolbar');
});
$subSubMenu_filter->append($menuItem);
}
}
if (! @nameList) {
my $menuItem = Gtk3::MenuItem->new('(No flags in this filter)');
$menuItem->set_sensitive(FALSE);
$subSubMenu_filter->append($menuItem);
}
my $menuItem = Gtk3::MenuItem->new(ucfirst($filter));
$menuItem->set_submenu($subSubMenu_filter);
$popupMenu->append($menuItem);
}
# Also add a 'Cancel' menu item, which does nothing
$popupMenu->append(Gtk3::SeparatorMenuItem->new()); # Separator
my $cancel_item = Gtk3::MenuItem->new('Cancel');
$cancel_item->signal_connect('activate' => sub {
return undef;
});
$popupMenu->append($cancel_item);
# Display the popup menu
$popupMenu->popup(
undef, undef, undef, undef,
1, # Left mouse button
Gtk3::get_current_event_time(),
);
$popupMenu->show_all();
# Operation complete. Now wait for the user's response
return 1;
}
sub removeRoomFlagButton {
# Called by a ->signal_connect in $self->drawPaintingButtonSet whenever the user clicks the
# 'remove room flag' button in the 'painting' button set
# Removes the specified room flag from the toolbar and updates IVs
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if there's an error
# 1 otherwise
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->removeRoomFlagButton', @_);
}
# Set up the popup menu
my $popupMenu = Gtk3::Menu->new();
if (! $popupMenu) {
return undef;
}
# Add a title menu item, which does nothing
my $title_item = Gtk3::MenuItem->new('Remove preferred room flag:');
$title_item->signal_connect('activate' => sub {
return undef;
});
$title_item->set_sensitive(FALSE);
$popupMenu->append($title_item);
$popupMenu->append(Gtk3::SeparatorMenuItem->new()); # Separator
# Fill the popup menu with room flags
foreach my $roomFlag ($self->worldModelObj->preferRoomFlagList) {
my $menu_item = Gtk3::MenuItem->new($roomFlag);
$menu_item->signal_connect('activate' => sub {
# Remove the room flag from the world model's list of preferred room flags...
$self->worldModelObj->del_preferRoomFlag($roomFlag);
# ...and from the painter object iself...
$self->worldModelObj->painterObj->ivDelete('roomFlagHash', $roomFlag);
# ...then redraw the window component containing the toolbar(s)
$self->redrawWidgets('toolbar');
});
$popupMenu->append($menu_item);
}
# Add a 'remove all' menu item
$popupMenu->append(Gtk3::SeparatorMenuItem->new()); # Separator
my $remove_all_item = Gtk3::MenuItem->new('Remove all');
$remove_all_item->signal_connect('activate' => sub {
my ($total, $choice);
$total = scalar $self->worldModelObj->preferRoomFlagList;
# If there's more than one colour, prompt the user for confirmation
if ($total > 1) {
$choice = $self->showMsgDialogue(
'Remove all room flag buttons',
'question',
'Are you sure you want to remove all ' . $total . ' room flag buttons?',
'yes-no',
);
} else {
$choice = 'yes';
}
if (defined $choice && $choice eq 'yes') {
# Reset the world model's list of preferred room flags
$self->worldModelObj->reset_preferRoomFlagList();
# Update the painter object (which might contain room flags not added with these
# tools)
foreach my $roomFlag ($self->worldModelObj->preferRoomFlagList) {
$self->worldModelObj->ivDelete('roomFlagHash', $roomFlag);
}
# Then redraw the window component containing the toolbar(s)
$self->redrawWidgets('toolbar');
}
});
$popupMenu->append($remove_all_item);
# Also add a 'Cancel' menu item, which does nothing
my $cancel_item = Gtk3::MenuItem->new('Cancel');
$cancel_item->signal_connect('activate' => sub {
return undef;
});
$popupMenu->append($cancel_item);
# Display the popup menu
$popupMenu->popup(
undef, undef, undef, undef,
1, # Left mouse button
Gtk3::get_current_event_time(),
);
$popupMenu->show_all();
# Operation complete. Now wait for the user's response
return 1;
}
sub addBGColourButton {
# Called by a ->signal_connect in $self->drawBackgroundButtonSet whenever the user clicks
# the 'add background colour' button in the 'background' button set
# Prompts the user for a new RGB colour tag, then implements the user's choice
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if there's an error
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my $colour;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->addBGColourButton', @_);
}
$colour = $self->showColourSelectionDialogue('Add preferred background colour');
if (defined $colour) {
# Add the room flag to the world model's list of preferred background colours...
$self->worldModelObj->add_preferBGColour($colour);
# ...then redraw the window component containing the toolbar(s), selecting the new
# colour
$self->ivPoke('bgColourChoice', $colour);
$self->redrawWidgets('toolbar');
}
return 1;
}
sub removeBGColourButton {
# Called by a ->signal_connect in $self->drawBackgroundButtonSet whenever the user clicks
# the 'remove background colour' button in the 'background' button set
# Removes the specified colour from the toolbar and updates IVs
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if there's an error
# 1 otherwise
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->removeBGColourButton', @_);
}
# Set up the popup menu
my $popupMenu = Gtk3::Menu->new();
if (! $popupMenu) {
return undef;
}
# Add a title menu item, which does nothing
my $title_item = Gtk3::MenuItem->new('Remove preferred background colour:');
$title_item->signal_connect('activate' => sub {
return undef;
});
$title_item->set_sensitive(FALSE);
$popupMenu->append($title_item);
$popupMenu->append(Gtk3::SeparatorMenuItem->new()); # Separator
# Fill the popup menu with colours
foreach my $colour ($self->worldModelObj->preferBGColourList) {
my $menu_item = Gtk3::MenuItem->new($colour);
$menu_item->signal_connect('activate' => sub {
# Remove the colour from the world model's list of preferred background colours...
$self->worldModelObj->del_preferBGColour($colour);
# ...then redraw the window component containing the toolbar(s)
$self->redrawWidgets('toolbar');
});
$popupMenu->append($menu_item);
}
# Add a 'remove all' menu item
$popupMenu->append(Gtk3::SeparatorMenuItem->new()); # Separator
my $remove_all_item = Gtk3::MenuItem->new('Remove all');
$remove_all_item->signal_connect('activate' => sub {
my ($total, $choice);
$total = scalar $self->worldModelObj->preferBGColourList;
# If there's more than one colour, prompt the user for confirmation
if ($total > 1) {
$choice = $self->showMsgDialogue(
'Remove all colour buttons',
'question',
'Are you sure you want to remove all ' . $total . ' colour buttons?',
'yes-no',
);
} else {
$choice = 'yes';
}
if (defined $choice && $choice eq 'yes') {
# Reset the world model's list of preferred background colour...
$self->worldModelObj->reset_preferBGColourList();
# ...then redraw the window component containing the toolbar(s)
$self->redrawWidgets('toolbar');
}
});
$popupMenu->append($remove_all_item);
# Also add a 'Cancel' menu item, which does nothing
my $cancel_item = Gtk3::MenuItem->new('Cancel');
$cancel_item->signal_connect('activate' => sub {
return undef;
});
$popupMenu->append($cancel_item);
# Display the popup menu
$popupMenu->popup(
undef, undef, undef, undef,
1, # Left mouse button
Gtk3::get_current_event_time(),
);
$popupMenu->show_all();
# Operation complete. Now wait for the user's response
return 1;
}
# Treeview widget methods
sub enableTreeView {
# Called by $self->drawWidgets
# Sets up the Automapper window's treeview widget
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if the widget can't be created
# Otherwise returns the Gtk3::ScrolledWindow containing the Gtk3::TreeView created
my ($self, $check) = @_;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->enableTreeView', @_);
}
# Create the treeview
my $objectModel = Gtk3::TreeStore->new( ['Glib::String'] );
my $treeView = Gtk3::TreeView->new($objectModel);
if (! $objectModel || ! $treeView) {
return undef;
}
# No interactive searches required
$treeView->set_enable_search(FALSE);
# Append a single column to the treeview
$treeView->append_column(
Gtk3::TreeViewColumn->new_with_attributes(
'Regions',
Gtk3::CellRendererText->new,
markup => 0,
)
);
# Make the treeview scrollable
my $treeViewScroller = Gtk3::ScrolledWindow->new;
$treeViewScroller->add($treeView);
$treeViewScroller->set_policy(qw/automatic automatic/);
# Make the branches of the list tree clickable, so the rows can be expanded and collapsed
$treeView->signal_connect('row_activated' => sub {
my ($treeView, $path, $column) = @_;
$self->treeViewRowActivatedCallback();
});
lib/Games/Axmud/Win/Map.pm view on Meta::CPAN
$canvasFrame->set_border_width(3);
# Create a scrolled window
my $canvasScroller = Gtk3::ScrolledWindow->new();
my $canvasHAdjustment = $canvasScroller->get_hadjustment();
my $canvasVAdjustment = $canvasScroller->get_vadjustment();
$canvasScroller->set_border_width(3);
# Set the scrolling policy
$canvasScroller->set_policy('always','always');
# Add the scrolled window to the frame
$canvasFrame->add($canvasScroller);
# The only way to scroll the map to the correct position, is to store the scrolled window's
# size allocation whenever it is set
$canvasScroller->signal_connect('size-allocate' => sub {
my ($widget, $hashRef) = @_;
$self->ivPoke('canvasScrollerWidth', $$hashRef{width});
$self->ivPoke('canvasScrollerHeight', $$hashRef{height});
});
# Store the remaining widgets
$self->ivPoke('canvasFrame', $canvasFrame);
$self->ivPoke('canvasScroller', $canvasScroller);
$self->ivPoke('canvasHAdjustment', $canvasHAdjustment);
$self->ivPoke('canvasVAdjustment', $canvasVAdjustment);
# Set up tooltips
$self->enableTooltips();
# Draw the empty background map (default is white)
$self->resetMap();
# Setup complete
return $canvasFrame;
}
sub enableTooltips {
# Called by $self->enableCanvas (only)
# Sets up tooltips
#
# 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 . '->enableTooltips', @_);
}
# Create a Gtk3::Window to act as a tooltip, being visible (or not) as appropriate
my $tooltipLabel = Gtk3::Label->new();
my $tooltipWin = Gtk3::Window->new('popup');
$tooltipWin->set_decorated(FALSE);
$tooltipWin->set_position('mouse');
$tooltipWin->set_border_width(2);
$tooltipWin->modify_fg('normal', [Gtk3::Gdk::Color::parse('black')]->[1]);
$tooltipWin->modify_bg('normal', [Gtk3::Gdk::Color::parse('yellow')]->[1]);
$tooltipWin->add($tooltipLabel);
# Update IVs
$self->ivPoke('canvasTooltipObj', undef);
$self->ivPoke('canvasTooltipObjType', undef);
$self->ivPoke('canvasTooltipFlag', FALSE);
# Setup complete
return 1;
}
sub setMapPosn {
# Can be called by anything
# Scroll the canvas to the desired position, revealing a portion of the map
#
# Expected arguments
# $xPos - Value between 0 (far left) and 1 (far right)
# $yPos - Value between 0 (far top) and 1 (far bottom)
#
# Return values
# 'undef' on improper arguments or if there is no current regionmap
# 1 otherwise
my ($self, $xPos, $yPos, $check) = @_;
# Local variables
my ($canvasWidget, $xBlocks, $yBlocks, $xPixels, $yPixels, $scrollX, $scrollY);
# Check for improper arguments
if (! defined $xPos || ! defined $yPos || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->setMapPosn', @_);
}
# Do nothing if there is no current regionmap
if (! $self->currentRegionmap) {
return undef;
}
# Get the canvas widget to be scrolled
$canvasWidget = $self->currentParchment->ivShow(
'canvasWidgetHash',
$self->currentRegionmap->currentLevel,
);
# The code in this function, which uses GooCanvas2::Canvas->scroll_to, produces a slightly
# different value to the code in $self->getMapPosn, which uses scrollbar positions
# When moving up and down through map levels, this causes the scroll position to drift from
# its original position
# The only way to deal with this is to adjust $xPos and $yPos so that they represent the
# middle of a gridblock. In that way, the first change of level might adjust the map's
# scroll position (slightly), but subsequent changes preserve the exact same scroll
# position
lib/Games/Axmud/Win/Map.pm view on Meta::CPAN
# Continue the drag operation by re-drawing the object(s) at their new position
$self->continueDrag($event, $event->x_root, $event->y_root);
}
});
$canvasObj->signal_connect('enter_notify_event' => sub {
my ($item, $target, $event) = @_;
if ($modelObj && $self->worldModelObj->showTooltipsFlag && ! $self->canvasTooltipObj) {
# Show the tooltips window
$self->showTooltips($type, $canvasObj, $modelObj);
}
});
$canvasObj->signal_connect('leave_notify_event' => sub {
my ($item, $target, $event) = @_;
if (
$modelObj
&& $self->canvasTooltipFlag
&& $self->canvasTooltipObj eq $canvasObj
&& $self->canvasTooltipObjType eq $type
) {
# Hide the tooltips window
$self->hideTooltips();
}
});
# Setup complete
return 1;
}
sub canvasEventHandler {
# Handles events on the map background (i.e. clicking on an empty part of the background
# which doesn't contain a room, room tag, room guild, exit, exit tag, label, or checked
# direction)
# The calling function, an anonymous sub defined in $self->setupCanvasEvent, filters out the
# signals we don't want
# At the moment, the signals let through the filter are:
# button_press, 2button_press, 3button_press, button_release
#
# Expected arguments
# $canvasObj - The canvas object which intercepted an event signal
# $event - The Gtk3::Gdk::Event that caused the signal
#
# Return values
# 'undef' on improper arguments, if there is no region map or if the signal $event is one
# that this function doesn't handle
# 1 otherwise
my ($self, $canvasObj, $event, $check) = @_;
# Local variables
my (
$clickXPosPixels, $clickYPosPixels, $clickType, $button, $shiftFlag, $ctrlFlag,
$clickXPosBlocks, $clickYPosBlocks, $newRoomObj, $roomNum, $roomObj, $exitObj, $listRef,
$result, $twinExitObj, $result2, $popupMenu,
);
# Check for improper arguments
if (! defined $canvasObj || ! defined $event || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->canvasEventHandler', @_);
}
# Don't do anything if there is no current regionmap
if (! $self->currentRegionmap) {
return undef;
}
# In case the previous click on the canvas was a right-click on an exit, we no longer need
# the coordinates of the click
$self->ivUndef('exitClickXPosn');
$self->ivUndef('exitClickYPosn');
# Get the coordinates on the map of the clicked pixel. If the map is magnified we might get
# fractional values, so we need to use int()
($clickXPosPixels, $clickYPosPixels) = (int($event->x), int($event->y));
# For mouse button clicks, get the click type and whether or not the SHIFT and/or CTRL keys
# were held down
($clickType, $button, $shiftFlag, $ctrlFlag) = $self->checkMouseClick($event);
if (! $clickType) {
# Not an event in which we're interested
return undef;
}
# Work out which gridblock is underneath the mouse click
($clickXPosBlocks, $clickYPosBlocks) = $self->findGridBlock(
$clickXPosPixels,
$clickYPosPixels,
$self->currentRegionmap,
);
# If $self->freeClickMode and/or $self->bgColourMode aren't set to 'default', left-clicking
# on empty space causes something unusual to happen
if (
$clickType eq 'single'
&& $button eq 'left'
&& ($self->freeClickMode ne 'default' || $self->bgColourMode ne 'default')
) {
# Free click mode 'add_room' - 'Add room at click' menu option
# (NB If this code is altered, the equivalent code in ->enableCanvasPopupMenu must also
# be altered)
if ($self->freeClickMode eq 'add_room') {
# Only add one new room
$self->reset_freeClickMode();
$newRoomObj = $self->mapObj->createNewRoom(
$self->currentRegionmap,
$clickXPosBlocks,
$clickYPosBlocks,
$self->currentRegionmap->currentLevel,
);
lib/Games/Axmud/Win/Map.pm view on Meta::CPAN
# Free click mode 'add_label' - 'Add label at click' menu option
} elsif ($self->freeClickMode eq 'add_label') {
$self->addLabelAtClickCallback($clickXPosPixels, $clickYPosPixels);
# Only add one new label
$self->reset_freeClickMode();
# Free click mode 'move_room' - 'Move selected rooms to click' menu option
} elsif ($self->freeClickMode eq 'move_room') {
$self->moveRoomsToClick($clickXPosBlocks, $clickYPosBlocks);
# Only do it once
$self->reset_freeClickMode();
# Background colour mode 'square_start' (no menu option)
} elsif ($self->freeClickMode eq 'default' && $self->bgColourMode eq 'square_start') {
$self->setColouredSquare($clickXPosBlocks, $clickYPosBlocks);
# Background colour mode 'rect_start' (no menu option)
} elsif ($self->freeClickMode eq 'default' && $self->bgColourMode eq 'rect_start') {
# Store the coordinates of the click, and wait for the second click
$self->ivPoke('bgColourMode', 'rect_stop');
$self->ivPoke('bgRectXPos', $clickXPosBlocks);
$self->ivPoke('bgRectYPos', $clickYPosBlocks);
# Background colour mode 'rect_stop' (no menu option)
} elsif ($self->freeClickMode eq 'default' && $self->bgColourMode eq 'rect_stop') {
$self->setColouredRect($clickXPosBlocks, $clickYPosBlocks);
}
# Non-default operation complete
return 1;
}
# Otherwise, see if there's a room inside the gridblock that was clicked (if there is, we
# will be able to detect clicks near exits)
$roomNum = $self->currentRegionmap->fetchRoom(
$clickXPosBlocks,
$clickYPosBlocks,
$self->currentRegionmap->currentLevel,
);
if (defined $roomNum) {
$roomObj = $self->worldModelObj->ivShow('modelHash', $roomNum);
}
if ($roomObj && $clickType eq 'single' && $self->currentRegionmap->gridExitHash) {
# Usually, when we click on the map on an empty pixel, all selected objects are
# unselected
# However, because exits are often drawn only 1 pixel wide, they're quite difficult to
# click on. This section checks whether the mouse click occured close enough to an
# exit
# A left-click near an exit causes the exit to be selected/unselected. A right-click
# selects the exit (unselecting everything else) and opens a popup menu for that exit.
# If the click isn't close enough to an exit, the user is deemed to have clicked in
# open space
# (NB If no exits have been drawn, don't bother checking)
# Now we check if they clicked near an exit, or in open space
$exitObj = $self->findClickedExit(
$clickXPosPixels,
$clickYPosPixels,
$roomObj,
$self->currentRegionmap,
);
if ($exitObj) {
if ($button eq 'left' && $event->state =~ m/mod5-mask/) {
# This is a drag operation on the nearby exit
$listRef = $self->currentParchment->getDrawnExit($exitObj);
if (defined $listRef) {
$self->startDrag(
'exit',
$$listRef[0], # The exit's canvas object
$exitObj,
$event,
$clickXPosPixels,
$clickYPosPixels,
);
}
} elsif ($button eq 'left') {
# If this exit (and/or its twin) is a selected exit, unselect them
$result = $self->unselectObj($exitObj);
if ($exitObj->twinExit) {
$twinExitObj
= $self->worldModelObj->ivShow('exitModelHash', $exitObj->twinExit);
if ($twinExitObj) {
$result2 = $self->unselectObj($twinExitObj);
}
}
if (! $result && ! $result2) {
# The exit wasn't already selected, so select it
$self->setSelectedObj(
[$exitObj, 'exit'],
# Retain other selected objects if CTRL key held down
$ctrlFlag,
);
}
} elsif ($button eq 'right') {
# Select the exit, unselecting all other selected objects
$self->setSelectedObj(
[$exitObj, 'exit'],
FALSE, # Select this object; unselect all other objects
);
# Create the popup menu
if ($self->selectedExit) {
$popupMenu = $self->enableExitsPopupMenu();
if ($popupMenu) {
$popupMenu->popup(
undef, undef, undef, undef,
$event->button,
$event->time,
);
}
}
}
return 1;
}
}
# Otherwise, the user clicked in open space
# If it was a right-click, open a popup menu
if ($clickType eq 'single' && $button eq 'right') {
$popupMenu = $self->enableCanvasPopupMenu(
$clickXPosPixels,
$clickYPosPixels,
$clickXPosBlocks,
$clickYPosBlocks,
);
if ($popupMenu) {
$popupMenu->popup(
undef, undef, undef, undef,
$event->button,
$event->time,
);
}
# If it was a left-click, it's potentially a selection box operation
} elsif ($clickType eq 'single' && $button eq 'left') {
# The selection box isn't actually drawn until the user moves their mouse. If they
# release the button instead, at that point we unselect all selected objects
$self->startSelectBox($clickXPosPixels, $clickYPosPixels);
# If it's a mouse button release, handle the end of any selection box operation
} elsif ($clickType eq 'release' && $button eq 'left' && $self->selectBoxFlag) {
$self->stopSelectBox($event, $clickXPosPixels, $clickYPosPixels);
# Otherwise, if it's a button click (not a button release), just unselect all selected
# objects
} elsif ($clickType ne 'release') {
$self->setSelectedObj();
}
return 1;
}
sub canvasObjEventHandler {
# Handles events on canvas object (i.e. clicking on a room, room tag, room guild, exit,
# exit tag or label). Note that clicks on canvas objects for checked directions are
# ignored; they are not handled by this function nor by $self->canvasEventHandler
# The calling function, an anonymous sub defined in $self->setupCanvasObjEvent, filters out
# the signals we don't want
# At the moment, the signals let through the filter are:
# button_press, 2button_press
#
# Expected arguments
# $objType - 'room', 'room_tag', 'room_guild', 'exit', 'exit_tag' or 'label'
# $canvasObj - The canvas object which intercepted an event signal
# $modelObj - The GA::ModelObj::Room, GA::Obj::Exit or GA::Obj::MapLabel which is
# represented by this canvas object
# $event - The Gtk3::Gdk::Event that caused the signal
#
# Return values
# 'undef' on improper arguments or if the signal $event is one that this function doesn't
# handle
# 1 otherwise
my ($self, $objType, $canvasObj, $modelObj, $event, $check) = @_;
# Local variables
my (
$clickType, $button, $shiftFlag, $ctrlFlag, $selectFlag, $clickTime, $otherRoomObj,
$startX, $stopX, $startY, $stopY, $result, $twinExitObj, $result2, $popupMenu,
);
# Check for improper arguments
if (
! defined $objType || ! defined $canvasObj || ! defined $modelObj || ! defined $event
|| defined $check
) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->canvasObjEventHandler', @_);
}
# In case the previous click on the canvas was a right-click on an exit, we no longer need
# the coordinates of the click
$self->ivUndef('exitClickXPosn');
$self->ivUndef('exitClickYPosn');
# If $self->freeClickMode has been set to 'add_room' or 'add_label' by the 'Add room at
# click' or 'Add label at click' menu options, since this part of the grid is already
# occupied, we can go back to normal
if ($self->freeClickMode eq 'add_room' || $self->freeClickMode eq 'add_label') {
$self->reset_freeClickMode();
}
# For mouse button clicks, get the click type and whether or not the SHIFT and/or CTRL keys
# were held down
($clickType, $button, $shiftFlag, $ctrlFlag) = $self->checkMouseClick($event);
if (! $clickType) {
# Not an event in which we're interested
return undef;
}
# Various parts of the function check that these hashes contain at least one item between
# them
if (
$self->selectedRoomHash || $self->selectedRoomTagHash || $self->selectedRoomGuildHash
|| $self->selectedExitHash || $self->selectedExitTagHash || $self->selectedLabelHash
) {
$selectFlag = TRUE;
}
# For capturing double-clicks on rooms, we need to compare the times at which each click is
# received
$clickTime = $axmud::CLIENT->getTime();
# Process single left clicks
if ($clickType eq 'single' && $button eq 'left') {
# Process a left-clicked room differently, if ->freeClickMode has been set to
# 'connect_exit' by the 'Connect to click' menu option (ignoring the SHIFT/CTRL keys)
if ($self->freeClickMode eq 'connect_exit' && $objType eq 'room') {
# Occasionally get an error, when there's no selected exit. $self->freeClickMode
# should get reset, but not in these situations
if (! $self->selectedExit) {
$self->reset_freeClickMode();
} else {
lib/Games/Axmud/Win/Map.pm view on Meta::CPAN
);
}
}
}
# Process right-clicks
} elsif ($clickType eq 'single' && $button eq 'right') {
if ($objType eq 'exit') {
# For twin exits - which share a canvas object - use the exit whose parent room is
# closest to the click
$modelObj = $self->chooseClickedExit($modelObj, int($event->x), int($event->y));
}
# If a group of things are already selected, unselect them all and select the object
# that was clicked
if ($selectFlag) {
# Select this room/label, unselecting all other objects
$self->setSelectedObj(
[$modelObj, $objType],
# Retain other selected objects if CTRL key held down
$ctrlFlag,
);
} else {
# If this object isn't already selected, select it (but don't unselect something
# as we would for a left-click)
if ($objType eq 'room_tag') {
$self->setSelectedObj(
[$modelObj, 'room_tag'],
FALSE, # Select this object; unselect all other objects
);
} elsif ($objType eq 'room_guild') {
$self->setSelectedObj(
[$modelObj, 'room_guild'],
FALSE, # Select this object; unselect all other objects
);
} elsif ($objType eq 'exit_tag') {
$self->setSelectedObj(
[$modelObj, 'exit_tag'],
FALSE, # Select this object; unselect all other objects
);
} else {
$self->setSelectedObj(
[$modelObj, $objType],
FALSE, # Select this object; unselect all other objects
);
}
}
# Create the popup menu
if ($objType eq 'room' && $self->selectedRoom) {
$popupMenu = $self->enableRoomsPopupMenu();
} elsif ($objType eq 'room_tag' && $self->selectedRoomTag) {
$popupMenu = $self->enableRoomTagsPopupMenu();
} elsif ($objType eq 'room_guild' && $self->selectedRoomGuild) {
$popupMenu = $self->enableRoomGuildsPopupMenu();
} elsif ($objType eq 'exit_tag' && $self->selectedExitTag) {
$popupMenu = $self->enableExitTagsPopupMenu();
} elsif ($objType eq 'exit' && $self->selectedExit) {
# Store the position of the right-click, in case the user wants to add a bend from
# the popup menu
$self->ivPoke('exitClickXPosn', int($event->x));
$self->ivPoke('exitClickYPosn', int($event->y));
# Now we can open the poup menu
$popupMenu = $self->enableExitsPopupMenu();
} elsif ($objType eq 'label' && $self->selectedLabel) {
$popupMenu = $self->enableLabelsPopupMenu();
}
if ($popupMenu) {
$popupMenu->popup(undef, undef, undef, undef, $event->button, $event->time);
}
}
return 1;
}
sub deleteCanvasObj {
# Called by numerous functions
#
# When a region object, room object, room tag, room guild, exit, exit tag or label is being
# drawn, redrawn or deleted from the world model, this function must be called
# The function checks whether the model object is currently drawn on a map as one or more
# canvas objects and, if it is, destroys the canvas objects
#
# This function also handles coloured blocks and rectangles on the background map, details
# of which are stored in the regionmap object (GA::Obj::Regionmap), not the world model
# The function checks whether a canvas object for the coloured block/rectangle is currently
# displayed on the map as a canvas object and, if so, destroys the canvas object
#
# Expected arguments
# $type - Set to 'region', 'room', 'room_tag', 'room_guild', 'exit', 'exit_tag' or
# 'label' for world model objects, 'checked_dir' for checked directions
# and 'square', 'rect' for coloured blocks/rectangles
# $modelObj - The GA::ModelObj::Region, GA::ModelObj::Room, GA::Obj::Exit or
# GA::Obj::MapLabel being drawn /redrawn / deleted
# - For checked directions, the GA::ModelObj::Room in which the checked
# direction is stored
# - For coloured squares, it's not a blessed reference, but a coordinate in
# the form 'x_y' (to delete canvas objects on all levels), or 'x_y_z' (to
# delete the canvas object on one level)
# - For coloured rectangles, it's not a blessed reference, but a key in the
# form 'object-number' (to delete canvas objects on all levels), or
# 'object-number_level' (to delete the canvas object on one level)
#
# Optional arguments
# $regionmapObj, $parchmentObj
# - The regionmap and parchment object for $modelObj. If not set, this
# function fetches them. Both must be specified if $type is 'square' or
# 'rect')
# $deleteFlag - Set to TRUE if the object is being deleted from the world model, FALSE
# (or 'undef') if not. Never TRUE for coloured blocks/rectangles which
# are not stored in the world model
#
# Return values
# 'undef' on improper arguments, if there's an error or if there are no canvas objects to
# destroy
# 1 otherwise
my ($self, $type, $modelObj, $regionmapObj, $parchmentObj, $deleteFlag, $check) = @_;
# Local variables
my (
$roomObj,
@redrawList,
%redrawHash,
);
# Check for improper arguments
if (! defined $type || ! defined $modelObj || defined $check) {
lib/Games/Axmud/Win/Map.pm view on Meta::CPAN
my $exitObj = $self->worldModelObj->ivShow('exitModelHash', $exitNum);
if ($exitObj->superFlag) {
$exitCount++;
}
}
# If there are ten super-region exits, each individual exit has nine region paths
# joining it to every other super-region exit. We then double the number, because
# safe region paths are stored separately. So the estimated number of region
# paths is ((n-1) ^ 2 ), all multiplied by 2
$estimate += (2 * (($exitCount - 1) ** 2));
}
# If the estimated number of paths is above the limit set by the world model, make the
# pause window visible for the duration of the recalculation
if ($estimate > $self->worldModelObj->recalculatePauseNum) {
$self->showPauseWin();
}
# Recalculate region paths for each region added to our list
$count = 0;
foreach my $regionmapObj (@regionmapList) {
my $number = $self->worldModelObj->recalculateRegionPaths(
$self->session,
$regionmapObj,
);
if ($number) {
$count += $number;
}
}
# Make the pause window invisible
$self->hidePauseWin();
} else {
# Recalculate paths to/from the selected exit.
$count = $self->worldModelObj->recalculateSpecificPaths(
$self->session,
$self->currentRegionmap,
$self->selectedExit,
);
# In case the called function returns 'undef', $count still needs to be an integer
if (! $count) {
$count = 0;
}
# For the message we're about to compose, @regionmapList must contain the affected
# regionmap
push (@regionmapList, $self->currentRegionmap);
}
# Display a popup showing the results
$msg = 'Recalculation complete: ';
if (! $count) {
$msg .= 'no region paths found';
} elsif ($count == 1) {
$msg .= '1 region path found';
} else {
$msg .= $count . ' region paths found';
}
if (@regionmapList == 1) {
$msg .= ' in 1 region.';
} else {
$msg .= ' in ' . scalar @regionmapList . ' regions.';
}
$self->showMsgDialogue(
'Recalculate region paths',
'info',
$msg,
'ok',
);
return 1;
}
sub locateCurrentRoomCallback {
# Called by $self->enableRegionsColumn
# Tries to find the current room by comparing the Locator task's current room with every
# room in the current region, in a specified region, or in all regions
# If there's a single matching room, that room is set as the current room. If the single
# matching room is in a different region or level to the current one, the map is redrawn
# If there are multiple matching rooms, those rooms are selected. If they are all in a
# different region or at a different level to the current one, the map is redrawn
#
# Expected arguments
# $type - Where to search: 'current' for the current regionmap, 'select' to prompt the
# user for a regionmap, or 'all' to search in all regionmaps
#
# Return values
# 'undef' on improper arguments, if the standard callback check fails, if there is no
# current regionmap, or if there is no Locator task (or the task doesn't know the
# current location), if the Locator's current room is dark or unspecified or if the
# user declines to continue
# 1 otherwise
my ($self, $type, $check) = @_;
# Local variables
my (
$taskObj, $msg, $regionName, $regionmapObj, $choice, $matchObj, $regionObj,
@roomList, @list, @regionList, @selectList, @modList, @newRegionList, @sortedList,
%regionmapHash,
);
# Check for improper arguments
if (
! defined $type || ($type ne 'current' && $type ne 'select' && $type ne 'all')
|| defined $check
lib/Games/Axmud/Win/Map.pm view on Meta::CPAN
# Called by $self->enableRoomsColumn (also called by GA::Cmd::Go->do)
# Performs the A* algorithm to find a path between the current room and the selected room,
# and then does something with it
#
# Expected arguments
# $mode - Set to one of the following:
# 'select_room' - shows the path by selecting every room along the route
# 'pref_win' - shows the path in a 'pref' window, allowing the user to store
# it as a pre-defined route (using the ';addroute' command)
# 'send_char' - sends the character to the selected room
#
# Return values
# 'undef' on improper arguments, if the standard callback check fails or if no path can be
# found between the current and selected rooms
# 1 otherwise
my ($self, $mode, $check) = @_;
# Local variables
my (
$dictObj, $text, $count, $maxChars, $string, $lastExitObj, $roomListRef, $exitListRef,
$response,
@roomList, @exitList, @cmdList, @reverseCmdList, @highlightList, @modList,
);
# Check for improper arguments
if (
! defined $mode
|| ($mode ne 'select_room' && $mode ne 'pref_win' && $mode ne 'send_char')
|| defined $check
) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->processPathCallback', @_);
}
# Standard callback check
if (
! $self->currentRegionmap
|| ! $self->mapObj->currentRoom
|| ! $self->selectedRoom
|| $self->mapObj->currentRoom eq $self->selectedRoom
) {
return undef;
}
# Import the current dictionary (for speed)
$dictObj = $self->session->currentDict;
# Use the universal version of the A* algorithm to find a path between the current and
# selected rooms (if they're in the same region, the call is automatically redirected to
# ->findPath)
($roomListRef, $exitListRef) = $self->worldModelObj->findUniversalPath(
$self->session,
$self->mapObj->currentRoom,
$self->selectedRoom,
$self->worldModelObj->avoidHazardsFlag,
);
if (! defined $roomListRef || ! @$roomListRef) {
# There is no path between the current and selected room. Notify the user with a popup
$self->showMsgDialogue(
'No path found',
'warning',
'There is no known path between the current room (#'
. $self->mapObj->currentRoom->number . ') and the selected room (#'
. $self->selectedRoom->number . ')',
'ok',
);
return undef;
}
# Apply post-processing to the path to remove jagged edges (if allowed)
if ($self->worldModelObj->postProcessingFlag) {
($roomListRef, $exitListRef) = $self->worldModelObj->smoothPath(
$self->session,
$roomListRef,
$exitListRef,
$self->worldModelObj->avoidHazardsFlag,
);
}
# Convert the list references returned by the called functions into lists
@roomList = @$roomListRef;
@exitList = @$exitListRef;
# Compile a list of commands to get from one end of the route to the other. If assisted
# moves are turned on, use them; otherwise, use each exit's nominal direction
# At the same time, try to compile a list of directions that lead from the end of the
# route back to the start
@cmdList = $self->worldModelObj->convertExitList($self->session, @exitList);
# Attempt to find the reverse list of directions, if possible (but only bother in
# 'select_room' mode)
if ($mode eq 'pref_win') {
@reverseCmdList = $self->worldModelObj->findPathCmds($self->session, -1, @roomList);
}
# 'select_room' - select each room in the path, in order to highlight the route (but don't
# select the current room)
# 'pref_win' - show the route/reverse route in a 'pref' window
if ($mode eq 'select_room' || $mode eq 'pref_win') {
foreach my $roomObj (@roomList) {
if ($roomObj ne $self->mapObj->currentRoom) {
push (@highlightList, $roomObj, 'room');
}
}
$self->setSelectedObj(
\@highlightList,
TRUE, # Select multiple objects, including the currently selected room
);
}
# 'pref_win' - show the route/reverse route in a 'pref' window, allowing the user to store
# it as a pre-defined route (using the ';addroute' command)
lib/Games/Axmud/Win/Map.pm view on Meta::CPAN
@reducedList = @sortedList;
}
# Prepare the message to show in the window
if ($self->mapObj->currentRoom) {
$msg = "Current room:\n";
$msg .= " #" . $self->mapObj->currentRoom->number . " '";
# '<unnamed room>' will cause a Pango error, so replace that string
# GA::ModelObj::Room->name has already been cut down to a maximum of 32 characters. By
# checking for a length longer than 31, we can be certain we're not adding an ellipsis
# to a room title that was exactly 32 characters long
$roomName = $self->mapObj->currentRoom->name;
if ($roomName eq '<unnamed room>') {
$roomName = '(unnamed room)';
} elsif (length($roomName) > 31) {
$roomName = substr($roomName, 0, 29) . '...';
}
$msg .= $roomName . "'\n\n";
} else {
$msg = '';
}
if (@reducedList) {
if (scalar @sortedList != scalar @reducedList) {
$msg .= "Selected rooms (first " . $limit . " rooms of " . scalar @sortedList
. ")";
} elsif (scalar @sortedList == 1) {
$msg .= "Selected rooms (1 room)";
} else {
$msg .= "Selected rooms (" . scalar @sortedList . " rooms)";
}
foreach my $obj (@reducedList) {
my $roomName;
$msg .= "\n #" . $obj->number . " '";
$roomName = $obj->name;
if ($roomName eq '<unnamed room>') {
$roomName = '(unnamed room)';
} elsif (length($roomName) > 31) {
$roomName = substr($roomName, 0, 29) . '...';
}
$msg .= $roomName . "'";
}
}
# Display a popup to show the results
$self->showMsgDialogue(
'Identify rooms',
'info',
$msg,
'ok',
undef,
TRUE, # Preserve newline characters in $msg
);
return 1;
}
sub updateVisitsCallback {
# Called by $self->enableRoomsColumn, ->enableRoomsPopupMenu and ->drawMiscButtonSet
# Adjusts the number of character visits shown in the selected room(s)
# Normally, the current character's visits are changed. However, if $self->showChar is set,
# that character's visits are changed
#
# Expected arguments
# $mode - 'increase' to increase the number of visits by one, 'decrease' to decrease the
# visits by one, 'manual' to let the user enter a value manually, 'reset' to
# reset the number to zero
#
# Return values
# 'undef' on improper arguments, if the standard callback check fails, if the user clicks
# the 'cancel' button on a 'dialogue' window or for any other error
# 1 otherwise
my ($self, $mode, $check) = @_;
# Local variables
my (
$char, $current, $result, $matchFlag,
@roomList, @drawList,
);
# Check for improper arguments
if (
! defined $mode
|| ($mode ne 'increase' && $mode ne 'decrease' && $mode ne 'manual' && $mode ne 'reset')
|| defined $check
) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->updateVisitsCallback', @_);
}
# Standard callback check
if (! $self->currentRegionmap || (! $self->selectedRoom && ! $self->selectedRoomHash)) {
return undef;
}
# Get a list of selected room(s)
@roomList = $self->compileSelectedRooms();
# Decide which character to use
if ($self->showChar) {
$char = $self->showChar;
lib/Games/Axmud/Win/Map.pm view on Meta::CPAN
@sortedList, @reducedList,
);
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->identifyExitsCallback', @_);
}
# Standard callback check
if (! $self->currentRegionmap || (! $self->selectedExit && ! $self->selectedExitHash)) {
return undef;
}
# Compile a list of selected exits and sort by exit model number
@sortedList = sort {$a->number <=> $b->number} ($self->compileSelectedExits());
# Reduce the size of the list to a maximum of $limit
$limit = 10;
if (@sortedList > $limit) {
@reducedList = @sortedList[0..($limit - 1)];
} else {
@reducedList = @sortedList;
}
# Prepare the message to show in the 'dialogue' window
if (scalar @sortedList != scalar @reducedList) {
$msg = "Selected exits (first " . $limit . " exits of " . scalar @sortedList . ")\n";
} elsif (scalar @sortedList == 1) {
$msg = "Selected exits (1 exit)\n";
} else {
$msg = "Selected exits (" . scalar @sortedList . " exits)\n";
}
foreach my $exitObj (@reducedList) {
my $customDir;
# Convert the exit's map direction, ->mapDir (a standard primary direction) into a
# custom primary direction, so that we can compare it with the exit's nominal
# direction
$customDir = $self->session->currentDict->ivShow('primaryDirHash', $exitObj->mapDir);
if (! $customDir || $customDir eq $exitObj->dir) {
$msg .= " #" . $exitObj->number . " '" . $exitObj->dir . "' (room #"
. $exitObj->parent . ")\n";
} else {
$msg .= " #" . $exitObj->number . " '" . $exitObj->dir . "' [" . $exitObj->mapDir
. "] (room #" . $exitObj->parent . ")\n";
}
}
# Display a popup to show the results
$self->showMsgDialogue(
'Identify exits',
'info',
$msg,
'ok',
undef,
TRUE, # Preserve newline characters in $msg
);
return 1;
}
sub editExitCallback {
# Called by $self->enableExitsColumn
# Opens a GA::EditWin::Exit for the selected exit. If the selected exit could be confused
# with others occupying (roughly) the same space, opens a 'dialogue' window so the user
# can choose one
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments or if the standard callback check fails
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my (
$comboListRef, $exitHashRef, $choice, $exitObj,
@comboList,
%exitHash,
);
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->editExitCallback', @_);
}
# Standard callback check
if (! $self->currentRegionmap || ! $self->selectedExit) {
return undef;
}
# If the selected exit has a twin exit and/or a shadow exit, we need to prompt the user to
# ask which of them should be edited
if ($self->selectedExit->twinExit || $self->selectedExit->shadowExit) {
($comboListRef, $exitHashRef) = $self->compileExitList();
if (! defined $comboListRef) {
return undef;
}
@comboList = @$comboListRef;
%exitHash = %$exitHashRef;
lib/Games/Axmud/Win/Map.pm view on Meta::CPAN
($stringListRef, $exitHashRef) = $self->compileExitList();
if (! defined $stringListRef) {
return undef;
}
@stringList = @$stringListRef;
%exitHash = %$exitHashRef;
# If there is more than one exit in the list, prompt the user to specify which one to delete
if (scalar @stringList > 1) {
# Compile the combo list
if (@stringList == 2) {
@comboList = ($bothString, @stringList);
} elsif (@stringList > 2) {
@comboList = ($allString, @stringList);
} else {
@comboList = @stringList;
}
# Prompt the user to choose which exit to delete
$choice = $self->showComboDialogue(
'Select exit',
'Select which exit to delete',
\@comboList,
);
if (! $choice) {
return undef;
} elsif ($choice eq $bothString || $choice eq $allString) {
@finalList = values %exitHash;
} else {
push (@finalList, $exitHash{$choice});
}
} else {
# There's only one exit on which to operate
push (@finalList, $self->selectedExit);
}
# Delete the exit object(s) and instruct the world model to update its Automapper windows
$self->worldModelObj->deleteExits(
$self->session,
TRUE, # Update Automapper windows now
@finalList,
);
return 1;
}
sub addBendCallback {
# Called by $self->enableExitsPopupMenu (only)
# After a right-click on an exit, when the user has selected 'add bend' in the popup menu,
# add a bend at the same position
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments, if the standard callback check fails or if the bend is
# not added
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my (
$startXPos, $startYPos, $clickXPos, $clickYPos, $stopXPos, $stopYPos, $resultType,
$twinExitObj,
);
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->addBendCallback', @_);
}
# Standard callback check
if (
! $self->currentRegionmap
|| ! $self->selectedExit
|| (! $self->selectedExit->oneWayFlag && ! $self->selectedExit->twinExit)
|| $self->selectedExit->regionFlag
|| ! defined $self->exitClickXPosn
|| ! defined $self->exitClickYPosn
) {
return undef;
}
# Get the absolute coordinates of the start of the middle (bending) section of the
# exit
# At the same time, convert the absolute coordinates of the right-mouse click on the exit,
# and the absolute coordinates of the end of the bending section, into coordinates
# relative to the start of the bending section of the eixt
($startXPos, $startYPos, $clickXPos, $clickYPos, $stopXPos, $stopYPos, $resultType)
= $self->findExitClick(
$self->selectedExit,
$self->exitClickXPosn,
$self->exitClickYPosn,
);
# If the click wasn't in the parent room's gridblock, in the destination room's gridblock
# or too close to an existing bend...
if (! $resultType) {
# Add a bend to the exit
$self->worldModelObj->addExitBend(
FALSE, # Don't update Automapper windows yet
$self->selectedExit,
$startXPos, $startYPos,
$clickXPos, $clickYPos,
$stopXPos, $stopYPos,
);
# Repeat the process for the selected exit's twin (if there is one)
if ($self->selectedExit->twinExit) {
$twinExitObj = $self->worldModelObj->ivShow(
'exitModelHash',
$self->selectedExit->twinExit,
);
($startXPos, $startYPos, $clickXPos, $clickYPos, $stopXPos, $stopYPos)
= $self->findExitClick(
$twinExitObj,
$self->exitClickXPosn,
$self->exitClickYPosn,
);
$self->worldModelObj->addExitBend(
FALSE, # Don't update Automapper windows yet
$twinExitObj,
$startXPos, $startYPos,
$clickXPos, $clickYPos,
$stopXPos, $stopYPos,
);
}
# Now we can redraw the exit
$self->worldModelObj->updateMapExit(
$self->selectedExit,
$twinExitObj, # May be 'undef'
);
return 1;
} else {
# If the click was too close to an existing bend, show a message explaining why nothing
# has happened (don't bother showing a message for other values of $resultType, which
# probably can't be returned to this function anyway)
if ($resultType eq 'near_bend') {
$self->showMsgDialogue(
'Add bend',
'error',
'Cannot add a bend - you clicked too close to an existing bend',
'ok',
);
}
return undef;
}
}
sub removeBendCallback {
# Called by $self->enableExitsPopupMenu (only)
# After a right-click on an exit, when the user has selected 'remove bend' in the popup
# menu, remove the bend closest to the clicked position
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments, if the standard callback check fails or if the mouse
# click was not near a bend
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my ($index, $twinExitObj);
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->removeBendCallback', @_);
}
# Standard callback check
if (
! $self->currentRegionmap
|| ! $self->selectedExit
|| (! $self->selectedExit->oneWayFlag && ! $self->selectedExit->twinExit)
|| ! $self->selectedExit->bendOffsetList
|| ! defined $self->exitClickXPosn
|| ! defined $self->exitClickYPosn
) {
return undef;
}
# Find the number of the bend which is closest to the the clicked position
$index = $self->findExitBend(
$self->selectedExit,
$self->exitClickXPosn,
$self->exitClickYPosn,
);
if (! defined $index) {
$self->showMsgDialogue(
'Remove bend',
'error',
'Please right-click on the bend that you want to remove',
'ok',
);
return undef;
} else {
# Remove this bend
$self->worldModelObj->removeExitBend(
$self->session,
TRUE, # Update Automapper windows now
$self->selectedExit,
$index, # Remove this bend (first bend is numbered 0)
);
lib/Games/Axmud/Win/Map.pm view on Meta::CPAN
if ($exitMode eq 'no_exit') {
# Draw exit mode 'no_exit': The room takes up the whole gridblock
($startX, $startY) = (0, 0);
} else {
# Draw exit mode 'simple_exit'/'complex_exit': The room takes up the central part of the
# gridblock
($startX, $startY) = $self->getBorderCorner(
0, # $roomObj->xPosBlocks,
0, # $roomObj->yPosBlocks,
0, # $blockCornerXPosPixels,
0, # $blockCornerYPosPixels,
$self->currentRegionmap,
);
}
# Find the coordinates of the pixel at the bottom-right of the room's border
if ($exitMode eq 'no_exit') {
# Delete 2 pixels to allow a 1-pixel border on each side of the room box; otherwise,
# the room's borders touch and will look like double-width lines
$stopX = $startX + $self->currentRegionmap->blockWidthPixels - 3;
$stopY = $startY + $self->currentRegionmap->blockHeightPixels - 3;
# In draw exit modes 'simple_exit'/'complex_exit', the room takes up the middle part of the
# gridblock
} else {
$stopX = $startX + $self->currentRegionmap->roomWidthPixels - 1;
$stopY = $startY + $self->currentRegionmap->roomHeightPixels - 1;
}
# The mouse button was released over a gridblock containing a suitable room. Was the mouse
# over the room itself, or in the surrounding empty space?
if (
$clickXPosPixels >= (
$startX + ($xBlocks * $self->currentRegionmap->blockWidthPixels)
) && $clickXPosPixels <= (
$stopX + ($xBlocks * $self->currentRegionmap->blockWidthPixels)
) && $clickYPosPixels >= (
$startY + ($yBlocks * $self->currentRegionmap->blockHeightPixels)
) && $clickYPosPixels <= (
$stopY + ($yBlocks * $self->currentRegionmap->blockHeightPixels)
)
) {
# Mouse button was released over a suitable destination room
return $destRoomObj;
} else {
# Mouse button was not release over a suitable destination room
return undef;
}
}
sub findExitClick {
# Called by $self->addBendCallback and ->findExitBend
# After a right-click on an exit, when the user has selected 'add bend' in the popup menu,
# find the position of the click relative to the start of the middle (bending) section of
# the drawn exit (the bending section starts at the same position, that an uncertain exit
# would end). Returns the relative position of the click, as well as the absolute
# position of the start and end of the bending section
# (When called by ->findExitBend, process a left-mouse click)
#
# Expected arguments
# $exitObj - The exit that was right-clicked
# $clickXPos, $clickYPos - The position of the mouse click on the canvas
#
# Return values
# An empty list on improper arguments or if the relative coordinates can't be found
# Otherwise returns a list of coordinates in the form
# (
# start_section_x, start_section_y,
# mouse_click_x, mouse_click_y,
# end_section_x, end_section_y,
# result_type,
# )
# ...where 'start_section_x', 'start_section_y' are absolute coordinates of the start
# of the bending section, and where 'mouse_click_x', 'mouse_click_y', 'end_section_x'
# and 'end_section_y' are coordinates relative to the start, and 'result_type' gives
# more information about the click:
#
# 'parent_block' if the click took place in the parent room's gridblock
# 'dest_block' if the click took place in the destination room's gridblock
# 'near_bend' if the click took place close enough to an existing bend, that no
# additional bend can be added there
# 'undef' otherwise
my ($self, $exitObj, $clickXPos, $clickYPos, $check) = @_;
# Local variables
my (
$mapDir, $exitMode, $roomObj, $xPos, $yPos, $posnListRef, $destRoomObj, $destXPos,
$destYPos, $oppDir, $oppPosnListRef, $resultType, $bendSize,
@emptyList, @returnList, @offsetList,
);
# Check for improper arguments
if (! defined $exitObj || ! defined $clickXPos || ! defined $clickYPos || defined $check) {
$axmud::CLIENT->writeImproper($self->_objClass . '->findExitClick', @_);
return @emptyList;
}
# Fetch the equivalent primary direction (the direction in which the exit is drawn on the
# map)
$mapDir = $exitObj->mapDir;
if (! $mapDir) {
return @emptyList;
}
# Get the current exit drawing mode. GA::Obj::WorldModel->drawExitMode is one of the values
# 'ask_regionmap', 'no_exit', 'simple_exit' and 'complex_exit'. The regionmap's
# ->drawExitMode is any of those values except 'ask_regionmap'
if ($self->worldModelObj->drawExitMode eq 'ask_regionmap') {
$exitMode = $self->currentRegionmap->drawExitMode;
} else {