Games-Axmud

 view release on metacpan or  search on metacpan

lib/Games/Axmud/Table.pm  view on Meta::CPAN

            # Use TRUE or FALSE flags
            if (! $expandFlag) {
                $expandFlag = FALSE;
            } else {
                $expandFlag = TRUE;
            }

            if (! $fillFlag) {
                $fillFlag = FALSE;
            } else {
                $fillFlag = TRUE;
            }

            # Check $spacing is an integer, or use a default value
            if (! defined $spacing || ! $axmud::CLIENT->intCheck($spacing, 0)) {

                $spacing = 0;
            }

            $self->packingBox2->pack_end($widget, $expandFlag, $fillFlag, $spacing);

            return 1;

        } else {

            # Can't pack the widget if the main container widget already contains something
            if ($self->packingBox2->get_children()) {

                return undef;
            }

            if ($self->type eq 'scroll') {
                $self->packingBox2->add_with_viewport($widget);
            } else {
                $self->packingBox2->add($widget);
            }

            return 1;
        }
    }

    sub remove {

        # Can be called by anything to remove a widget from the main container widget
        #
        # Expected arguments
        #   $widget     - The Gtk3 widget to remove from the main container widget
        #
        # Return values
        #   'undef' on improper arguments
        #   1 otherwise

        my ($self, $widget, $check) = @_;

        # Check for improper arguments
        if (! defined $widget || defined $check) {

             return $axmud::CLIENT->writeImproper($self->_objClass . '->remove', @_);
        }

        return $axmud::CLIENT->desktopObj->removeWidget($self->packingBox2, $widget);
    }

    sub empty {

        # Can be called by anything to remove all widgets from the main container widget
        #
        # 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 . '->empty', @_);
        }

        foreach my $child ($self->packingBox2->get_children()) {

            $self->packingBox2->remove($child);
        }

        return 1;
    }

    ##################
    # Accessors - set

    sub set_equal {

        my ($self, $flag, $check) = @_;

        # Check for improper arguments
        if (! defined $flag || defined $check) {

            return $axmud::CLIENT->writeImproper($self->_objClass . '->set_equal', @_);
        }

        if ($self->type ne 'horizontal' && $self->type ne 'vertical') {

            return undef;
        }

        if (! $flag) {

            $self->packingBox2->set_column_homogeneous(FALSE);
            $self->packingBox2->set_row_homogeneous(FALSE);

        } else {

            $self->packingBox2->set_column_homogeneous(TRUE);
            $self->packingBox2->set_row_homogeneous(TRUE);
        }

        return 1;
    }

lib/Games/Axmud/Table.pm  view on Meta::CPAN


#   sub setWidgetsIfSession {}      # Inherited from GA::Generic::Table

#   sub setWidgetsChangeSession {}  # Inherited from GA::Generic::Table

#   sub setWidgetsOnResize {}       # Inherited from GA::Generic::Table

    # ->signal_connects

    # Other functions

    sub pack {

        # Can be called by anything to add a widget to the mini-table
        # Unlike GA::Strip::Table, this code doesn't perform any checks; the widget is added
        #   regardless of any existing widgets that are already on the table
        #
        # Expected arguments
        #   $widget     - The Gtk3 widget to add to the main container widget
        #   $left, Right, $top, $bottom
        #               - The table coordinates to use
        #
        # Return values
        #   'undef' on improper arguments
        #   1 on success

        my ($self, $widget, $left, $right, $top, $bottom, $check) = @_;

        # Check for improper arguments
        if (
            ! defined $widget || ! defined $left || ! defined $right || ! defined $top
            || ! defined $bottom || defined $check
        ) {
             return $axmud::CLIENT->writeImproper($self->_objClass . '->pack', @_);
        }

        $self->packingBox2->attach($widget, $left, $right, $top, $bottom);

        return 1;
    }

    sub remove {

        # Can be called by anything to remove a widget from the mini-table
        #
        # Expected arguments
        #   $widget     - The Gtk3 widget to remove from the mini-table
        #
        # Return values
        #   'undef' on improper arguments
        #   1 otherwise

        my ($self, $widget, $check) = @_;

        # Check for improper arguments
        if (! defined $widget || defined $check) {

             return $axmud::CLIENT->writeImproper($self->_objClass . '->remove', @_);
        }

        return $axmud::CLIENT->desktopObj->removeWidget($self->packingBox2, $widget);
    }

    sub empty {

        # Can be called by anything to remove all widgets from the mini-table
        #
        # 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 . '->empty', @_);
        }

        foreach my $child ($self->packingBox2->get_children()) {

            $self->packingBox2->remove($child);
        }

        return 1;
    }

    ##################
    # Accessors - set

    sub set_equal {

        my ($self, $colFlag, $rowFlag, $check) = @_;

        # Check for improper arguments
        if (defined $check) {

            return $axmud::CLIENT->writeImproper($self->_objClass . '->set_homo', @_);
        }

        if ($self->type ne 'horizontal' && $self->type ne 'vertical') {

            return undef;
        }

        if (! $colFlag) {
            $self->packingBox2->set_column_homogeneous(FALSE);
        } else {
            $self->packingBox2->set_column_homogeneous(TRUE);
        }

        if (! $rowFlag) {
            $self->packingBox2->set_row_homogeneous(FALSE);
        } else {
            $self->packingBox2->set_row_homogeneous(TRUE);
        }

        return 1;

lib/Games/Axmud/Table.pm  view on Meta::CPAN

        if (! defined $text) {

            $text = '';
        }

        $editFlag = $self->testFlag($self->ivShow('initHash', 'edit_flag'));
        $systemFlag = $self->testFlag($self->ivShow('initHash', 'system_flag'));
        $colourScheme = $self->ivShow('initHash', 'colour_scheme');
        $spacing = $self->testInt($self->ivShow('initHash', 'spacing'), 0, 0);
        $hExpandFlag = $self->testFlag($self->ivShow('initHash', 'expand_horizontal_flag'));
        $vExpandFlag = $self->testFlag($self->ivShow('initHash', 'expand_vertical_flag'));

        # Create packing box(es)
        my ($packingBox, $packingBox2) = $self->setupPackingBoxes(Gtk3::Grid->new());

        # Create the Gtk3::TextView inside a Gtk3::Frame and Gtk3::ScrolledWindow. However, if
        #   $packingBox is itself a Gtk3::Frame, don't create a second one
        my ($frame, $scroll);
        if (! $packingBox->isa('Gtk3::Frame')) {

            $frame = Gtk3::Frame->new(undef);
            $packingBox2->attach($frame, 0, 0, 1, 1);
            $frame->set_border_width($spacing);

            $scroll = Gtk3::ScrolledWindow->new(undef, undef);
            $frame->add($scroll);

        } else {

            $scroll = Gtk3::ScrolledWindow->new(undef, undef);
            $packingBox2->attach($scroll, 0, 0, 1, 1);
        }

        $scroll->set_shadow_type($axmud::CLIENT->constShadowType);
        $scroll->set_policy('automatic', 'automatic');
        $scroll->set_border_width($spacing);

        # Create a textview
        my $textView = Gtk3::TextView->new();
        $scroll->add($textView);
        my $buffer = Gtk3::TextBuffer->new();
        $textView->set_buffer($buffer);

        if (! $editFlag) {

            $textView->set_editable(FALSE);
            $textView->set_cursor_visible(FALSE);
            $textView->set_can_focus(FALSE);

        } else {

            $textView->set_editable(TRUE);
            $textView->set_cursor_visible(TRUE);
            $textView->set_can_focus(TRUE);
        }

        $textView->set_wrap_mode('word-char');      # Wrap words if possible, characters if not
        $textView->set_justification('left');

        if ($systemFlag && $axmud::CLIENT->ivExists('colourSchemeHash', $colourScheme)) {
            $axmud::CLIENT->desktopObj->setTextViewStyle($colourScheme, $textView);
        } else {
            $axmud::CLIENT->desktopObj->setTextViewStyle($self->winObj->winType, $textView);
        }

        $buffer->set_text($text);

        # Set expansion
        $textView->set_hexpand($hExpandFlag);
        $textView->set_vexpand($vExpandFlag);

        # Update IVs
        $self->ivPoke('funcRef', $funcRef);
        $self->ivPoke('funcID', $funcID);
        $self->ivPoke('packingBox', $packingBox);
        $self->ivPoke('packingBox2', $packingBox2);
        $self->ivPoke('frame', $frame);
        $self->ivPoke('scroll', $scroll);
        $self->ivPoke('textView', $textView);
        $self->ivPoke('buffer', $buffer);

        # Set up ->signal_connects
        $self->setChangedEvent();

        return 1;
    }

#   sub objDestroy {                # Inherited from GA::Generic::Table

#   sub setWidgetsIfSession {}      # Inherited from GA::Generic::Table

#   sub setWidgetsChangeSession {}  # Inherited from GA::Generic::Table

#   sub setWidgetsOnResize {}       # Inherited from GA::Generic::Table

    # ->signal_connects

    sub setChangedEvent {

        # Called by $self->objEnable
        #
        # 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 . '->setChangedEvent', @_);
        }

        $self->buffer->signal_connect('changed' => sub {

            my $currentFuncRef = $self->funcRef;

            if ($currentFuncRef) {

                &$currentFuncRef(
                    $self,
                    $self->textView,
                    $self->buffer,
                    $self->funcID,
                    $axmud::CLIENT->desktopObj->bufferGetText($self->buffer),
                );
            }
        });

        return 1;
    }

    # Other functions

    ##################
    # Accessors - set

    sub set_editable {

        my ($self, $flag, $check) = @_;

        # Check for improper arguments
        if (defined $check) {

            return $axmud::CLIENT->writeImproper($self->_objClass . '->set_editable', @_);
        }

        if (! $flag) {

            $self->textView->set_editable(FALSE);
            $self->textView->set_cursor_visible(FALSE);
            $self->textView->set_can_focus(FALSE);

        } else {

            $self->textView->set_editable(TRUE);
            $self->textView->set_cursor_visible(TRUE);
            $self->textView->set_can_focus(TRUE);
        }

        return 1;
    }

#   sub set_func {}                 # Inherited from GA::Generic::Table

#   sub set_id {}                   # Inherited from GA::Generic::Table

    sub set_text {

        my ($self, $text, $check) = @_;

        # Check for improper arguments
        if (defined $check) {

             return $axmud::CLIENT->writeImproper($self->_objClass . '->set_text', @_);
        }

        if (! defined $text) {

            $text = '';
        }

        $self->buffer->set_text($text);

        return 1;
    }

    sub insert_text {

        my ($self, $text, $check) = @_;

        # Check for improper arguments
        if (defined $check) {

             return $axmud::CLIENT->writeImproper($self->_objClass . '->insert_text_at_cursor', @_);
        }

        if (! defined $text) {

            $text = '';
        }

        $self->buffer->insert_at_cursor ($text);

        return 1;
    }

    # (Get equivalents)

    sub get_editable {

        my ($self, $check) = @_;

        # Check for improper arguments
        if (defined $check) {

            return $axmud::CLIENT->writeImproper($self->_objClass . '->get_editable', @_);
        }

        if ($self->textView->get_editable()) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    sub get_text {

        my ($self, $check) = @_;

        # Check for improper arguments
        if (defined $check) {

             return $axmud::CLIENT->writeImproper($self->_objClass . '->get_text', @_);
        }

        return $axmud::CLIENT->desktopObj->bufferGetText($self->buffer);
    }

    ##################
    # Accessors - get

    sub frame
        { $_[0]->{frame} }
    sub scroll
        { $_[0]->{scroll} }
    sub textView
        { $_[0]->{textView} }
    sub buffer
        { $_[0]->{buffer} }
}

# Complex table objects

{ package Games::Axmud::Table::Pane;

    use strict;
    use warnings;
#   use diagnostics;

    use Glib qw(TRUE FALSE);

    our @ISA = qw(Games::Axmud::Generic::Table Games::Axmud);

    ##################
    # Constructors

    sub new {

        # Called by GA::Strip::Table->addTableObj
        # Creates the GA::Table::Pane, which contains one or more Gtk3::TextViews sharing a single
        #   Gtk3::TextBuffer
        #
        # Expected arguments
        #   $number     - The table object's number within the parent strip object (matches
        #                   GA::Strip::Table->tableObjCount, or -1 for a temporary table object
        #                   created to access its default IVs)
        #   $name       - A name for the table object. Can be any string or, if no name was
        #                   specified in the call to the calling function, $name is the same as
        #                   $number. (No part of the code checks that table object names are unique;
        #                   if two or more table objects share the same ->name, usually the one with
        #                   the lowest ->number 'wins'. 'temp' for temporary table objects. Max 16
        #                   chars)
        #   $stripObj   - The parent strip object (GA::Strip::Table). 'temp' for temporary table
        #                   objects
        #   $zoneObj    - The tablezone object (GA::Obj::Tablezone) which marks out an area of the
        #                   parent strip object's Gtk3::Grid for use exclusively by this table
        #                   object. 'temp' for temporary table objects
        #
        # Optional arguments
        #   %initHash   - A hash containing arbitrary data to use as the table object's
        #                   initialisation settings. The table object should use default
        #                   initialisation settings unless it can succesfully interpret one or more
        #                   of the key-value pairs in the hash, if there are any
        #               - This type of table object recognises these initialisation settings:
        #
        #                   'frame_title' - If specified, the table object is drawn inside a frame

lib/Games/Axmud/Table.pm  view on Meta::CPAN

        #                       anything else
        #   $defaultFlag    - Flag set to TRUE if this tab will be $session's default tab (where
        #                       text received from the world is usually displayed), FALSE (or
        #                       'undef') otherwise (might be TRUE even if $sessionFlag is FALSE)
        #   $labelText      - The text to use in the tab label, ignored if specified (exists for
        #                       compatibility with other functions in this group)
        #   $oldBuffer      - If a Gtk3::Notebook with a single tab is being replaced by a
        #                       standalone textview object, the old textview object's
        #                       Gtk3::TextBuffer, which is transferred to the new textview object
        #                       ('undef' otherwise)
        #
        # Return values
        #   'undef' on improper arguments or if the simple tab can't be drawn
        #   Otherwise returns the tab object (GA::Obj::Tab) created, which stores (among other
        #       things) the textview object created

        my (
            $self, $session, $colourScheme, $sessionFlag, $defaultFlag, $labelText, $oldBuffer,
            $check,
        ) = @_;

        # Local variables
        my ($textViewObj, $packedObj, $tabObj);

        # Check for improper arguments
        if (! defined $session || defined $check) {

             return $axmud::CLIENT->writeImproper($self->_objClass . '->addSimpleTab', @_);
        }

        # If this pane object has drawn a notebook, not a simple container (a Gtk3::ScrolledWindow
        #   or Gtk3::VPaned), $self->addTab should have been called instead. Show a warning, then
        #   redirect the function call
        if ($self->notebook) {

            $self->winObj->session->writeWarning(
                'Tried to add a simple tab to a notebook; code should call ->addTab, not'
                . ' ->addSimpleTab',
                $self->_objClass . '->addSimpleTab',
            );

            return $self->addTab(
                $session,
                $colourScheme,
                $sessionFlag,
                $defaultFlag,
                $labelText,
                $oldBuffer,
            );

        # If there is already a simple tab, don't create another one
        } elsif ($self->tabObjHash) {

            return $self->writeError(
                'Tried to add a simple tab, but one or more tabs already exist',
                $self->_objClass . '->addSimpleTab',
            );
        }

        # Create a new GA::Obj::Textview object to handle the Gtk3::Textview(s)
        $textViewObj = $axmud::CLIENT->desktopObj->add_textView(
            $session,
            $self->winObj,
            $self,
        );

        if (! $textViewObj) {

            return undef;
        }

        # Set the colour scheme to use
        if (
            ! defined $colourScheme
            || ! $axmud::CLIENT->ivExists('colourSchemeHash', $colourScheme)
        ) {
            $colourScheme = $self->ivShow('initHash', 'colour_scheme');
        }

        # Create the Gtk3::TextView(s) themselves. The function call returns a Gtk3::ScrolledWindow
        #   or a Gtk3::VPaned containing the textview(s)
        $packedObj = $textViewObj->objEnable(
            $self->ivShow('initHash', 'split_mode'),
            $colourScheme,
            $self->ivShow('initHash', 'max_lines'),
            $self->ivShow('initHash', 'new_line'),
            $oldBuffer,
        );

        if (! $packedObj) {

            $textViewObj->objDestroy();
            return undef;
        }

        # Pack the Gtk3::ScrolledWindow/Gtk3::VPaned into our main Gtk3::VBox
        $self->packingBox2->pack_start($packedObj, TRUE, TRUE, 0);

        # Create a tab object to store details about the tab
        $tabObj = Games::Axmud::Obj::Tab->new(
            0,                          # ->number
            $self,
            $session,
            $defaultFlag,
            $textViewObj,
            $self->packingBox2,         # ->packableObj
            $packedObj,                 # ->packedObj
        );

        # Update IVs. The code above has already checked that $self->tabObjHash is empty
        $self->ivAdd('tabObjHash', $tabObj->number, $tabObj);
        $self->ivIncrement('tabObjCount');
        $self->ivPoke('simpleTabFlag', TRUE);

        # Make the changes visible
        $self->winObj->winShowAll($self->_objClass . '->addSimpleTab');

        # The new tab is the visible tab
        $self->respondVisibleTab($tabObj, $sessionFlag);

        return $tabObj;

lib/Games/Axmud/Table.pm  view on Meta::CPAN

        # Local variables
        my ($textViewObj, $packedObj, $tabObj);

        # Check for improper arguments
        if (! defined $session || defined $check) {

             return $axmud::CLIENT->writeImproper($self->_objClass . '->addTab', @_);
        }

        # If this table object isn't using a notebook, but a simple container (a
        #   Gtk3::ScrolledWindow or a Gtk3::VPaned), convert from the latter to the former
        if (! $self->notebook) {

            if ($self->tabObjHash) {

                # Convert the existing single tab to a normal tab
                if (! $self->convertSimpleTab()) {

                    # (Error message displayed by called function)
                    return undef;
                }

            } else {

                # No tabs exist, so create the notebook, then we can continue creating the first
                #   tab in it
                if (! $self->drawNotebook()) {

                    return $self->writeWarning(
                        'General error adding a tab',
                        $self->_objClass . '->addTab',
                    );
                }
            }
        }

        # Create the tab

        # The tab contains a vertical packing box, which contains everything else
        my $vBox = Gtk3::VBox->new(FALSE, 0);
        $vBox->set_border_width(0);

        # A horizontal packing box is used as the tab's label (in place of a Gtk3::Label)
        my $hBox = Gtk3::HBox->new(FALSE, 0);
        my $label = Gtk3::Label->new();
        $hBox->pack_start($label, FALSE, FALSE, 0);
        $label->show();

        # Add an 'X' button to close the tab, if required
        my $button;
        if ($self->canCloseFlag) {

            $button = Gtk3::Button->new();
            $hBox->pack_start($button, FALSE, FALSE, 0);
            $button->set_image(Gtk3::Image->new_from_stock('gtk-close', 'menu'));
            $button->set_relief('none');
            $button->show();
        }

        # Create a new GA::Obj::Textview object to handle the Gtk3::Textview(s)
        $textViewObj = $axmud::CLIENT->desktopObj->add_textView(
            $session,
            $self->winObj,
            $self,
        );

        if (! $textViewObj) {

            return undef;
        }

        # Set the colour scheme to use
        if (
            ! defined $colourScheme
            || ! $axmud::CLIENT->ivExists('colourSchemeHash', $colourScheme)
        ) {
            $colourScheme = $self->ivShow('initHash', 'colour_scheme');
        }

        # Create the Gtk3::TextView(s) themselves. The function call returns a Gtk3::ScrolledWindow
        #   or a Gtk3::VPaned containing the textview(s)
        $packedObj = $textViewObj->objEnable(
            $self->ivShow('initHash', 'split_mode'),
            $colourScheme,
            $self->ivShow('initHash', 'max_lines'),
            $self->ivShow('initHash', 'new_line'),
            $oldBuffer,
        );

        if (! $packedObj) {

            $textViewObj->objDestroy();
            return undef;
        }

        # Pack the Gtk3::ScrolledWindow/Gtk3::VPaned into this tab's Gtk3::VBox
        $vBox->pack_start($packedObj, TRUE, TRUE, 0);

        # From Gtk documentation: 'Note that due to historical reasons, GtkNotebook refuses to
        #   switch to a page unless the child widget is visible. Therefore, it is recommended to
        #   show child widgets before adding them to a notebook.'
        $vBox->show();
        $hBox->show();

        # Add the tab to the notebook
        my $tabNum = $self->notebook->append_page($vBox, $hBox);

        # Make the tab re-orderable
        my $tabWidget = $self->notebook->get_nth_page($tabNum);
        $self->notebook->set_tab_reorderable($tabWidget, TRUE);

        # If no label text was specified, use the default text
        if (! defined $labelText) {

            $labelText = 'Tab #' . $tabNum;
        }

        $label->set_markup($labelText);

        # Create a tab object to store details about the tab
        $tabObj = Games::Axmud::Obj::Tab->new(
            $self->tabObjCount,         # ->number
            $self,
            $session,
            $defaultFlag,
            $textViewObj,
            $vBox,                      # ->packableObj
            $packedObj,                 # ->packedObj
            $vBox,                      # ->tabWidget
            $label,                     # ->tabLabel
        );

        # Update IVs
        $self->ivAdd('tabObjHash', $tabObj->number, $tabObj);
        $self->ivIncrement('tabObjCount');

        # The new tab should be the visible (current) one
        # NB When replacing a standalone textview object with a Gtk3::Notebook, adding the old
        #   textview object's buffer to the new notebook's first tab, we don't set the first tab as
        #   the current page - because the calling function wants to set the (new) second tab as the
        #   current page
        if (! $oldBuffer) {

            $self->notebook->set_current_page($tabNum);
        }

        # After replacing a standalone textview object with a Gtk3::Notebook, the original session's
        #   textview(s) don't scroll to the bottom (as it should) without this code (and placing the
        #   code anywhere else doesn't work, either)
        if ($oldBuffer) {

            $axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->addTab');
        }

        # Set up ->signal_connects for the close button, if it was created
        if ($button) {

            if (! $defaultFlag) {
                $self->setButtonClicked($button, $tabObj);
            } else {
                $self->setButtonClicked($button, $tabObj, $session);
            }
        }

        # Make the changes visible
        $self->winObj->winShowAll($self->_objClass . '->addTab');

        # The new tab is the visible tab. The call above to ->set_current_page ought to have
        #   caused a call to $self->respondVisibleTab, but if $sessionFlag is set, call it again,
        #   forcing it to call GA::Win::Internal->setVisibleSession at least once
        if ($sessionFlag) {

            $self->respondVisibleTab($tabObj, $sessionFlag);
        }

        return $tabObj;
    }

    sub removeSessionTab {

        # Called by GA::Session->stop (only)
        # Removes the tab containing the default textview object for the calling session (if other
        #   parts of the code want to remove a non-default tab, they should call
        #   $self->removeTabNum)
        # After removing the tab, if there is then only a single session open, and if the
        #   initialisation setting demands that we use a simple tab rather than a Gtk3::Notebook
        #   tab, replace the notebook with a simple tab
        #
        # Expected arguments
        #   $session    - The GA::Session for the tab to be removed
        #
        # Return values
        #   'undef' on improper arguments, or if the tab widgets can't be removed or if the
        #       session's default tab can't be found
        #   1 on success

        my ($self, $session, $check) = @_;

        # Local variables
        my ($tabObj, $count, $newTabObj);

        # Check for improper arguments
        if (! defined $session || defined $check) {

            return $axmud::CLIENT->writeImproper($self->_objClass . '->removeTab', @_);
        }

        if (! $self->notebook) {

            # A simple tab, containing a standalone textview object
            $tabObj = $self->ivShow('tabObjHash', 0);
            if (! $tabObj || ! $tabObj->defaultFlag || $tabObj->session ne $session) {

                # (Error message displayed by calling function)
                return undef;
            }

            # Remove the simple tab by removing everything from the main packing box
            $axmud::CLIENT->desktopObj->removeWidget($self->packingBox2, $tabObj->packedObj);
            # Inform the textview object (if any) of its demise
            if ($tabObj->textViewObj) {

                $tabObj->textViewObj->objDestroy();
            }

            # Update IVs
            $self->ivEmpty('tabObjHash');
            $self->ivPoke('tabObjCount', 0);

        } else {

            # A tab in a Gtk3::Notebook. Find which one corresponds to the session
            $tabObj = $self->findSession($session);
            if (! defined $tabObj) {

                # (Error message displayed by calling function)
                return undef;
            }

            # Remove the tab from its Gtk3::Notebook
            $self->notebook->remove_page($self->notebook->page_num($tabObj->tabWidget));
            # Inform the textview object (if any) of its demise
            if ($tabObj->textViewObj) {

                $tabObj->textViewObj->objDestroy();
            }

            # Update IVs
            $self->ivDelete('tabObjHash', $tabObj->number);

            # If there is only one tab left, and the first tab created (since the pane was last
            #   empty of tabs) was a simple tab, convert a normal tab into a simple tab
            $count = $self->ivPairs('tabObjHash');
            if ($count == 1 && $self->simpleTabFlag) {

                if (! $self->convertTab()) {

                    # (Error message already displayed)
                    return undef;
                }

            # If there are no tabs left, remove the notebook itself, so the next tab to be added can
            #   be a simple or normal tab
            } elsif (! $count) {

                $axmud::CLIENT->desktopObj->removeWidget($self->packingBox2, $self->notebook);

                $self->ivUndef('notebook');
            }
        }

        # If there are no tabs left, the calling code can create a simple tab or a normal tab
        if (! $self->tabObjHash) {

            $self->ivPoke('simpleTabFlag', FALSE);
        }

        # Make the changes visible
        $self->winObj->winShowAll($self->_objClass . '->removeTab');

        return 1;
    }

    sub removeTab {

        # Called by callback in $self->setButtonClicked (only)
        # Removes the specified tab
        #
        # Expected arguments
        #   $tabObj     - The GA::Obj::Tab to remove
        #
        # Return values
        #   'undef' on improper arguments, or if the specified tab doesn't exist
        #   1 on success

        my ($self, $tabObj, $check) = @_;

        # Local variables
        my ($count, $funcRef);

        # Check for improper arguments
        if (! defined $tabObj || defined $check) {

            return $axmud::CLIENT->writeImproper($self->_objClass . '->removeTab', @_);
        }

        # Check the tab exists
        if (! $self->ivExists('tabObjHash', $tabObj->number)) {

            return undef;
        }

        # Remove the tab
        if (! $self->notebook) {

            # A simple tab, containing a standalone textview object

            # Remove the simple tab by removing everything from the main packing box
            $axmud::CLIENT->desktopObj->removeWidget($self->packingBox2, $tabObj->packedObj);
            # Inform the textview object (if any) of its demise
            if ($tabObj->textViewObj) {

                $tabObj->textViewObj->objDestroy();
            }

            # Update IVs
            $self->ivEmpty('tabObjHash');
            $self->ivPoke('tabObjCount', 0);

        } else {

            # A tab in a Gtk3::Notebook

            # Remove the tab from its Gtk3::Notebook
            $self->notebook->remove_page($self->notebook->page_num($tabObj->tabWidget));
            # Inform the textview object (if any) of its demise
            if ($tabObj->textViewObj) {

                $tabObj->textViewObj->objDestroy();
            }

            # Update IVs
            $self->ivDelete('tabObjHash', $tabObj->number);

            # If there is only one tab left, and the first tab created (since the pane was last
            #   empty of tabs) was a simple tab, convert a normal tab into a simple tab
            $count = $self->ivPairs('tabObjHash');
            if ($count == 1 && $self->simpleTabFlag) {

                if (! $self->convertTab()) {

                    # (Error message already displayed)
                    return undef;
                }

            # If there are no tabs left, remove the notebook itself, so the next tab to be added can
            #   be a simple or normal tab
            } elsif (! $count) {

                $axmud::CLIENT->desktopObj->removeWidget($self->packingBox2, $self->notebook);

                $self->ivUndef('notebook');
            }
        }

        # If there are no tabs left, the calling code can create a simple tab or a normal tab
        if (! $self->tabObjHash) {

            $self->ivPoke('simpleTabFlag', FALSE);
        }

        # Inform any code that wants to be informed when the tab changes
        if ($self->closeFuncRef) {

            $funcRef = $self->closeFuncRef;
            &$funcRef($self, $tabObj, $self->closeFuncID);
        }

        # Make the changes visible
        $self->winObj->winShowAll($self->_objClass . '->removeTab');

        return 1;
    }

    sub convertSimpleTab {

        # Called by $self->addTab, when a simple tab is currently visible
        #
        # Converts the standalone textview object (a simple tab) into a new tab on a Gtk3::Notebook,
        #   preserving the Gtk3::TextBuffer
        #
        # Expected arguments
        #   (none besides $self)
        #
        # Return values
        #   'undef' on improper arguments or if there's an error
        #   1 on success

        my ($self, $check) = @_;

        # Local variables
        my ($oldTabObj, $newTabObj, $notebook, $oldLabelText);

        # Check for improper arguments
        if (defined $check) {

             return $axmud::CLIENT->writeImproper($self->_objClass . '->convertSimpleTab', @_);
        }

        # Set a flag that various ->signal_connects can use to avoid responding when a tab
        #   conversion operation is in progress
        $self->ivPoke('tabConvertFlag', TRUE);

        # Get the single existing tab
        $oldTabObj = $self->ivShow('tabObjHash', 0);

        # Remove the standalone textview object
        $axmud::CLIENT->desktopObj->removeWidget($self->packingBox2, $oldTabObj->packedObj);

        # Add a Gtk3::Notebook in its place
        $notebook = $self->drawNotebook();
        if (! $notebook) {

            # Emergency fallback - put the old textview back, as if nothing had happened (but show a
            #   warning)
            $self->packingBox2->pack_start($oldTabObj->packedObj, TRUE, TRUE, 0);

            return $self->writeWarning(
                'General error converting simple tab',
                $self->_objClass . '->convertSimpleTab',
            );
        }

        # Update IVs
        $self->ivEmpty('tabObjHash');
        $self->ivPoke('tabObjCount', 0);

        # Add a tab in its place, using the old textview object's buffer and the old session number
        if ($oldTabObj->defaultFlag) {

            $oldLabelText = $oldTabObj->session->getTabLabelText();
        }

        $newTabObj = $self->addTab(
            $oldTabObj->session,
            $oldTabObj->textViewObj->colourScheme,
            undef,                                      # Not called by GA::Session->setDefaultTab
            $oldTabObj->defaultFlag,
            $oldLabelText,
            $oldTabObj->textViewObj->buffer,
        );

        # Restore the scroll lock, if it was enabled in the old single textview
        if ($oldTabObj->textViewObj->scrollLockFlag) {

            $newTabObj->textViewObj->toggleScrollLock();
        }

        # Restore the old single textview's split screen mode
        $newTabObj->textViewObj->setSplitScreenMode($oldTabObj->textViewObj->splitScreenMode);

        # Update the GA::Session's tab IVs, as required
        if (
            $oldTabObj->session->defaultTabObj
            && $oldTabObj->session->defaultTabObj eq $oldTabObj
        ) {
            $oldTabObj->session->set_defaultTabObj($newTabObj);
        }

        if (
            $oldTabObj->session->currentTabObj
            && $oldTabObj->session->currentTabObj eq $oldTabObj
        ) {
            $oldTabObj->session->set_currentTabObj($newTabObj);
        }

        # Operation complete
        $self->ivPoke('tabConvertFlag', FALSE);

        return 1;
    }

    sub convertTab {

        # Called by $self->removeSessionTab or ->removeTab when there's only a single Gtk3::Notebook
        #   tab left, and the initialisation setting specifies that a tab label shouldn't be visible
        # Converts the Gtk3::Notebook containing a single remaining tab into a standalone textview
        #   object, preserving its Gtk3::TextBuffer (a simple tab)
        #
        # Expected arguments
        #   (none besides $self)
        #
        # Return values
        #   'undef' on improper arguments or if there's an error
        #   1 on success

        my ($self, $tabObj, $check) = @_;

        # Local variables
        my ($oldTabObj, $scroll, $newTabObj, $oldLabelText);

        # Check for improper arguments
        if (defined $check) {

             return $axmud::CLIENT->writeImproper($self->_objClass . '->convertTab', @_);
        }

        # Set a flag that various ->signal_connects can use to avoid responding when a tab
        #   conversion operation is in progress
        $self->ivPoke('tabConvertFlag', TRUE);

        # Get the single remaining tab (the calling function has already checked there is only one)
        ($oldTabObj) = $self->ivValues('tabObjHash');
        if (! $oldTabObj) {

            return $self->writeWarning(
                'General error converting tab',
                $self->_objClass . '->convertTab',
            );
        }

        # Remove the Gtk3::Notebook
        $axmud::CLIENT->desktopObj->removeWidget($self->packingBox2, $self->notebook);

        # v1.1.128 This is not necessary, and in fact messes up everything
#        # Replace it with a standalone textview object
#        $axmud::CLIENT->desktopObj->removeWidget($oldTabObj->packableObj, $oldTabObj->packedObj);
#        $self->packingBox2->pack_start($oldTabObj->packedObj, TRUE, TRUE, 0);

        # Update IVs
        $self->ivUndef('notebook');
        $self->ivEmpty('tabObjHash');
        $self->ivPoke('tabObjCount', 0);

        # Add a simple tab, using the old tab's buffer and the old session
        if ($oldTabObj->defaultFlag) {

            $oldLabelText = $oldTabObj->session->getTabLabelText();
        }

        $newTabObj = $self->addSimpleTab(
            $oldTabObj->session,
            $oldTabObj->textViewObj->colourScheme,
            undef,                                  # Not called by GA::Session->setDefaultTab
            $oldTabObj->defaultFlag,
            $oldLabelText,
            $oldTabObj->textViewObj->buffer,
        );

        # Restore the scroll lock, if it was enabled in the old single textview
        if ($oldTabObj->textViewObj->scrollLockFlag) {

            $newTabObj->textViewObj->toggleScrollLock();
        }

        # Restore the old single textview's split screen mode
        $newTabObj->textViewObj->setSplitScreenMode($oldTabObj->textViewObj->splitScreenMode);

        # Update the GA::Session's tab IVs, as required
        if (
            $oldTabObj->session->defaultTabObj
            && $oldTabObj->session->defaultTabObj eq $oldTabObj
        ) {
            $oldTabObj->session->set_defaultTabObj($newTabObj);
        }

        if (
            $oldTabObj->session->currentTabObj
            && $oldTabObj->session->currentTabObj eq $oldTabObj
        ) {
            $oldTabObj->session->set_currentTabObj($newTabObj);
        }

        # Operation complete
        $self->ivPoke('tabConvertFlag', FALSE);

        return 1;
    }

    sub updateColourScheme {

        # Called by GA::Win::Internal->updateColourScheme (only)
        # When a colour scheme is modified, checks all textview objects in this pane object and
        #   updates any that use the modified colour scheme. Alternatively, when no colour scheme is
        #   specified, updates all textview objects
        #
        # Expected arguments

lib/Games/Axmud/Table.pm  view on Meta::CPAN

        #
        # Before v1.0.905, textview objects had two split screen modes, 'on' and 'off'. Since then,
        #   textview objects have had three modes, but pane objects continue to distinguish only
        #   between 'on' and 'off'
        # The textview object modes 'single' and 'hidden' are considered 'off', and this function
        #   converts them to 'split'
        # The textview object mode 'split' is considered 'off', and this function converts it to
        #   'hidden'
        # In this way, for textview objects created by a pane object, split screen mode is only
        #   'single' when the textview object is created with that mode set. Once the mode is
        #   changed (by this function), it cannot be restored to 'single' (by this function)
        #
        # This change has been made because of Gtk3 performance issues, particularly with
        #   Gtk3::TextViews with large buffers. In general, any pane in which split screen mode
        #   might be turned 'on' should probably create the textview object using the mode 'hidden'
        #   rather than 'single'
        #
        # Expected arguments
        #   (none besides $self)
        #
        # Return values
        #   'undef' on improper arguments or if the toggle operation fails
        #   1 on success

        my ($self, $check) = @_;

        # Local variables
        my ($tabObj, $packedObj, $viewport, $entryObj);

        # Check for improper arguments
        if (defined $check) {

            return $axmud::CLIENT->writeImproper($self->_objClass . '->toggleSplitScreen', @_);
        }

        # Get the visible tab's tab object
        if (! $self->notebook) {
            $tabObj = $self->ivShow('tabObjHash', 0);
        } else {
            $tabObj = $self->ivShow('tabObjHash', $self->notebook->get_current_page());
        }

        if (! $tabObj || ! $tabObj->textViewObj) {

            return undef;
        }

        # Get a new packable widget
        if (
            $tabObj->textViewObj->splitScreenMode eq 'single'
            || $tabObj->textViewObj->splitScreenMode eq 'hidden'
        ) {
            $packedObj = $tabObj->textViewObj->setSplitScreenMode('split');
        } else {
            $packedObj = $tabObj->textViewObj->setSplitScreenMode('hidden');
        }

        # If $packedObj is defined, it must be re-packed, replacing the old packable widget
        if ($packedObj) {

            $axmud::CLIENT->desktopObj->removeWidget($tabObj->packableObj, $tabObj->packedObj);
            $tabObj->packableObj->pack_start($packedObj, TRUE, TRUE, 0);
            $tabObj->ivPoke('packedObj', $packedObj);
        }

        # Find the entry strip object (if it exists)
        $entryObj = $self->winObj->ivShow('firstStripHash', 'Games::Axmud::Strip::Entry');
        if ($entryObj) {

            # Update the toolbutton icon for its scroll lock button
            if ($tabObj->textViewObj->splitScreenMode eq 'split') {
                $entryObj->updateSplitButton(TRUE);
            } else {
                $entryObj->updateSplitButton(FALSE);
            }
        }

        if ($packedObj) {

            # (If we try to scroll the textviews before they've been re-packed, we get an
            #   uncomfortable flash, so the scrolling function is called last)
            $self->winObj->winShowAll($self->_objClass . '->toggleSplitScreen');
            $axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->toggleSplitScreen');
            $tabObj->textViewObj->scrollToLock();
        }

        return 1;
    }

    sub findPage {

        # Can be called by anything
        # Finds the tab object (GA::Obj::Tab) corresponding to a specified page in the
        #   Gtk3::Notebook, when normal tabs (not simple tabs) are visible
        # If there is a simple tab visible and the specified page is 0, return it
        #
        # Expected arguments
        #   $page       - The tab's current page number in the notebook (0 for the first tab, 1
        #                   for the second, etc)
        #
        # Return values
        #   'undef' on improper arguments or if a matching tab object doesn't exist
        #   Otherwise, returns the tab object

        my ($self, $page, $check) = @_;

        # Check for improper arguments
        if (! defined $page || defined $check) {

             return $axmud::CLIENT->writeImproper($self->_objClass . '->findPage', @_);
        }

        # If there is a simple tab visible and the specified page is 0, return it
        if (! $self->notebook) {

            if ($page == 0) {
                return $self->ivShow('tabObjHash', 0);
            } else {
                return undef;
            }
        }

        # Otherwise, check each tab in turn until we find the right page number
        foreach my $tabObj ($self->ivValues('tabObjHash')) {

            my $num = $self->notebook->page_num($tabObj->tabWidget);
            if ($num == $page) {

                return $tabObj;
            }
        }

        # Corresponding tab object not found
        return undef;
    }

    sub findSession {

        # Can be called by anything
        # Finds the tab object (GA::Obj::Tab) for the tab/simple tab which contains the specified
        #   session's default textview object (GA::Obj::TextView)
        #
        # Expected arguments



( run in 0.700 second using v1.01-cache-2.11-cpan-f56aa216473 )