| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432 |
- /*
- ** Command & Conquer Generals Zero Hour(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- // FILE: ControlBarMultiSelect.cpp ////////////////////////////////////////////////////////////////
- // Author: Colin Day, March 2002
- // Desc: Context sensitive GUI for when you select mutiple objects. What we do is show
- // the commands that you can use between them all
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // USER INCLUDES //////////////////////////////////////////////////////////////////////////////////
- #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
- #include "Common/ThingTemplate.h"
- #include "GameClient/ControlBar.h"
- #include "GameClient/Drawable.h"
- #include "GameClient/GameClient.h"
- #include "GameClient/GadgetPushButton.h"
- #include "GameClient/GameWindow.h"
- #include "GameClient/InGameUI.h"
- #include "GameLogic/Object.h"
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- //-------------------------------------------------------------------------------------------------
- /** Reset the common command data */
- //-------------------------------------------------------------------------------------------------
- void ControlBar::resetCommonCommandData( void )
- {
- Int i;
- for( i = 0; i < MAX_COMMANDS_PER_SET; i++ )
- {
- m_commonCommands[ i ] = NULL;
- //Clear out any remnant overlays.
- GadgetButtonDrawOverlayImage( m_commandWindows[ i ], NULL );
- }
- } // end resetCommonCommandData
- //-------------------------------------------------------------------------------------------------
- /** add the common commands of this drawable to the common command set */
- //-------------------------------------------------------------------------------------------------
- void ControlBar::addCommonCommands( Drawable *draw, Bool firstDrawable )
- {
- Int i;
- const CommandButton *command;
- // sanity
- if( draw == NULL )
- return;
- Object* obj = draw->getObject();
- if (!obj)
- return;
- if (obj->isKindOf(KINDOF_IGNORED_IN_GUI)) // ignore these guys
- return;
- // get the command set of this drawable
- const CommandSet *commandSet = findCommandSet( obj->getCommandSetString() );
- if( commandSet == NULL )
- {
- //
- // if there is no command set for this drawable, none of the selected drawables
- // can possibly have matching commands so we'll get rid of them all
- //
- for( i = 0; i < MAX_COMMANDS_PER_SET; i++ )
- {
- m_commonCommands[ i ] = NULL;
- if (m_commandWindows[ i ])
- {
- m_commandWindows[ i ]->winHide( TRUE );
- }
- // After Every change to the m_commandWIndows, we need to show fill in the missing blanks with the images
- // removed from multiplayer branch
- //showCommandMarkers();
- } // end for i
- return;
- } // end if
- //
- // easy case, if we're adding the first drawable we simply just add any of the commands
- // in its set that can be multi-select commands to the common command set
- //
- if( firstDrawable == TRUE )
- {
- // just add each command that is classified as a common command
- for( i = 0; i < MAX_COMMANDS_PER_SET; i++ )
- {
- // our implementation doesn't necessarily make use of the max possible command buttons
- if (! m_commandWindows[ i ]) continue;
- // get command
- command = commandSet->getCommandButton(i);
- // add if present and can be used in a multi select
- if( command && BitTest( command->getOptions(), OK_FOR_MULTI_SELECT ) == TRUE )
- {
- // put it in the common command set
- m_commonCommands[ i ] = command;
- // show and enable this control
- m_commandWindows[ i ]->winHide( FALSE );
- m_commandWindows[ i ]->winEnable( TRUE );
- // set the command into the control
- setControlCommand( m_commandWindows[ i ], command );
- } // end if
- } // end for i
- } // end if
- else
- {
- // go through each command one by one
- for( i = 0; i < MAX_COMMANDS_PER_SET; i++ )
- {
-
- // our implementation doesn't necessarily make use of the max possible command buttons
- if (! m_commandWindows[ i ]) continue;
- // get the command
- command = commandSet->getCommandButton(i);
-
- Bool attackMove = (command && command->getCommandType() == GUI_COMMAND_ATTACK_MOVE) ||
- (m_commonCommands[ i ] && m_commonCommands[ i ]->getCommandType() == GUI_COMMAND_ATTACK_MOVE);
- // Kris: When any units have attack move, they all get it. This is to allow
- // combat units to be selected with the odd dozer or pilot and still retain that ability.
- if( attackMove && !m_commonCommands[ i ] )
- {
- // put it in the common command set
- m_commonCommands[ i ] = command;
- // show and enable this control
- m_commandWindows[ i ]->winHide( FALSE );
- m_commandWindows[ i ]->winEnable( TRUE );
- // set the command into the control
- setControlCommand( m_commandWindows[ i ], command );
- }
- else if( command != m_commonCommands[ i ] && !attackMove )
- {
- //
- // if this command does not match the command that is in the common command set then
- // *neither* this command OR the command in the common command set are really common
- // commands, so we will remove the one that has been stored in the common set
- //
- // remove the common command
- m_commonCommands[ i ] = NULL;
- //
- // hide the window control cause it should have been made visible from a command
- // that was placed in this common 'slot' earlier
- //
- m_commandWindows[ i ]->winHide( TRUE );
- }
- } // end if
- } // end else
- // After Every change to the m_commandWIndows, we need to show fill in the missing blanks with the images
- // removed from multiplayer branch
- //showCommandMarkers();
- } // end addCommonCommands
- //-------------------------------------------------------------------------------------------------
- /** Populate the visible command bar with commands that are common to all the objects
- * that are selected in the UI */
- //-------------------------------------------------------------------------------------------------
- void ControlBar::populateMultiSelect( void )
- {
- Drawable *draw;
- Bool firstDrawable = TRUE;
- Bool portraitSet = FALSE;
- const Image *portrait = NULL;
- Object *portraitObj = NULL;
- // first reset the common command data
- resetCommonCommandData();
- // by default, hide all the controls in the command section
- for( Int i = 0; i < MAX_COMMANDS_PER_SET; i++ )
- {
- if (m_commandWindows[ i ])
- {
- m_commandWindows[ i ]->winHide( TRUE );
- }
- }
- // sanity
- DEBUG_ASSERTCRASH( TheInGameUI->getSelectCount() > 1,
- ("populateMultiSelect: Can't populate multiselect context cause there are only '%d' things selected\n",
- TheInGameUI->getSelectCount()) );
- // get the list of drawable IDs from the in game UI
- const DrawableList *selectedDrawables = TheInGameUI->getAllSelectedDrawables();
- // sanity
- DEBUG_ASSERTCRASH( selectedDrawables->empty() == FALSE, ("populateMultiSelect: Drawable list is empty\n") );
- // loop through all the selected drawables
- for( DrawableListCIt it = selectedDrawables->begin();
- it != selectedDrawables->end(); ++it )
- {
-
- // get the drawable
- draw = *it;
-
- if (draw->getObject()->isKindOf(KINDOF_IGNORED_IN_GUI)) // ignore these guys
- continue;
- //
- // add command for this drawable, note that we also sanity check to make sure the
- // drawable has an object as all interesting drawables that we can select should
- // actually have an object underneath it so that we can do interesting things with
- // it ... otherwise we should have never selected it.
- // NOTE that we're not considering objects that are currently in the process of
- // being sold as those objects can't be issued anymore commands
- //
- if( draw && draw->getObject() &&
- !draw->getObject()->getStatusBits().test( OBJECT_STATUS_SOLD ) )
- {
- // add the common commands of this drawable to the common command set
- addCommonCommands( draw, firstDrawable );
- // not adding the first drawble anymore
- firstDrawable = FALSE;
- //
- // keep track of the portrait images, if all units selected have the same portrait
- // we will display it in the right HUD, otherwise we won't
- //
- if( portraitSet == FALSE )
- {
-
- portrait = draw->getTemplate()->getSelectedPortraitImage();
- portraitObj = draw->getObject();
- portraitSet = TRUE;
- } // end if
- else if( draw->getTemplate()->getSelectedPortraitImage() != portrait )
- portrait = NULL;
- } // end if
- } // end for, drawble id iterator
- // set the portrait image
- setPortraitByObject( portraitObj );
- } // end populateMultiSelect
- //-------------------------------------------------------------------------------------------------
- /** Update logic for the multi select context sensitive GUI */
- //-------------------------------------------------------------------------------------------------
- void ControlBar::updateContextMultiSelect( void )
- {
- Drawable *draw;
- Object *obj;
- const CommandButton *command;
- GameWindow *win;
- Int objectsThatCanDoCommand[ MAX_COMMANDS_PER_SET ];
- Int i;
- // zero the array that counts how many objects can do each command
- memset( objectsThatCanDoCommand, 0, sizeof( objectsThatCanDoCommand ) );
- // santiy
- DEBUG_ASSERTCRASH( TheInGameUI->getSelectCount() > 1,
- ("updateContextMultiSelect: TheInGameUI only has '%d' things selected\n",
- TheInGameUI->getSelectCount()) );
- // get the list of drawable IDs from the in game UI
- const DrawableList *selectedDrawables = TheInGameUI->getAllSelectedDrawables();
- // sanity
- DEBUG_ASSERTCRASH( selectedDrawables->empty() == FALSE, ("populateMultiSelect: Drawable list is empty\n") );
- // loop through all the selected drawable IDs
- for( DrawableListCIt it = selectedDrawables->begin();
- it != selectedDrawables->end(); ++it )
- {
-
- // get the drawable from the ID
- draw = *it;
- if (draw->getObject()->isKindOf(KINDOF_IGNORED_IN_GUI)) // ignore these guys
- continue;
- // get the object
- obj = draw->getObject();
- // sanity
- if( obj == NULL )
- continue;
- // for each of the visible command windows make sure the object can execute the command
- for( i = 0; i < MAX_COMMANDS_PER_SET; i++ )
- {
- // get the control window
- win = m_commandWindows[ i ];
- // our implementation doesn't necessarily make use of the max possible command buttons
- if (!win) continue;
- // don't consider hidden windows
- if( win->winIsHidden() == TRUE )
- continue;
- // get the command
- command = (const CommandButton *)GadgetButtonGetData(win);
- if( command == NULL )
- continue;
- // can we do the command
- CommandAvailability availability = getCommandAvailability( command, obj, win );
- win->winClearStatus( WIN_STATUS_NOT_READY );
- win->winClearStatus( WIN_STATUS_ALWAYS_COLOR );
- // enable/disable the window control
- switch( availability )
- {
- case COMMAND_HIDDEN:
- win->winHide( TRUE );
- break;
- case COMMAND_RESTRICTED:
- win->winEnable( FALSE );
- break;
- case COMMAND_NOT_READY:
- win->winEnable( FALSE );
- win->winSetStatus( WIN_STATUS_NOT_READY );
- break;
- case COMMAND_CANT_AFFORD:
- win->winEnable( FALSE );
- win->winSetStatus( WIN_STATUS_ALWAYS_COLOR );
- break;
- default:
- win->winEnable( TRUE );
- break;
- }
- //If button is a CHECK_LIKE, then update it's status now.
- if( BitTest( command->getOptions(), CHECK_LIKE ) )
- {
- GadgetCheckLikeButtonSetVisualCheck( win, availability == COMMAND_ACTIVE );
- }
- if( availability == COMMAND_AVAILABLE || availability == COMMAND_ACTIVE )
- objectsThatCanDoCommand[ i ]++;
- } // end for i
- } // end for, selected drawables
- //
- // for each command, if any objects can do the command we enable the window, otherwise
- // we disable it
- //
- for( i = 0; i < MAX_COMMANDS_PER_SET; i++ )
- {
- // our implementation doesn't necessarily make use of the max possible command buttons
- if (! m_commandWindows[ i ]) continue;
- // don't consider hidden commands
- if( m_commandWindows[ i ]->winIsHidden() == TRUE )
- continue;
- // don't consider slots that don't have commands
- if( m_commonCommands[ i ] == NULL )
- continue;
-
- // check the count of objects that can do the command and enable/disable the control,
- if( objectsThatCanDoCommand[ i ] > 0 )
- m_commandWindows[ i ]->winEnable( TRUE );
- else
- m_commandWindows[ i ]->winEnable( FALSE );
- } // end for i
- // After Every change to the m_commandWIndows, we need to show fill in the missing blanks with the images
- // removed from multiplayer branch
- //showCommandMarkers();
- } // end updateContextMultiSelect
|