/* ** Command & Conquer Generals(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 . */ //////////////////////////////////////////////////////////////////////////////// // // // (c) 2001-2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// // FILE: Shell.h ////////////////////////////////////////////////////////////////////////////////// // Author: Colin Day, September 2001 // Description: Shell menu representations // // Using The Shell: // ---------------- // // The Shell makes use of the window layouts to represent screens. You can push and // pop screens on the stack so that you don't have to keep track of how you got // to which screen. // // Here is what happens when you push a layout on the shell stack: // 1) The layout name is stored as a "pending push" // 2) The top of the stack has the Shutdown() method run // 3) The Shutdown() method (or other mechanisms like Update()) will call // Shell::shutdownComplete() when the shutdown process for that layout is "complete" // 4) Shell::shutdownComplete() sees the "pending push" in the shell // 5) "Pending push" layout is then loaded from disk and the pending push state is cleared // 6) The new layout is put on the top of the stack // 7) The new layout Init() method is called // // Here is what happens when you pop the top of the stack // 1) The stack sets a "pending pop" as in progress // 2) The top layout of the stack has the Shutdown() method called // 3) The Shutdown() method (or other mechanisms like Update()) will call // Shell::shutdownComplete() when the shutdown process for that layout is "complete" // 4) Shell::shutdownComplete() sees the "pending pop" in the shell // 5) The "pending pop" layout is then destroyed and removed from the stack // 6) The new top of the stack has the Init() method run // // Window Layouts and the Shell: // ----------------------------- // // Window Layouts in the shell need the following functions to work property, these // can be assigned from the GUIEdit window layout tool: // // - Init() [OPTIONAL] // This is called as a result of a push or pop operation (see above for more info) // The window layout is loaded from disk and then this Init() // method is run. All shell layout Init() methods should show // the layout windows. At this point you could move windows // to starting positions, set a state that the Update() method looks at to // "animate" the windows to the desired positions. // // - Update() [OPTIONAL] // This is called once at a rate of "shellUpdateDelay" for EVERY screen on the shell // stack. It does not matter if the screen is on the top, or is hidden, or // anything, this is always called. Each update is run starting with the screen // at the top of the stack and progressing to the bottom of the stack. // States could be set in the Init() or Shutdown() methods of the layout // that the Update() looks at and reacts to appropriately if desired. // // - Shutdown() [REQUIRED] // This is called when a layout is popped off the stack, or when a new layout // is pushed on top of this one (see above for more detail on what happens // during the push/pop process). You can switch into a "shutdown" state and // animate the layout appropriately in the Update() method for the layout. // When shutdown is actually complete you should hide the all windows in // the layout and then you are REQUIRED to notify the shell by calling // the Shell::shutdownComplete() method. // // Shutdown() is also required to be able to handle the paramater "immediatePop". // If this paramater is TRUE it means that when control returns from the // shutdown function that the layout will immediately be popped off the // stack. We need to be able to handle this when in code we want to // traverse back down the stack rapidly (like when we lose connection to // an online service, we might pop all the way back to the login screen) // /////////////////////////////////////////////////////////////////////////////////////////////////// #pragma once #ifndef __SHELL_H_ #define __SHELL_H_ // INCLUDES /////////////////////////////////////////////////////////////////////////////////////// // FORWARD REFERENCES ///////////////////////////////////////////////////////////////////////////// class WindowLayout; class AnimateWindowManager; class GameWindow; class ShellMenuSchemeManager; enum AnimTypes; //------------------------------------------------------------------------------------------------- /** This is the interface to the shell system to load, display, and * manage screen menu shell system layouts */ //------------------------------------------------------------------------------------------------- class Shell : public SubsystemInterface { public: Shell( void ); ~Shell( void ); // Inhertited from subsystem ==================================================================== virtual void init( void ); virtual void reset( void ); virtual void update( void ); //=============================================================================================== void showShellMap(Bool useShellMap ); ///< access function to turn on and off the shell map void hide( Bool hide ); ///< show/hide all shell layouts // pseudo-stack operations for manipulating layouts void push( AsciiString filename, Bool shutdownImmediate = FALSE ); ///< load new screen on top, optionally doing an immediate shutdown void pop( void ); ///< pop top layout void popImmediate( void ); ///< pop now, don't wait for shutdown void showShell( Bool runInit = TRUE ); ///< init the top of stack void hideShell( void ); ///< shutdown the top of stack WindowLayout *top( void ); ///< return top layout void shutdownComplete( WindowLayout *layout, Bool impendingPush = FALSE ); ///< layout has completed shutdown WindowLayout *findScreenByFilename( AsciiString filename ); ///< find screen inline Bool isShellActive( void ) { return m_isShellActive; } ///< Returns true if the shell is active inline Int getScreenCount(void) { return m_screenCount; } ///< Return the current number of screens void registerWithAnimateManager( GameWindow *win, AnimTypes animType, Bool needsToFinish, UnsignedInt delayMS = 0); Bool isAnimFinished( void ); void reverseAnimatewindow( void ); Bool isAnimReversed( void ); void loadScheme( AsciiString name ); ShellMenuSchemeManager *getShellMenuSchemeManager( void ) { return m_schemeManager; } WindowLayout *getSaveLoadMenuLayout( void ); ///< create if necessary and return layout for save load menu WindowLayout *getPopupReplayLayout( void ); ///< create if necessary and return layout for replay save menu WindowLayout *getOptionsLayout( Bool create ); ///< return layout for options menu, create if necessary and we are allowed to. void destroyOptionsLayout( void ); ///< destroy the shell's options layout. protected: void linkScreen( WindowLayout *screen ); ///< link screen to list void unlinkScreen( WindowLayout *screen ); ///< remove screen from list void doPush( AsciiString layoutFile ); ///< workhorse for push action void doPop( Bool impendingPush ); ///< workhorse for pop action enum { MAX_SHELL_STACK = 16 }; ///< max simultaneous shell screens WindowLayout *m_screenStack[ MAX_SHELL_STACK ]; ///< the screen layout stack Int m_screenCount; ///< # of screens in screen stack WindowLayout *m_background; ///< The Background layout if the 3d shell isn't running Bool m_clearBackground; ///< Flag if we're going to clear the background or not Bool m_pendingPush; ///< TRUE when a push is pending Bool m_pendingPop; ///< TRUE when a pop is pending AsciiString m_pendingPushName; ///< layout name to be pushed Bool m_isShellActive; ///< TRUE when the shell is active Bool m_shellMapOn; ///< TRUE when the shell map is on AnimateWindowManager *m_animateWindowManager; ///< The animate Window Manager ShellMenuSchemeManager *m_schemeManager; ///< The Shell Scheme Manager // // we keep a pointer to this layout so that we can simply just hide/unhide this // window layout. Why you ask? Well, as the result of pressing a button to start // a save game load a super large set of operations will happen as the game // loads. One of those operations is the destruction of the menu, which although // it just destroys the windows and puts them on a destroyed list, that destroyed // list is also processed before we are out of our own window procedure. // This is a prime example why it's easier to just deal with windows by hiding and // un-hiding them rather than actually creating and destroying them. // WindowLayout *m_saveLoadMenuLayout; ///< save/load menu layout WindowLayout *m_popupReplayLayout; ///< replay save menu layout WindowLayout *m_optionsLayout; ///< options menu layout }; // end class Shell // INLINING /////////////////////////////////////////////////////////////////////////////////////// // EXTERNALS ////////////////////////////////////////////////////////////////////////////////////// extern Shell *TheShell; ///< the shell external interface #endif // __SHELL_H_