/* ** Command & Conquer Renegade(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 O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : Combat * * * * $Archive:: /Commando/Code/wwui/dialogmgr.cpp $* * * * Author:: Patrick Smith * * * * $Modtime:: 2/05/02 1:04p $* * * * $Revision:: 40 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "dialogmgr.h" #include "dialogbase.h" #include "childdialog.h" #include "dx8wrapper.h" #include "assetmgr.h" #include "rinfo.h" #include "camera.h" #include "mousemgr.h" #include "tooltipmgr.h" #include "stylemgr.h" #include "dialogcontrol.h" #include "menudialog.h" #include "wwuiinput.h" #include "wwmemlog.h" #include "dialogtransition.h" #include "systimer.h" #include "tooltip.h" //////////////////////////////////////////////////////////////// // Static member initialization //////////////////////////////////////////////////////////////// DynamicVectorClass DialogMgrClass::DialogList; DialogBaseClass ** DialogMgrClass::TestArray; int DialogMgrClass::TestArrayCount; int DialogMgrClass::TestArrayMaxCount; bool DialogMgrClass::IsFirstRender = false; bool DialogMgrClass::IsInMenuMode = false; DialogBaseClass * DialogMgrClass::ActiveDialog = NULL; BYTE DialogMgrClass::KeyboardState[256]; DialogControlClass * DialogMgrClass::InputCapture = NULL; DialogControlClass * DialogMgrClass::FocusControl = NULL; WWUIInputClass * DialogMgrClass::Input = NULL; DialogTransitionClass * DialogMgrClass::Transition = NULL; DialogBaseClass * DialogMgrClass::PendingActiveDialog = NULL; DialogBaseClass * DialogMgrClass::TransitionDialog = NULL; uint32 DialogMgrClass::CurrTime = 0; uint32 DialogMgrClass::LastFrameTime = 0; Vector3 DialogMgrClass::LastMousePos (0, 0, 0); bool DialogMgrClass::LastMouseButtonState[MB_COUNT] = { 0 }; bool DialogMgrClass::IsFlushing = false; ToolTipClass* DialogMgrClass::mIMEMessage = NULL; uint32 DialogMgrClass::mIMEMessageTime = 0; static bool GameWasInFocus; //////////////////////////////////////////////////////////////// // // Initialize // //////////////////////////////////////////////////////////////// void DialogMgrClass::Initialize (const char *stylemgr_ini) { StyleMgrClass::Initialize_From_INI (stylemgr_ini); MouseMgrClass::Initialize (); ToolTipMgrClass::Initialize (); MenuDialogClass::Initialize (); ::memset (KeyboardState, 0, sizeof (KeyboardState)); TestArrayMaxCount = 0; return ; } //////////////////////////////////////////////////////////////// // // Shutdown // //////////////////////////////////////////////////////////////// void DialogMgrClass::Shutdown (void) { // // Remove all the dialogs from our list // Flush_Dialogs (); MenuDialogClass::Shutdown (); StyleMgrClass::Shutdown (); MouseMgrClass::Shutdown (); ToolTipMgrClass::Shutdown (); Set_Active_Dialog (NULL); delete[] TestArray; TestArray=NULL; if (mIMEMessage) { delete mIMEMessage; mIMEMessage = NULL; mIMEMessageTime = 0; } // // Release our hold on the input mechanism // REF_PTR_RELEASE (Input); return ; } //////////////////////////////////////////////////////////////// // // Reset_Inputs // //////////////////////////////////////////////////////////////// void DialogMgrClass::Reset_Inputs (void) { // // Update the cached mouse button states // LastMouseButtonState[MB_LBUTTON] = Input->Is_Button_Down (VK_LBUTTON); LastMouseButtonState[MB_MBUTTON] = Input->Is_Button_Down (VK_MBUTTON); LastMouseButtonState[MB_RBUTTON] = Input->Is_Button_Down (VK_RBUTTON); return ; } //////////////////////////////////////////////////////////////// // // Register_Dialog // //////////////////////////////////////////////////////////////// void DialogMgrClass::Register_Dialog (DialogBaseClass *dialog) { // // Check to see if this dialog is already in our list // if (DialogList.ID (dialog) == -1) { Reset_Inputs (); // // Keep a lock on the dialog // dialog->Add_Ref (); // // Add the dialog to our list. Note: We keep popup dialogs // as the topmost windows in our z order. Z order is determined // by the order in the list. // bool is_top_level = true; if (dialog->As_PopupDialogClass () == NULL) { int new_index = DialogList.Count () - 1; for (; new_index >= 0; new_index --) { if (DialogList[new_index]->As_PopupDialogClass () == NULL) { break; } is_top_level = false; } DialogList.Insert (new_index + 1, dialog); } else { DialogList.Add (dialog); } // // Make this the active dialog // if (is_top_level && dialog->Wants_Activation ()) { Set_Active_Dialog (dialog); } // // Update the framework // On_Dialog_Added (); // // Handle the first dialog... // if (DialogList.Count () == 1) { MouseMgrClass::Show_Cursor (true); IsFirstRender = true; } } return ; } //////////////////////////////////////////////////////////////// // // UnRegister_Dialog // //////////////////////////////////////////////////////////////// void DialogMgrClass::UnRegister_Dialog (DialogBaseClass *dialog) { // // Is this dialog in our list? // int index = DialogList.ID (dialog); if (index != -1) { Reset_Inputs (); // // Remove the dialog from our list // DialogList.Delete (index); REF_PTR_RELEASE (dialog); // // Update the framework // On_Dialog_Removed (); } return ; } //////////////////////////////////////////////////////////////// // // On_Dialog_Added // //////////////////////////////////////////////////////////////// void DialogMgrClass::On_Dialog_Added (void) { // // Center the mouse in the window // #if (0) HWND wnd = (HWND)WW3D::Get_Window (); RECT rect = { 0 }; ::GetClientRect (wnd, &rect); #endif //(0) /*Vector3 mouse_pos = Get_Mouse_Pos (); mouse_pos.X = rect.left + (rect.right - rect.left) / 2; mouse_pos.Y = rect.top + (rect.bottom - rect.top) / 2; Set_Mouse_Pos (mouse_pos);*/ return ; } //////////////////////////////////////////////////////////////// // // On_Dialog_Removed // //////////////////////////////////////////////////////////////// void DialogMgrClass::On_Dialog_Removed (void) { // // Are there any dialogs left? // if (DialogList.Count () == 0) { // // Revert from "dialog" mode. // MouseMgrClass::Show_Cursor (false); Set_Active_Dialog (NULL); } else if (IsFlushing == false) { // // Force "focus" to go to the most recent dialog // int index = DialogList.Count (); while (index --) { if (DialogList[index]->Wants_Activation ()) { Set_Active_Dialog (DialogList[index]); break; } } } return ; } //////////////////////////////////////////////////////////////// // // Update_Transition // //////////////////////////////////////////////////////////////// void DialogMgrClass::Update_Transition (void) { if (Transition != NULL) { // // Allow the transition to think // Transition->On_Frame_Update (); Transition->Render (); // // Did the transition finish? // if (Transition->Is_Complete ()) { // // Let the dialog controls be displayed (as necessary) // if (TransitionDialog != NULL) { TransitionDialog->Set_Controls_Hidden (false); } if (PendingActiveDialog != NULL) { PendingActiveDialog->Set_Controls_Hidden (false); } // // Now make the pending dialog active // Internal_Set_Active_Dialog (PendingActiveDialog); PendingActiveDialog = NULL; TransitionDialog = NULL; // // Release our hold on the transition // REF_PTR_RELEASE (Transition); } } return ; } //////////////////////////////////////////////////////////////// // // On_Frame_Update // //////////////////////////////////////////////////////////////// void DialogMgrClass::On_Frame_Update (void) { WWMEMLOG(MEM_GAMEDATA); // // Update the timing // uint32 old_time = CurrTime; CurrTime = TIMEGETTIME (); LastFrameTime = CurrTime - old_time; // DynamicVectorClass test_list = DialogList; if (DialogList.Count()>TestArrayMaxCount) { delete[] TestArray; TestArrayMaxCount=DialogList.Count(); TestArray=new DialogBaseClass*[TestArrayMaxCount]; } TestArrayCount=DialogList.Count(); for (int i=0;i= TestArrayCount || DialogList[index] != TestArray[index]) { break; } DialogBaseClass* dialog = DialogList[index]; WWASSERT(dialog != NULL); dialog->Add_Ref(); if (dialog->Is_Active () && dialog->As_ChildDialogClass () == NULL) { dialog->On_Frame_Update (); } // // Force an "On_Periodic" for dialogs that aren't in focus... // dialog->On_Periodic (); dialog->Release_Ref(); } // // Return from "dialog" mode if the ESC key has been let up... // if (IsInMenuMode && DialogList.Count () == 0 && ((KeyboardState[VK_ESCAPE] & 0x80) == 0)) { IsInMenuMode = false; Input->Exit_Menu_Mode (); } return ; } //////////////////////////////////////////////////////////////// // // Render // //////////////////////////////////////////////////////////////// void DialogMgrClass::Render (void) { WWMEMLOG(MEM_GAMEDATA); if (!GameInFocus) { GameWasInFocus=false; return; } if (!GameWasInFocus) { DialogMgrClass::Reset(); GameWasInFocus=true; } // // Enable static sorting levels // bool enable_static_sort = WW3D::Are_Static_Sort_Lists_Enabled (); WW3D::Enable_Static_Sort_Lists (true); // // Enable the "console" mode if this is the first dialog // we're rendering // if (IsFirstRender) { IsFirstRender = false; IsInMenuMode = true; Input->Enter_Menu_Mode (); } // // Update any transitions // Update_Transition (); // // Render each dialog // for (int index = 0; index < DialogList.Count (); index ++) { bool render = false; // // Should this dialog be rendered? // DialogBaseClass *dialog = DialogList[index]; if ( dialog->Is_Visible () /*&& dialog != PendingActiveDialog && dialog != TransitionOutDialog*/ ) { // // Don't render here if its a child-dialog // render = (dialog->As_ChildDialogClass () == NULL); } // // Render the dialog // if (render) { dialog->Render (); } } // // Render the tooltip // Vector3 cursor_pos = Get_Mouse_Pos (); ToolTipMgrClass::Update (Vector2 (cursor_pos.X, cursor_pos.Y)); ToolTipMgrClass::Render (); if ((mIMEMessageTime > CurrTime) && mIMEMessage) { mIMEMessage->Render(); } // // Render the mouse cursor // MouseMgrClass::Render (); // // Update the cached mouse button states // Reset_Inputs (); // // Put the static sort flag back the way we found it // WW3D::Enable_Static_Sort_Lists (enable_static_sort); return ; } //////////////////////////////////////////////////////////////// // // Set_Active_Dialog // //////////////////////////////////////////////////////////////// void DialogMgrClass::Set_Active_Dialog (DialogBaseClass *dialog) { if (ActiveDialog == dialog) { return ; } //REF_PTR_RELEASE (Transition); if (Transition != NULL) { PendingActiveDialog = dialog; return ; } // // Check to see if we should play an outro-transition for // the currently active dialog // if (ActiveDialog != NULL) { Transition = ActiveDialog->Get_Transition_Out (dialog); if (Transition != NULL) { PendingActiveDialog = dialog; TransitionDialog = ActiveDialog; // // Hide the controls on the pending dialog (if necessary) // if (PendingActiveDialog != NULL) { //PendingActiveDialog->Set_Controls_Hidden (true); } } } // // Check to see if we should play an intro-transition for // the new active dialog // if (dialog != NULL && Transition == NULL) { Transition = dialog->Get_Transition_In (ActiveDialog); if (Transition != NULL) { PendingActiveDialog = dialog; TransitionDialog = dialog; // // Hide the controls on the transitioning dialog // //TransitionDialog->Set_Controls_Hidden (true); } } // // If we don't have any transition to play, then simply // set the active dialog // if (Transition == NULL) { Internal_Set_Active_Dialog (dialog); } return ; } void DialogMgrClass::Reset (void) { // REF_PTR_RELEASE (Transition); // if (PendingActiveDialog) { // REF_PTR_SET(ActiveDialog,PendingActiveDialog); // REF_PTR_RELEASE(PendingActiveDialog); // } // Internal_Set_Active_Dialog (ActiveDialog); if (ActiveDialog) { ActiveDialog->Set_Dirty(); } if (PendingActiveDialog) { PendingActiveDialog->Set_Dirty(); } } //////////////////////////////////////////////////////////////// // // Internal_Set_Active_Dialog // //////////////////////////////////////////////////////////////// void DialogMgrClass::Internal_Set_Active_Dialog (DialogBaseClass *dialog) { // // Get rid of the input capture and focus // Release_Capture (); // // Switch the active dialog // DialogBaseClass *old_dialog = ActiveDialog; ActiveDialog = dialog; // // Notify the old dialog // if (old_dialog != NULL) { old_dialog->On_Activate (false); REF_PTR_RELEASE (old_dialog); } Set_Focus (NULL); // // Notify the new dialog (if necessary) // if (ActiveDialog != NULL) { ActiveDialog->Add_Ref (); ActiveDialog->On_Activate (true); } // // Remove any tooltips // ToolTipMgrClass::Reset (); return ; } //////////////////////////////////////////////////////////////// // // On_Key_Down // //////////////////////////////////////////////////////////////// bool DialogMgrClass::On_Key_Down (uint32 key_id, uint32 key_data) { if (Transition != NULL) { return false; } // // Update the keyboard state // ::GetKeyboardState (KeyboardState); // // Notify the active dialog (if any) // if (ActiveDialog != NULL) { return ActiveDialog->On_Key_Down (key_id, key_data); } return false; } //////////////////////////////////////////////////////////////// // // On_Key_Up // //////////////////////////////////////////////////////////////// bool DialogMgrClass::On_Key_Up (uint32 key_id) { if (Transition != NULL) { return false; } // // Update the keyboard state // ::GetKeyboardState (KeyboardState); // // Notify the active dialog (if any) // if (ActiveDialog != NULL) { return ActiveDialog->On_Key_Up (key_id); } return false; } //////////////////////////////////////////////////////////////// // // On_Unicode_Char // //////////////////////////////////////////////////////////////// void DialogMgrClass::On_Unicode_Char (uint16 unicode) { if (Transition != NULL) { return ; } // // Update the keyboard state // ::GetKeyboardState (KeyboardState); // // Notify the active dialog (if any) // if (ActiveDialog != NULL) { ActiveDialog->On_Unicode_Char (unicode); } return ; } //////////////////////////////////////////////////////////////// // // Find_Control // //////////////////////////////////////////////////////////////// DialogControlClass * DialogMgrClass::Find_Control (const Vector2 &mouse_pos) { DialogControlClass *retval = NULL; // // Get this information from the active dialog // if (ActiveDialog != NULL) { retval = ActiveDialog->Find_Control (mouse_pos); } return retval; } //////////////////////////////////////////////////////////////// // // Set_Capture // //////////////////////////////////////////////////////////////// void DialogMgrClass::Set_Capture (DialogControlClass *control) { InputCapture = control; return ; } //////////////////////////////////////////////////////////////// // // Release_Capture // //////////////////////////////////////////////////////////////// void DialogMgrClass::Release_Capture (void) { InputCapture = NULL; return ; } //////////////////////////////////////////////////////////////// // // Flush_Dialogs // //////////////////////////////////////////////////////////////// void DialogMgrClass::Flush_Dialogs (void) { WWDEBUG_SAY(("DialogMgrClass: Flushing dialogs\n")); IsFlushing = true; Set_Active_Dialog (NULL); // // Remove all the dialogs from our list // while (DialogList.Count () > 0) { DialogList[DialogList.Count () - 1]->End_Dialog (); } Set_Focus (NULL); // // Reset our transition variables // TransitionDialog = NULL; PendingActiveDialog = NULL; REF_PTR_RELEASE (Transition); // // Release our hold on the transitioning dialogs // //REF_PTR_RELEASE (TransitionInDialog); //REF_PTR_RELEASE (TransitionOutDialog); // // Reset the list // DialogList.Delete_All (); IsFlushing = false; WWDEBUG_SAY(("DialogMgrClass: Flush complete\n")); return ; } bool DialogMgrClass::Is_Flushing_Dialogs(void) { return IsFlushing; } //////////////////////////////////////////////////////////////// // // Was_Button_Down // //////////////////////////////////////////////////////////////// bool DialogMgrClass::Was_Button_Down (int vk_mouse_button_id) { bool retval = false; switch (vk_mouse_button_id) { case VK_LBUTTON: retval = LastMouseButtonState[MB_LBUTTON]; break; case VK_MBUTTON: retval = LastMouseButtonState[MB_MBUTTON]; break; case VK_RBUTTON: retval = LastMouseButtonState[MB_RBUTTON]; break; } return retval; } //////////////////////////////////////////////////////////////// // // Set_Focus // //////////////////////////////////////////////////////////////// void DialogMgrClass::Set_Focus (DialogControlClass *control) { if (FocusControl == control) { return ; } // // Change the focus // DialogControlClass *old_focus_ctrl = FocusControl; FocusControl = control; // // Let go of the currently focus'd control // if (old_focus_ctrl != NULL) { old_focus_ctrl->On_Kill_Focus (control); } // // Reset the focus // if (FocusControl != NULL) { FocusControl->On_Set_Focus (); } // // Remove the input capture // Release_Capture (); return ; } DialogBaseClass* DialogMgrClass::Find_Dialog(int dialogID) { for (int index = 0; index < DialogList.Count(); ++index) { if (DialogList[index]->Get_Dlg_ID() == dialogID) { return DialogList[index]; } } return NULL; } //////////////////////////////////////////////////////////////// // // Rollback // //////////////////////////////////////////////////////////////// void DialogMgrClass::Rollback (DialogBaseClass *dialog) { for (int index = DialogList.Count () - 1; index >= 0; index --) { // // Stop once we've come across the dialog we're rolling back to // if (DialogList[index] == dialog) { break; } // // Close this dialog (if necessary) // if (DialogList[index]->As_ChildDialogClass () == NULL) { DialogList[index]->End_Dialog (); } } return ; } void DialogMgrClass::Show_IME_Message(const wchar_t* message, uint32 duration) { if (mIMEMessage == NULL) { mIMEMessage = new ToolTipClass; } if (mIMEMessage) { mIMEMessage->Set_Position(Vector2(10,10)); mIMEMessage->Set_Text(message); mIMEMessageTime = (CurrTime + duration); } }