Games-Axmud

 view release on metacpan or  search on metacpan

lib/Games/Axmud/Obj/WorkspaceGrid.pm  view on Meta::CPAN

        # Return values
        #   'undef' on improper arguments
        #   1 otherwise

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

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

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

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

        # Tell any remaining 'grid' window objects to close their windows. If $session is
        #   defined, 'main' windows merely remove themselves from the workspace grid, but the
        #   window itself is not closed (exception: when Axmud is shutting down, all windows are
        #   closed)
        # Do this in the reverse order they were created, in the expectation that 'main' windows
        #   will be closed last
        foreach my $winObj (sort {$b->number <=> $a->number} ($self->ivValues('gridWinHash'))) {

            if (! $axmud::CLIENT->shutdownFlag && $session && $session->mainWin eq $winObj) {

                # (The ->winDisengage function calls $self->del_gridWin in turn)
                $winObj->winDisengage($session);

            } else {

                # (The ->winDestroy function calls $self->del_gridWin in turn)
                $winObj->winDestroy();
            }
        }

        # Check there are no 'grid' windows left (for error-detection purposes)
        $count = $self->ivPairs('gridWinHash');
        if ($count) {

            if ($count == 1) {
                $msg = 'There was 1';
            } else {
                $msg = 'There were ' . $count;
            }

            $msg .= ' un-closed \'grid\' window when the parent workspace grid closed';

            $axmud::CLIENT->writeWarning($msg, $self->_objClass . '->stop');
        }

        return 1;
    }

    sub fineTuneWinSize {

        # Called by GA::Obj::Workspace->chooseWinPosn, $self->changeWinzone,
        #   GA::Obj::Zone->adjustMultipleWin and ->replaceAreaSpace
        # Makes small adjustments to a window's size and position to close any gaps on the right and
        #   bottom edges of the workspace grid (because of an arkwardly-sized available workspace)
        # Makes more small adjustments to correct for window controls, usually before a call to
        #   GA::Obj::Workspace->moveResizeWin. (If the desktop theme uses window controls, we have
        #   to take them into account, changing the size of the window accordingly; $widthPixels and
        #   $heightPixels must now refer to the client area, not the whole window including the
        #   window controls)
        #
        # Expected arguments
        #   $winType    - The window type; one of the 'grid' window types specified by
        #                   GA::Client->constGridWinTypeHash
        #   $xPosPixels, $yPosPixels
        #               - The position of the window to be fine-tuned
        #   $widthPixels, $heightPixels
        #               - The size of the window to be fine-tuned
        #
        # Return values
        #   An empty list on improper arguments
        #   Otherwise returns the adjusted list, in the form
        #       ($xPosPixels, $yPosPixels, $widthPixels, $heightPixels)

        my ($self, $winType, $xPosPixels, $yPosPixels, $widthPixels, $heightPixels, $check) = @_;

        # Local variables
        my (
            $gridRightEdge, $winRightEdge, $gridBottomEdge, $winBottomEdge, $rightGap, $bottomGap,
            @emptyList,
        );

        # Check for improper arguments
        if (
            ! defined $winType || ! defined $xPosPixels || ! defined $yPosPixels
            || ! defined $widthPixels || ! defined $heightPixels || defined $check
        ) {
            $axmud::CLIENT->writeImproper($self->_objClass . '->fineTuneWinSize', @_);
            return @emptyList;
        }

        # Close the gap between the workspace grid and the right and bottom edges of the available
        #   workspace, if there is one, and if the global flag is set
        if ($axmud::CLIENT->gridEdgeCorrectionFlag) {

            # Get the position of the right boundary of the workspace grid, and the right edge of
            #   the window, in pixels
            $gridRightEdge
                = $self->xPosPixels + ($self->widthBlocks * $axmud::CLIENT->gridBlockSize) - 1;
            $winRightEdge = $xPosPixels + $widthPixels - 1;

            $gridBottomEdge
                = $self->yPosPixels + ($self->heightBlocks * $axmud::CLIENT->gridBlockSize) -1;
            $winBottomEdge = $yPosPixels + $heightPixels - 1;

            # For windows on the right edge of the workspace grid, look for a gap between that edge
            #   and the edge of the available workspace that's smaller than a gridblock
            if ($gridRightEdge == $winRightEdge) {

                $rightGap = $self->workspaceObj->currentWidth
                                - $self->workspaceObj->panelRightSize - 1 - $gridRightEdge;

                if ($rightGap > 0 && $rightGap < $axmud::CLIENT->gridBlockSize) {

                    # Increase the width of the window, therefore closing the gap
                    $widthPixels += $rightGap;
                }

lib/Games/Axmud/Obj/WorkspaceGrid.pm  view on Meta::CPAN

            }

            for (my $num = ($layer - 1); $num >= 0; $num--) {

                push (@layerList, $num);
            }
        }

        return @layerList;
    }

    sub changeWinzone {

        # Called by GA::Session->setMainWin, and also by GA::Cmd::MoveWindow->do, FixWindow->do
        # Moves a window from one zone into any available space in another zone, the latter being
        #   a zone in this workspace grid
        # If the new zone is the same as the old one, moves the window to the space it would have
        #   occupied, if it were being moved into this zone from a different one
        #
        # Expected arguments
        #   $winObj             - Blessed reference to the window object to be moved (inheriting
        #                           from GA::Generic::GridWin)
        #   $zoneObj            - Blessed reference to the zone object (GA::Obj::Zone) into which
        #                           the window should be moved
        #
        # Optional arguments
        #   $defaultSizeFlag    - If TRUE, the window is resized to fit the zone's default size. If
        #                           FALSE or 'undef', the window keeps its current size (subject to
        #                           small adjustments to fill small gaps)
        #   $fixWidthPixels, $fixHeightPixels
        #                       - Only specified when called by GA::Cmd::FixWindow->do. If the
        #                           user has changed the window's size, these variables specify that
        #                           size. Both must be specified or both must be set to 'undef'
        #
        # Return values
        #   'undef' on improper arguments or if there's an error
        #   1 otherwise

        my (
            $self, $winObj, $zoneObj, $defaultSizeFlag, $fixWidthPixels, $fixHeightPixels, $check,
        ) = @_;

        # Local variables
        my (
            $blockSize, $widthPixels, $heightPixels, $widthBlocks, $heightBlocks, $xPosBlocks,
            $yPosBlocks, $successFlag, $layer, $oldZoneObj, $xPosPixels, $yPosPixels, $areaObj,
        );

        # Check for improper arguments
        if (
            ! defined $winObj || ! defined $zoneObj || defined $check
            || (defined $fixWidthPixels && ! defined $fixHeightPixels)
            || (! defined $fixWidthPixels && defined $fixHeightPixels)
        ) {
            return $axmud::CLIENT->writeImproper($self->_objClass . '->changeWinzone', @_);
        }

        # Check that the window is a 'grid' window
        if (
            $winObj->winCategory ne 'grid'
            || ! $axmud::CLIENT->desktopObj->ivExists('gridWinHash', $winObj->number)
            || ! $winObj->areaObj
            || ! $winObj->areaObj->zoneObj
        ) {
            return $axmud::CLIENT->writeError(
                'Can\'t move the window - window is not a grid window',
                $self->_objClass . '->changeWinzone',
            );
        }

        # Check that the window is allowed in the new zone
        if (
            ! $zoneObj->checkWinAllowed(
                $winObj->winType,
                $winObj->winName,
                $winObj->session,
            )
        ) {
            return $axmud::CLIENT->writeError(
                'Can\'t move the window - window is not allowed in zone #' . $zoneObj->number,
                $self->_objClass . '->changeWinzone',
            );
        }

        # Set the provisional size of the window in its new zone
        # If called by GA::Cmd::FixWindow->do after the user manually changed the window's size,
        #   use that size
        # If the default flag has been set, use the new zone's default size, otherwise use the
        #   window's current size
        $blockSize = $axmud::CLIENT->gridBlockSize;

        if ($fixWidthPixels) {

            $widthPixels = $fixWidthPixels;
            $heightPixels = $fixHeightPixels;

            # When the window object was first created, the call to $self->fineTuneWinSize modified
            #   the size of the window due to window controls. We must reverse those changes (if
            #   they were applied), so that our call to $zoneObj->placeWin() will have the same
            #   initial window size as it would have had, if GA::Obj::Workspace->chooseWinPosn had
            #   been calling it
            if ($winObj->winType ne 'external') {

                $widthPixels += (
                    $winObj->workspaceObj->controlsLeftSize
                    + $winObj->workspaceObj->controlsRightSize
                );

                $heightPixels += (
                    $winObj->workspaceObj->controlsTopSize
                    + $winObj->workspaceObj->controlsBottomSize
                );
            }

        } elsif ($defaultSizeFlag) {

            $widthPixels = $zoneObj->defaultAreaWidth * $blockSize;
            $heightPixels = $zoneObj->defaultAreaHeight * $blockSize;

        } else {

            $widthPixels = $winObj->areaObj->widthBlocks * $blockSize;
            $heightPixels = $winObj->areaObj->heightBlocks * $blockSize;
        }

        # Try to find room for the window in the new zone
        # First define a provisional position for the window at the zone's start corner
        ($widthBlocks, $heightBlocks, $xPosBlocks, $yPosBlocks)
            = $zoneObj->findProvWinPosn($widthPixels, $heightPixels);

        # Try to find room for the window in the new zone. Start at the default layer, then check
        #   other layers
        ($successFlag, $layer, $xPosBlocks, $yPosBlocks) = $zoneObj->placeWin(
            $self->defaultLayer,
            $xPosBlocks,
            $yPosBlocks,
            $widthBlocks,
            $heightBlocks,
            # In case the window already exists in the zone, any space it currently occupies is
            #   available
            $winObj,
        );

        if (!$successFlag) {

            # There is no room for the window in this zone
            return $axmud::CLIENT->writeError(
                'Can\'t move the window - ouldn\'t find room for the \'' . $winObj->winType
                . '\' window anywhere in zone #' . $zoneObj->number,
                $self->_objClass . '->changeWinzone',
            );
        }

        # If the window position on the grid puts it rather close to the edge (or edges) of the
        #   zone, and if the gaps between the window and the zone's edge are empty, adjust the size
        #   of the window to fill the gap (this prevents small areas of the zone from always being
        #   empty: makes the desktop look nice). If the maximum allowable gap size is 0, don't fill
        #   gaps at all
        if ($axmud::CLIENT->gridGapMaxSize) {

            ($xPosBlocks, $yPosBlocks, $widthBlocks, $heightBlocks)
                = $zoneObj->adjustSingleWin(
                    $layer,
                    $xPosBlocks,
                    $yPosBlocks,
                    $widthBlocks,
                    $heightBlocks,
            );
        }

        # There is room for the window in the specified zone, at layer $layer and grid coordinates
        #   $xPosBlocks, $yPosBlocks
        $oldZoneObj = $winObj->areaObj->zoneObj;
        if ($oldZoneObj) {

            if ($oldZoneObj ne $zoneObj) {

                $successFlag = $oldZoneObj->removeArea($winObj->areaObj);

            } else {

                # The original and destination zones are the same, but the window's old and new size
                #   and position on the workspace won't necessarily be the same. Don't call
                #   $oldZoneObj->replaceAreaSpace to reshuffle window positions yet, because that
                #   will mess up everything
                $successFlag = $oldZoneObj->removeArea(
                    $winObj->areaObj,
                    TRUE,
                );
            }

            if (! $successFlag) {

                return $axmud::CLIENT->writeError(
                    'Can\'t move the window - attempt to move it from its current zone failed',
                    $self->_objClass . '->changeWinzone',
                );
            }
        }

        # Work out the window object's size and position on the desktop in pixels
        $xPosPixels = $self->xPosPixels + (($zoneObj->xPosBlocks + $xPosBlocks) * $blockSize);
        $yPosPixels = $self->yPosPixels + (($zoneObj->yPosBlocks + $yPosBlocks) * $blockSize);
        $widthPixels = ($widthBlocks * $blockSize);
        $heightPixels = ($heightBlocks * $blockSize);

        # Correct for small gaps in the grid and for window controls
        ($xPosPixels, $yPosPixels, $widthPixels, $heightPixels) = $self->fineTuneWinSize(
            $winObj->winType,
            $xPosPixels,
            $yPosPixels,
            $widthPixels,
            $heightPixels,
        );

        # Mark the window as added to the new zone
        $areaObj = $zoneObj->addArea(
            $layer,
            $xPosBlocks,
            $yPosBlocks,
            $widthBlocks,
            $heightBlocks,
            $xPosPixels,
            $yPosPixels,
            $widthPixels,
            $heightPixels,
            $winObj->session,
        );

        if (! $areaObj) {

            return $axmud::CLIENT->writeError(
                'Can\'t move the window - attempt to move it to its new zone failed',
                $self->_objClass . '->changeWinzone',
            );
        }

        # Update the window object's own IVs
        $winObj->set_workspaceGridObj($self);
        $winObj->set_workspaceObj($self->workspaceObj);
        $winObj->set_areaObj($areaObj);

        # If the new zone is different from the old one, update the workspace grid object's IVs too
        if ($oldZoneObj && $oldZoneObj->workspaceGridObj ne $zoneObj->workspaceGridObj) {

            $oldZoneObj->workspaceGridObj->ivDelete('gridWinHash', $winObj->number);
            $zoneObj->workspaceGridObj->add_gridWin($winObj);
        }

        # Resize the window and move it to the correct location
        $self->workspaceObj->moveResizeWin(
            $winObj,
            $xPosPixels,
            $yPosPixels,
            $widthPixels,
            $heightPixels,
        );

        # Reshuffle the positions of all windows in the zone, if necessary, in order to fill smaller
        #   gaps to fill up the zone, or expand larger ones to make room for another window
        # If the global flag isn't set allowing these adjustments, or if the zone has a maximum of



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