/*
** 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 .
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: WinMain.cpp //////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: GUIEdit.cpp
//
// Created: Colin Day, July 2001
//
// Desc: GUI Edit and window layout entry point
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
#include
#include
#include
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "Common/Debug.h"
#include "Common/GameMemory.h"
#include "Common/GameEngine.h"
#include "GameClient/GameWindowManager.h"
#include "Win32Device/GameClient/Win32Mouse.h"
#include "Resource.h"
#include "Lib/BaseType.h"
#include "GUIEdit.h"
#include "EditWindow.h"
#include "DialogProc.h"
#include "LayoutScheme.h"
// DEFINES ////////////////////////////////////////////////////////////////////
// PRIVATE TYPES //////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
static char *szWindowClass = "GUIEdit";
// PUBLIC DATA ////////////////////////////////////////////////////////////////
HINSTANCE ApplicationHInstance; ///< main application instance
HWND ApplicationHWnd; ///< main application HWnd
Win32Mouse *TheWin32Mouse = NULL; ///< for Win32 mouse
char *gAppPrefix = "ge_"; /// So GuiEdit can have a different debug log file name if we need it
const Char *g_strFile = "data\\Generals.str";
const Char *g_csfFile = "data\\%s\\Generals.csf";
///////////////////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK AboutCallback(HWND, UINT, WPARAM, LPARAM);
///////////////////////////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// initInstance ===============================================================
//
// FUNCTION: initInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
//=============================================================================
static BOOL initInstance( HINSTANCE hInstance, int nCmdShow )
{
// store application instance
ApplicationHInstance = hInstance;
// create app window and keep handle
ApplicationHWnd = CreateWindowEx( 0, // extended style
szWindowClass, // window class name
"GUIEdit", // window name
WS_OVERLAPPEDWINDOW, // window styles
0, // x position
0, // y position
GetSystemMetrics( SM_CXSCREEN ), // width
GetSystemMetrics( SM_CYSCREEN ), // height
NULL, // parent
NULL, // menu
ApplicationHInstance, // instance
NULL ); // creation data
if( ApplicationHWnd == NULL )
return FALSE;
// display the window
ShowWindow( ApplicationHWnd, SW_MAXIMIZE );
UpdateWindow( ApplicationHWnd );
return TRUE;
} // end initInstance
// registerClass ==============================================================
//
// FUNCTION: registerClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage is only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
//=============================================================================
static ATOM registerClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof( WNDCLASSEX );
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)GUIEDIT_LARGE_ICON);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
wcex.lpszMenuName = (LPCSTR)GUIEDIT_MENU;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)GUIEDIT_SMALL_ICON);
return RegisterClassEx( &wcex );
} // registerClass
///////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// WinMain ====================================================================
/** Entry point for application */
//=============================================================================
Int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
Int returnValue;
HACCEL hAccelTable;
Bool quit = FALSE;
/// @todo remove this force set of working directory later
Char buffer[ _MAX_PATH ];
GetModuleFileName( NULL, buffer, sizeof( buffer ) );
Char *pEnd = buffer + strlen( buffer );
while( pEnd != buffer )
{
if( *pEnd == '\\' )
{
*pEnd = 0;
break;
}
pEnd--;
}
::SetCurrentDirectory(buffer);
// start the log
DEBUG_INIT(DEBUG_FLAGS_DEFAULT);
initMemoryManager();
// register a class for our window with the OS
registerClass( hInstance );
// Perform application initialization:
if( !initInstance( hInstance, nCmdShow ) )
return FALSE;
// load accellerator table
hAccelTable = LoadAccelerators( hInstance, (LPCTSTR)GUIEDIT_ACCELERATORS );
// initialize the common controls
INITCOMMONCONTROLSEX controls;
controls.dwSize = sizeof( controls );
controls.dwICC = ICC_BAR_CLASSES;
InitCommonControlsEx( &controls );
// initialize GUIEdit data
TheEditor = new GUIEdit;
if( TheEditor == NULL )
return FALSE;
TheEditor->init();
//
// see if we have any messages to process, a NULL window handle tells the
// OS to look at the main window associated with the calling thread, us!
//
while( quit == FALSE )
{
// is there is message ready for us?
if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
{
// process ALL messages waiting
while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
{
// get the message
returnValue = GetMessage( &msg, NULL, 0, 0 );
// check for quitting
if( returnValue == 0 )
quit = TRUE;
// translate accelerator messages
if( !TranslateAccelerator( msg.hwnd, hAccelTable, &msg ) )
{
// translate and dispatch the message
TranslateMessage( &msg );
DispatchMessage( &msg );
} // end if
} // end while
} // end if
else
{
// udpate our universe
TheEditor->update();
Sleep(1);
} // end else
} // end while
// shutdown GUIEdit data
delete TheEditor;
TheEditor = NULL;
// close the log
shutdownMemoryManager();
DEBUG_SHUTDOWN();
return msg.wParam;
} // end WinMain
// WndProc ====================================================================
//
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//=============================================================================
LRESULT CALLBACK WndProc( HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam )
{
switch( message )
{
// ------------------------------------------------------------------------
case WM_MOUSEMOVE:
{
// keep focus in our app
if( GetFocus() != hWnd )
SetFocus( hWnd );
return 0;
} // end move mouse
// ------------------------------------------------------------------------
case WM_COMMAND:
{
Int controlID = LOWORD( wParam );
// Int nofifyCode = HIWORD( wParam );
// HWND hWndControl = (HWND)lParam;
switch( controlID )
{
// --------------------------------------------------------------------
case MENU_EXIT:
TheEditor->menuExit();
break;
//---------------------------------------------------------------------
case MENU_NEW:
TheEditor->menuNew();
break;
// --------------------------------------------------------------------
case MENU_OPEN:
TheEditor->menuOpen();
break;
// --------------------------------------------------------------------
case MENU_SAVE:
TheEditor->menuSave();
break;
// --------------------------------------------------------------------
case MENU_SAVEAS:
TheEditor->menuSaveAs();
break;
// --------------------------------------------------------------------
case MENU_COPY:
TheEditor->menuCopy();
break;
// --------------------------------------------------------------------
case MENU_CUT:
TheEditor->menuCut();
break;
// --------------------------------------------------------------------
case MENU_PASTE:
TheEditor->menuPaste();
break;
// --------------------------------------------------------------------
case MENU_CALLBACKS:
DialogBox( TheEditor->getInstance(), (LPCTSTR)CALLBACK_EDITOR_DIALOG,
TheEditor->getWindowHandle(), CallbackEditorDialogProc );
break;
// --------------------------------------------------------------------
case MENU_GRID_SETTINGS:
DialogBox( TheEditor->getInstance(), (LPCTSTR)GRID_SETTINGS_DIALOG,
TheEditor->getWindowHandle(), GridSettingsDialogProc );
break;
// --------------------------------------------------------------------
case MENU_SHOW_HIDDEN_OUTLINES:
TheEditor->setShowHiddenOutlines( !TheEditor->getShowHiddenOutlines() );
break;
// --------------------------------------------------------------------
case MENU_SHOW_SEE_THRU_OUTLINES:
TheEditor->setShowSeeThruOutlines( !TheEditor->getShowSeeThruOutlines() );
break;
// --------------------------------------------------------------------
case MENU_TEST_MODE:
// switch to test mode or edit mode
if( TheEditor)
{
EditMode mode = TheEditor->getMode();
if( mode != MODE_TEST_RUN )
TheEditor->setMode( MODE_TEST_RUN );
else
TheEditor->setMode( MODE_EDIT );
} // end if
break;
// --------------------------------------------------------------------
case MENU_BACKGROUND_COLOR:
if( TheEditWindow )
{
RGBColorReal color = TheEditWindow->getBackgroundColor();
RGBColorInt *newColor;
POINT mouse;
// get mouse point
GetCursorPos( &mouse );
// select a new color
newColor = SelectColor( (Int)(255.0f * color.red),
(Int)(255.0f * color.green),
(Int)(255.0f * color.blue),
(Int)(255.0f * color.alpha),
mouse.x, mouse.y );
if( newColor )
{
color.red = (Real)newColor->red / 255.0f;
color.green = (Real)newColor->green / 255.0f;
color.blue = (Real)newColor->blue / 255.0f;
color.alpha = (Real)newColor->alpha / 255.0f;
TheEditWindow->setBackgroundColor( color );
} // end if
} // end if
break;
// --------------------------------------------------------------------
case MENU_SCHEME:
{
// open the default scheme information
if( TheDefaultScheme )
TheDefaultScheme->openDialog();
break;
} // end scheme
// --------------------------------------------------------------------
case MENU_ABOUT:
{
DialogBox( ApplicationHInstance, (LPCTSTR)ABOUT_DIALOG,
hWnd, (DLGPROC)AboutCallback );
break;
} // end about
// --------------------------------------------------------------------
default:
{
return DefWindowProc( hWnd, message, wParam, lParam );
} // end default
} // end switch( controlID )
return 0;
} // end command
// ------------------------------------------------------------------------
case WM_CLOSE:
{
// close gets initiated from the 'x' in the top right of the window
TheEditor->menuExit();
return 0;
} // end close
// ------------------------------------------------------------------------
case WM_KEYDOWN:
{
Int virtualKey = wParam;
// Int keyData = lParam;
Bool controlDown = BitTest( GetKeyState( VK_CONTROL ), 0x1000 );
switch( virtualKey )
{
// --------------------------------------------------------------------
case VK_ESCAPE:
{
// unselect all windows
if( TheEditor )
if(TheEditor->getMode() == MODE_KEYBOARD_MOVE)
TheEditor->setMode( MODE_EDIT );
else
TheEditor->clearSelections();
break;
} // end escape
// --------------------------------------------------------------------
case VK_DELETE:
{
// delete all selected windows
if( TheEditor )
TheEditor->deleteSelected();
break;
} // end delete
// --------------------------------------------------------------------
case VK_LEFT:
{
// delete all selected windows
if( TheEditor && TheEditWindow)
{
if(TheEditor->getMode() == MODE_EDIT)
{
if(TheEditor->selectionCount() <= 0 )
break;
ICoord2D zero;
zero.x = zero.y = 0;
TheEditWindow->setDragMoveOrigin(&zero);
TheEditWindow->setDragMoveDest(&zero);
TheEditor->setMode(MODE_KEYBOARD_MOVE);
}
if(TheEditor->getMode() == MODE_KEYBOARD_MOVE)
{
ICoord2D temp;
temp = TheEditWindow->getDragMoveDest();
if(!controlDown && TheEditor->isGridSnapOn())
{
temp.x -= TheEditor->getGridResolution();
TheEditor->gridSnapLocation(&temp,&temp);
}
else
{
temp.x--;
}
TheEditWindow->setDragMoveDest(&temp);
}
}
break;
} // end Left
// --------------------------------------------------------------------
case VK_RIGHT:
{
// delete all selected windows
if( TheEditor && TheEditWindow)
{
if(TheEditor->getMode() == MODE_EDIT)
{
if(TheEditor->selectionCount() <= 0 )
break;
ICoord2D zero;
zero.x = zero.y = 0;
TheEditWindow->setDragMoveOrigin(&zero);
TheEditWindow->setDragMoveDest(&zero);
TheEditor->setMode(MODE_KEYBOARD_MOVE);
}
if(TheEditor->getMode() == MODE_KEYBOARD_MOVE)
{
ICoord2D temp;
temp = TheEditWindow->getDragMoveDest();
if(!controlDown && TheEditor->isGridSnapOn())
{
temp.x += TheEditor->getGridResolution();
TheEditor->gridSnapLocation(&temp,&temp);
}
else
{
temp.x++;
}
TheEditWindow->setDragMoveDest(&temp);
}
}
break;
} // end RIGHT
// --------------------------------------------------------------------
case VK_UP:
{
// delete all selected windows
if( TheEditor && TheEditWindow)
{
if(TheEditor->getMode() == MODE_EDIT)
{
if(TheEditor->selectionCount() <= 0 )
break;
ICoord2D zero;
zero.x = zero.y = 0;
TheEditWindow->setDragMoveOrigin(&zero);
TheEditWindow->setDragMoveDest(&zero);
TheEditor->setMode(MODE_KEYBOARD_MOVE);
}
if(TheEditor->getMode() == MODE_KEYBOARD_MOVE)
{
ICoord2D temp;
temp = TheEditWindow->getDragMoveDest();
if(!controlDown && TheEditor->isGridSnapOn())
{
temp.y -= TheEditor->getGridResolution();
TheEditor->gridSnapLocation(&temp,&temp);
}
else
{
temp.y--;
}
TheEditWindow->setDragMoveDest(&temp);
}
}
break;
} // end Up
// --------------------------------------------------------------------
case VK_DOWN:
{
// delete all selected windows
if( TheEditor && TheEditWindow)
{
if(TheEditor->getMode() == MODE_EDIT)
{
if(TheEditor->selectionCount() <= 0 )
break;
ICoord2D zero;
zero.x = zero.y = 0;
TheEditWindow->setDragMoveOrigin(&zero);
TheEditWindow->setDragMoveDest(&zero);
TheEditor->setMode(MODE_KEYBOARD_MOVE);
}
if(TheEditor->getMode() == MODE_KEYBOARD_MOVE)
{
ICoord2D temp;
temp = TheEditWindow->getDragMoveDest();
if(!controlDown && TheEditor->isGridSnapOn())
{
temp.y += TheEditor->getGridResolution();
TheEditor->gridSnapLocation(&temp,&temp);
}
else
{
temp.y++;
}
TheEditWindow->setDragMoveDest(&temp);
}
}
break;
} // end Down
// --------------------------------------------------------------------
case VK_RETURN:
{
if( TheEditor && TheEditWindow && TheEditor->getMode() == MODE_KEYBOARD_MOVE )
{
ICoord2D tempOrigin, tempDest;
tempDest = TheEditWindow->getDragMoveDest();
tempOrigin = TheEditWindow->getDragMoveOrigin();
// move the windows
TheEditor->dragMoveSelectedWindows( &tempOrigin, &tempDest );
// go back to normal mode
TheEditor->setMode( MODE_EDIT );
}
break;
}// end Enter
} // end switch( virtualKey )
return 0;
} // end key down
// ------------------------------------------------------------------------
case WM_SIZE:
{
Int width = LOWORD( lParam );
Int height = HIWORD( lParam );
// resize status bar
if( TheEditor )
{
HWND statusBar = TheEditor->getStatusBarWindowHandle();
if( statusBar )
{
RECT rect;
Int barX, barY;
Int barWidth, barHeight;
// keep status window height the same
GetWindowRect( statusBar, &rect );
barWidth = width;
barHeight = rect.bottom - rect.top;
barX = 0;
barY = height - barHeight;
MoveWindow( statusBar, barX, barY, barWidth, barHeight, TRUE );
} // end if
} // end if
return 0;
} // end size
// ------------------------------------------------------------------------
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
} // end paint
// ------------------------------------------------------------------------
case WM_DESTROY:
{
PostQuitMessage(0);
break;
} // end destroy
// ------------------------------------------------------------------------
default:
{
return DefWindowProc(hWnd, message, wParam, lParam);
} // end default
} // end switch( message )
return DefWindowProc( hWnd, message, wParam, lParam );
} // end WndProc
// AboutCallback ==============================================================
/** Mesage handler for about box. */
//=============================================================================
LRESULT CALLBACK AboutCallback( HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam )
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
} // end AboutCallback