dhewm3/neo/tools/guied/GEApp.cpp

1383 lines
33 KiB
C++

/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
Doom 3 Source Code 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.
Doom 3 Source Code 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "tools/edit_gui_common.h"
#include <io.h>
#include "../../sys/win32/rc/guied_resource.h"
#include "../../ui/DeviceContext.h"
#include "GEApp.h"
#include "GEOptionsDlg.h"
#include "GEViewer.h"
static const int IDM_WINDOWCHILD = 1000;
static const int ID_GUIED_FILE_MRU1 = 10000;
static INT_PTR CALLBACK AboutDlg_WndProc ( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch ( msg )
{
case WM_COMMAND:
EndDialog ( hwnd, 1 );
break;
}
return FALSE;
}
rvGEApp::rvGEApp ( )
{
mMDIFrame = NULL;
mMDIClient = NULL;
mRecentFileMenu = NULL;
mViewer = NULL;
mRecentFileInsertPos = 0;
}
rvGEApp::~rvGEApp ( )
{
DestroyAcceleratorTable ( mAccelerators );
}
/*
================
rvGEApp::Initialize
Initialize the gui editor application
================
*/
bool rvGEApp::Initialize ( void )
{
mOptions.Init();
// Mutually exclusive
com_editors = EDITOR_GUI;
Sys_GrabMouseCursor( false );
// Load the options
mOptions.Load ( );
mInstance = win32.hInstance;
// Create the accelerators
mAccelerators = LoadAccelerators ( mInstance, MAKEINTRESOURCE(IDR_GUIED_ACCELERATORS) );
// Register the window classes for the main frame and the mdi child window
WNDCLASSEX wndClass;
memset ( &wndClass, 0, sizeof(wndClass) );
wndClass.cbSize = sizeof(WNDCLASSEX);
wndClass.lpszClassName = "QUAKE4_GUIEDITOR_CLASS";
wndClass.lpfnWndProc = FrameWndProc;
wndClass.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE + 1);
wndClass.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW);
wndClass.lpszMenuName = MAKEINTRESOURCE(IDR_GUIED_MAIN);
wndClass.hInstance = mInstance;
RegisterClassEx ( &wndClass );
wndClass.lpszMenuName = NULL;
wndClass.lpfnWndProc = MDIChildProc;
wndClass.lpszClassName = "QUAKE4_GUIEDITOR_CHILD_CLASS";
wndClass.style = CS_OWNDC|CS_DBLCLKS|CS_BYTEALIGNWINDOW|CS_VREDRAW|CS_HREDRAW;
wndClass.hbrBackground = (HBRUSH)GetStockObject( LTGRAY_BRUSH );
RegisterClassEx ( &wndClass );
// Create the main window
mMDIFrame = CreateWindow ( "QUAKE4_GUIEDITOR_CLASS",
"Quake IV GUI Editor",
WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, mInstance, (LPVOID)this );
if ( !mMDIFrame )
{
return false;
}
SetClassLongPtr( mMDIFrame, GCLP_HICON, (LONG_PTR)LoadIcon( win32.hInstance, MAKEINTRESOURCE( IDI_GUIED ) ) );
// Create the MDI window
CLIENTCREATESTRUCT ccs;
ccs.hWindowMenu = GetSubMenu ( GetMenu ( mMDIFrame ), 5 );
ccs.idFirstChild = IDM_WINDOWCHILD;
mMDIClient = CreateWindow ( "MDICLIENT", NULL,
WS_CHILDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
0, 0, 1000, 1000,
mMDIFrame, NULL,
mInstance, &ccs );
if ( !mMDIClient )
{
DestroyWindow ( mMDIFrame );
return false;
}
// hide the doom window by default
::ShowWindow ( win32.hWnd, SW_HIDE );
// Show both windows
mOptions.GetWindowPlacement ( "mdiframe", mMDIFrame );
ShowWindow ( mMDIFrame, SW_SHOW );
UpdateWindow ( mMDIFrame );
ShowWindow ( mMDIClient, SW_SHOW );
UpdateWindow ( mMDIClient );
return true;
}
/*
================
rvGEApp::GetActiveWorkspace
Retrieves the workspace pointer for the active workspace. If there is no active
workspace then it will return NULL
================
*/
rvGEWorkspace* rvGEApp::GetActiveWorkspace ( HWND* ret )
{
rvGEWorkspace* workspace;
HWND active;
workspace = NULL;
active = (HWND)SendMessage ( mMDIClient, WM_MDIGETACTIVE, 0, NULL );
// Return the window handle if requested
if ( ret )
{
*ret = active;
}
if ( !active )
{
return NULL;
}
return rvGEWorkspace::GetWorkspace ( active );
}
/*
================
rvGEApp::TranslateAccelerator
Translate any accelerators destined for this window
================
*/
bool rvGEApp::TranslateAccelerator ( LPMSG msg )
{
HWND focus;
if ( msg->message == WM_SYSCHAR )
{
SetFocus ( GetMDIClient ( ) );
msg->hwnd = GetMDIClient ( );
}
if ( mViewer )
{
return false;
}
focus = GetActiveWindow ( );
// Only use accelerators when on the main window or navigator window
if ( focus == mMDIClient || focus == mMDIFrame ||
focus == GetNavigator().GetWindow ( ) )
{
if ( ::TranslateAccelerator ( mMDIFrame, mAccelerators, msg ) )
{
return true;
}
}
if ( TranslateMDISysAccel ( mMDIClient, msg ) )
{
return true;
}
return false;
}
/*
================
rvGEApp::RunFrame
Runs the current frame which causes the active window to be redrawn
================
*/
void rvGEApp::RunFrame ( void )
{
HWND wnd;
rvGEWorkspace* workspace = GetActiveWorkspace ( &wnd );
if ( workspace )
{
// Render the workspace using a temp DC
HDC hDC = GetDC ( wnd );
workspace->Render ( hDC );
ReleaseDC ( wnd, hDC );
if ( mViewer )
{
mViewer->RunFrame ( );
}
}
}
/*
================
rvGEApp::FrameWndProc
Main frame window procedure
================
*/
LRESULT CALLBACK rvGEApp::FrameWndProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
rvGEApp* app = (rvGEApp*) GetWindowLongPtr ( hWnd, GWLP_USERDATA );
switch ( uMsg )
{
case WM_SIZE:
{
RECT rStatus;
RECT rClient;
// Tell the status bar to resize
app->mStatusBar.Resize ( LOWORD(lParam), HIWORD(lParam) );
// Calculate the new client window rectangle (minus the status bar)
GetWindowRect ( app->mStatusBar.GetWindow ( ), &rStatus );
GetClientRect ( hWnd, &rClient );
if ( app->mOptions.GetStatusBarVisible ( ) )
{
rClient.bottom -= (rStatus.bottom-rStatus.top);
}
MoveWindow ( app->mMDIClient, 0, 0, rClient.right-rClient.left, rClient.bottom-rClient.top, FALSE );
return 0;
}
case WM_ENABLE:
{
int i;
// Synchronise all toolwindows to the same state.
for(i = 0; i < app->mToolWindows.Num(); i++)
{
if(app->mToolWindows[i] != hWnd)
{
EnableWindow(app->mToolWindows[i], wParam);
}
}
break;
}
case WM_NCACTIVATE:
return app->ToolWindowActivate ( hWnd, uMsg, wParam, lParam );
case WM_ACTIVATE:
common->ActivateTool( LOWORD( wParam ) != WA_INACTIVE );
break;
case WM_INITMENUPOPUP:
app->HandleInitMenu ( wParam, lParam );
break;
case WM_CLOSE:
while ( app->mWorkspaces.Num ( ) )
{
SendMessage ( app->mWorkspaces[0]->GetWindow ( ), WM_CLOSE, 0, 0 );
}
break;
case WM_DESTROY:
app->mOptions.SetWindowPlacement ( "mdiframe", hWnd );
app->mOptions.Save ( );
ExitProcess(0);
break;
case WM_COMMAND:
{
int result;
assert ( app );
result = app->HandleCommand ( wParam, lParam );
if ( -1 != result )
{
return result;
}
break;
}
case WM_CREATE:
{
LPCREATESTRUCT cs;
cs = (LPCREATESTRUCT) lParam;
app = (rvGEApp*)cs->lpCreateParams;
assert ( app );
SetWindowLongPtr( hWnd, GWLP_USERDATA, (LONG_PTR)app );
app->mMDIFrame = hWnd;
app->InitRecentFiles ( );
app->UpdateRecentFiles ( );
app->mNavigator.Create ( hWnd, gApp.mOptions.GetNavigatorVisible ( ) );
app->mTransformer.Create ( hWnd, gApp.mOptions.GetTransformerVisible ( ) );
app->mStatusBar.Create ( hWnd, 9999, gApp.mOptions.GetStatusBarVisible ( ) );
app->mProperties.Create ( hWnd, gApp.mOptions.GetPropertiesVisible ( ) );
// add all the tool windows to the tool window array
app->mToolWindows.Append ( app->mMDIFrame );
app->mToolWindows.Append ( app->mNavigator.GetWindow ( ) );
app->mToolWindows.Append ( app->mProperties.GetWindow ( ) );
app->mToolWindows.Append ( app->mTransformer.GetWindow ( ) );
SendMessage ( app->mNavigator.GetWindow ( ), WM_NCACTIVATE, true, (LONG)-1 );
SendMessage ( app->mProperties.GetWindow ( ), WM_NCACTIVATE, true, (LONG)-1 );
SendMessage ( app->mTransformer.GetWindow ( ), WM_NCACTIVATE, true, (LONG)-1 );
break;
}
}
return DefFrameProc ( hWnd, app?app->mMDIClient:NULL, uMsg, wParam, lParam );
}
/*
================
rvGEApp::MDIChildProc
MDI Child window procedure
================
*/
LRESULT CALLBACK rvGEApp::MDIChildProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
rvGEWorkspace* workspace = (rvGEWorkspace*)GetWindowLongPtr ( hWnd, GWLP_USERDATA );
// Give the active workspace a chance to play with it
if ( workspace )
{
workspace->HandleMessage ( uMsg, wParam, lParam );
}
switch ( uMsg )
{
case WM_CLOSE:
workspace->GetApplication ( )->mWorkspaces.Remove ( workspace );
break;
case WM_CREATE:
{
LPMDICREATESTRUCT mdics;
LPCREATESTRUCT cs;
// MDI windows have their creation params buried two levels deep, extract
// that param since it is the workspace pointer
cs = (LPCREATESTRUCT) lParam;
mdics = (LPMDICREATESTRUCT) cs->lpCreateParams;
// Attach the workspace to the window
workspace = (rvGEWorkspace*) mdics->lParam;
workspace->Attach ( hWnd );
workspace->GetApplication ( )->mWorkspaces.Append ( workspace );
break;
}
case WM_MDIACTIVATE:
assert ( workspace );
if ( (HWND)lParam == hWnd )
{
workspace->GetApplication ( )->GetNavigator().SetWorkspace(workspace);
workspace->GetApplication ( )->GetTransformer().SetWorkspace(workspace);
workspace->GetApplication ( )->GetProperties().SetWorkspace(workspace);
gApp.GetStatusBar ( ).SetSimple ( false );
}
else if ( lParam == NULL )
{
gApp.GetStatusBar ( ).SetSimple ( true );
}
break;
case WM_DESTROY:
assert ( workspace );
workspace->Detach ( );
delete workspace;
break;
case WM_SETCURSOR:
return 1;
case WM_ERASEBKGND:
return TRUE;
case WM_PAINT:
{
HDC dc;
PAINTSTRUCT ps;
dc = BeginPaint(hWnd, &ps);
if ( workspace )
{
workspace->Render ( dc );
}
EndPaint(hWnd, &ps);
break;
}
}
return DefMDIChildProc ( hWnd, uMsg, wParam, lParam );
}
/*
================
rvGEApp::HandleCommandSave
Handles the ID_GUIED_FILE_SAVE and ID_GUIED_FILE_SAVEAS commands
================
*/
void rvGEApp::HandleCommandSave ( rvGEWorkspace* workspace, const char* filename )
{
idStr realFilename;
// See if we need to browse for a filename
if ( workspace->IsNew ( ) || filename == NULL )
{
OPENFILENAME ofn;
char szFile[MAX_PATH];
strcpy ( szFile, workspace->GetFilename ( ) );
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = mMDIFrame;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = "GUI Files\0*.GUI\0All Files\0*.*\0";
ofn.nFilterIndex = 1;
ofn.Flags = OFN_PATHMUSTEXIST;
// Display the save dialog box.
if ( !GetSaveFileName(&ofn) )
{
return;
}
realFilename = ofn.lpstrFile;
realFilename.StripFileExtension ( );
realFilename.Append ( ".gui" );
// If the file already exists then warn about overwriting it
if ( _taccess ( realFilename, 0 ) == 0 )
{
if ( IDNO == MessageBox ( va("File '%s' already exists. Do you want to replace it?", realFilename.c_str()), MB_YESNO|MB_ICONQUESTION ) )
{
return;
}
}
}
else
{
realFilename = filename;
}
// Now performe the file save
if ( workspace->SaveFile ( realFilename ) )
{
mOptions.AddRecentFile ( workspace->GetFilename ( ) );
UpdateRecentFiles ( );
}
else
{
MessageBox ( va("Could not write file '%s'", workspace->GetFilename()), MB_OK|MB_ICONERROR );
}
}
/*
================
rvGEApp::HandleCommand
Handles the WM_COMMAND message
================
*/
int rvGEApp::HandleCommand ( WPARAM wParam, LPARAM lParam )
{
HWND active;
rvGEWorkspace* workspace = GetActiveWorkspace ( &active );
// The recent file list needs to be handled specially
if ( LOWORD(wParam) >= ID_GUIED_FILE_MRU1 && LOWORD(wParam) < ID_GUIED_FILE_MRU1 + rvGEOptions::MAX_MRU_SIZE )
{
OpenFile ( mOptions.GetRecentFile ( mOptions.GetRecentFileCount() - (LOWORD(wParam)-ID_GUIED_FILE_MRU1) - 1 ) );
return 0;
}
switch ( LOWORD ( wParam ) )
{
case ID_GUIED_SOURCECONTROL_CHECKIN:
assert ( workspace );
HandleCommandSave ( workspace, workspace->GetFilename ( ) );
workspace->CheckIn ( );
break;
case ID_GUIED_SOURCECONTROL_CHECKOUT:
assert ( workspace );
workspace->CheckOut ( );
break;
case ID_GUIED_SOURCECONTROL_UNDOCHECKOUT:
assert ( workspace );
if ( IDYES == MessageBox ( va("Are you sure you want to undo the checkout of the file '%s'?",workspace->GetFilename()), MB_YESNO|MB_ICONQUESTION) )
{
workspace->UndoCheckout ( );
}
break;
case ID_GUIED_TOOLS_RELOADMATERIALS:
SetCursor ( LoadCursor ( NULL, MAKEINTRESOURCE(IDC_WAIT) ) );
cmdSystem->BufferCommandText( CMD_EXEC_NOW, "reloadImages\n" );
cmdSystem->BufferCommandText( CMD_EXEC_NOW, "reloadMaterials\n" );
SetCursor ( LoadCursor ( NULL, MAKEINTRESOURCE(IDC_ARROW) ) );
break;
case ID_GUIED_EDIT_COPY:
assert ( workspace );
workspace->Copy ( );
break;
case ID_GUIED_EDIT_PASTE:
assert ( workspace );
workspace->Paste ( );
break;
case ID_GUIED_HELP_ABOUT:
DialogBox ( GetInstance(), MAKEINTRESOURCE(IDD_GUIED_ABOUT), mMDIFrame, AboutDlg_WndProc );
break;
case ID_GUIED_TOOLS_VIEWER:
{
if ( mViewer )
{
break;
}
mViewer = new rvGEViewer;
if ( !mViewer->Create ( mMDIFrame ) )
{
delete mViewer;
mViewer = NULL;
}
if ( workspace )
{
if ( !workspace->IsModified () || HandleCommand ( MAKELONG(ID_GUIED_FILE_SAVE,0), 0 ) )
{
mViewer->OpenFile ( workspace->GetFilename ( ) );
}
}
SetActiveWindow ( mViewer->GetWindow ( ) );
break;
}
case ID_GUIED_ITEM_MAKESAMESIZEWIDTH:
assert ( workspace );
workspace->MakeSelectedSameSize ( true, false );
break;
case ID_GUIED_ITEM_MAKESAMESIZEBOTH:
assert ( workspace );
workspace->MakeSelectedSameSize ( true, true );
break;
case ID_GUIED_ITEM_MAKESAMESIZEHEIGHT:
assert ( workspace );
workspace->MakeSelectedSameSize ( false, true );
break;
case ID_GUIED_ITEM_ALIGNLEFTS:
assert ( workspace );
workspace->AlignSelected ( rvGEWorkspace::ALIGN_LEFTS );
break;
case ID_GUIED_ITEM_ALIGNCENTERS:
assert ( workspace );
workspace->AlignSelected ( rvGEWorkspace::ALIGN_CENTERS );
break;
case ID_GUIED_ITEM_ALIGNRIGHTS:
assert ( workspace );
workspace->AlignSelected ( rvGEWorkspace::ALIGN_RIGHTS );
break;
case ID_GUIED_ITEM_ALIGNTOPS:
assert ( workspace );
workspace->AlignSelected ( rvGEWorkspace::ALIGN_TOPS );
break;
case ID_GUIED_ITEM_ALIGNMIDDLES:
assert ( workspace );
workspace->AlignSelected ( rvGEWorkspace::ALIGN_MIDDLES );
break;
case ID_GUIED_ITEM_ALIGNBOTTOMS:
assert ( workspace );
workspace->AlignSelected ( rvGEWorkspace::ALIGN_BOTTOMS );
break;
case ID_GUIED_ITEM_ARRANGESENDBACKWARD:
assert ( workspace );
workspace->SendSelectedBackward ( );
break;
case ID_GUIED_ITEM_ARRANGESENDTOBACK:
assert ( workspace );
workspace->SendSelectedToBack( );
break;
case ID_GUIED_ITEM_ARRANGEBRINGFORWARD:
assert ( workspace );
workspace->BringSelectedForward ( );
break;
case ID_GUIED_ITEM_ARRANGEBRINGTOFRONT:
assert ( workspace );
workspace->BringSelectedToFront ( );
break;
case ID_GUIED_ITEM_ARRANGEMAKECHILD:
assert ( workspace );
workspace->MakeSelectedAChild ( );
break;
case ID_GUIED_ITEM_PROPERTIES:
assert ( workspace );
workspace->EditSelectedProperties ( );
break;
case ID_GUIED_ITEM_SCRIPTS:
assert ( workspace );
workspace->EditSelectedScripts ( );
break;
case ID_GUIED_ITEM_NEWWINDOWDEF:
assert ( workspace );
workspace->AddWindow ( rvGEWindowWrapper::WT_NORMAL );
break;
case ID_GUIED_ITEM_NEWEDITDEF:
assert ( workspace );
workspace->AddWindow ( rvGEWindowWrapper::WT_EDIT );
break;
case ID_GUIED_ITEM_NEWHTMLDEF:
assert ( workspace );
workspace->AddWindow ( rvGEWindowWrapper::WT_HTML );
break;
case ID_GUIED_ITEM_NEWCHOICEDEF:
assert ( workspace );
workspace->AddWindow ( rvGEWindowWrapper::WT_CHOICE );
break;
case ID_GUIED_ITEM_NEWSLIDERDEF:
assert ( workspace );
workspace->AddWindow ( rvGEWindowWrapper::WT_SLIDER );
break;
case ID_GUIED_ITEM_NEWLISTDEF:
assert ( workspace );
workspace->AddWindow ( rvGEWindowWrapper::WT_LIST );
break;
case ID_GUIED_ITEM_NEWBINDDEF:
assert ( workspace );
workspace->AddWindow ( rvGEWindowWrapper::WT_BIND );
break;
case ID_GUIED_ITEM_NEWRENDERDEF:
assert ( workspace );
workspace->AddWindow ( rvGEWindowWrapper::WT_RENDER );
break;
case ID_GUIED_WINDOW_TILE:
SendMessage ( mMDIClient, WM_MDITILE, 0, 0 );
break;
case ID_GUIED_WINDOW_CASCADE:
SendMessage ( mMDIClient, WM_MDICASCADE, 0, 0 );
break;
case ID_GUIED_VIEW_STATUSBAR:
{
RECT rWindow;
mStatusBar.Show ( mOptions.GetStatusBarVisible()?false:true );
GetWindowRect ( mMDIFrame, &rWindow );
SendMessage ( mMDIFrame, WM_SIZE, 0, MAKELONG ( rWindow.right-rWindow.left, rWindow.bottom-rWindow.top ) );
break;
}
case ID_GUIED_WINDOW_SHOWNAVIGATOR:
mNavigator.Show ( mOptions.GetNavigatorVisible()?false:true );
break;
case ID_GUIED_WINDOW_SHOWPROPERTIES:
mProperties.Show ( mOptions.GetPropertiesVisible()?false:true );
break;
case ID_GUIED_WINDOW_SHOWTRANSFORMER:
mTransformer.Show ( mOptions.GetTransformerVisible()?false:true );
break;
case ID_GUIED_EDIT_DELETE:
assert ( workspace );
workspace->DeleteSelected ( );
break;
case ID_GUIED_VIEW_HIDESELECTED:
assert ( workspace );
workspace->HideSelected ( );
break;
case ID_GUIED_VIEW_UNHIDESELECTED:
assert ( workspace );
workspace->UnhideSelected ( );
break;
case ID_GUIED_VIEW_SHOWHIDDEN:
assert ( workspace );
workspace->ShowHidden ( );
break;
case ID_GUIED_EDIT_UNDO:
assert ( workspace );
workspace->GetModifierStack().Undo ( );
mNavigator.Update ( );
mTransformer.Update ( );
break;
case ID_GUIED_EDIT_REDO:
assert ( workspace );
workspace->GetModifierStack().Redo ( );
mNavigator.Update ( );
mTransformer.Update ( );
break;
case ID_GUIED_VIEW_OPTIONS:
GEOptionsDlg_DoModal ( mMDIFrame );
break;
case ID_GUIED_VIEW_SHOWGRID:
mOptions.SetGridVisible ( mOptions.GetGridVisible()?false:true );
break;
case ID_GUIED_VIEW_SNAPTOGRID:
mOptions.SetGridSnap ( mOptions.GetGridSnap ()?false:true );
break;
case ID_GUIED_VIEW_ZOOMIN:
assert ( workspace );
workspace->ZoomIn ( );
break;
case ID_GUIED_VIEW_ZOOMOUT:
assert ( workspace );
workspace->ZoomOut ( );
break;
case ID_GUIED_FILE_EXIT:
DestroyWindow ( mMDIFrame );
break;
case ID_GUIED_FILE_CLOSE:
if ( active )
{
assert ( workspace );
SendMessage ( active, WM_CLOSE, 0, 0 );
}
break;
case ID_GUIED_FILE_NEW:
NewFile ( );
break;
case ID_GUIED_FILE_SAVE:
assert ( workspace );
HandleCommandSave ( workspace, workspace->GetFilename ( ) );
break;
case ID_GUIED_FILE_SAVEAS:
assert ( workspace );
HandleCommandSave ( workspace, NULL );
break;
case ID_GUIED_FILE_OPEN:
{
OPENFILENAME ofn;
char szFile[MAX_PATH] = "";
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = mMDIFrame;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = "GUI Files\0*.GUI\0All Files\0*.*\0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
// Display the Open dialog box.
if (GetOpenFileName(&ofn)==TRUE)
{
OpenFile ( ofn.lpstrFile );
}
break;
}
}
return -1;
}
/*
================
rvGEApp::HandleInitMenu
Handles the initialization of the main menu
================
*/
int rvGEApp::HandleInitMenu ( WPARAM wParam, LPARAM lParam )
{
int cMenuItems = GetMenuItemCount((HMENU)wParam);
int nPos;
int id;
UINT flags;
rvGEWorkspace* workspace;
HMENU hmenu;
hmenu = (HMENU) wParam;
workspace = GetActiveWorkspace ( );
// Run through all the menu items in the menu and see if any of them need
// modification in any way
for (nPos = 0; nPos < cMenuItems; nPos++)
{
id = GetMenuItemID(hmenu, nPos);
flags = 0;
// Handle popup menus too
if ( id < 0 )
{
HMENU sub = GetSubMenu ( hmenu, nPos );
if ( sub )
{
HandleInitMenu ( (WPARAM) sub, 0 );
continue;
}
}
// Menu items that are completely unrelated to the workspace
switch ( id )
{
case ID_GUIED_VIEW_STATUSBAR:
flags = MF_BYCOMMAND | (mOptions.GetStatusBarVisible()?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem ( hmenu, id, flags );
break;
case ID_GUIED_WINDOW_SHOWNAVIGATOR:
flags = MF_BYCOMMAND | (mOptions.GetNavigatorVisible()?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem ( hmenu, id, flags );
break;
case ID_GUIED_WINDOW_SHOWPROPERTIES:
flags = MF_BYCOMMAND | (mOptions.GetPropertiesVisible()?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem ( hmenu, id, flags );
break;
case ID_GUIED_WINDOW_SHOWTRANSFORMER:
flags = MF_BYCOMMAND | (mOptions.GetTransformerVisible()?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem ( hmenu, id, flags );
break;
}
// Handle the basic case where an item is disabled because
// there is no workspace available
if ( !workspace )
{
switch ( id )
{
case ID_GUIED_EDIT_UNDO:
case ID_GUIED_EDIT_REDO:
case ID_GUIED_VIEW_SHOWGRID:
case ID_GUIED_VIEW_SNAPTOGRID:
case ID_GUIED_VIEW_HIDESELECTED:
case ID_GUIED_VIEW_UNHIDESELECTED:
case ID_GUIED_EDIT_DELETE:
case ID_GUIED_WINDOW_TILE:
case ID_GUIED_WINDOW_CASCADE:
case ID_GUIED_ITEM_NEWWINDOWDEF:
case ID_GUIED_ITEM_NEWEDITDEF:
case ID_GUIED_ITEM_NEWHTMLDEF:
case ID_GUIED_ITEM_ARRANGEBRINGTOFRONT:
case ID_GUIED_ITEM_ARRANGEBRINGFORWARD:
case ID_GUIED_ITEM_ARRANGESENDTOBACK:
case ID_GUIED_ITEM_ARRANGESENDBACKWARD:
case ID_GUIED_ITEM_PROPERTIES:
case ID_GUIED_ITEM_SCRIPTS:
case ID_GUIED_VIEW_ZOOMIN:
case ID_GUIED_VIEW_ZOOMOUT:
case ID_GUIED_ITEM_ALIGNLEFTS:
case ID_GUIED_ITEM_ALIGNCENTERS:
case ID_GUIED_ITEM_ALIGNRIGHTS:
case ID_GUIED_ITEM_ALIGNBOTTOMS:
case ID_GUIED_ITEM_ALIGNMIDDLES:
case ID_GUIED_ITEM_ALIGNTOPS:
case ID_GUIED_ITEM_MAKESAMESIZEHEIGHT:
case ID_GUIED_ITEM_MAKESAMESIZEWIDTH:
case ID_GUIED_ITEM_MAKESAMESIZEBOTH:
case ID_GUIED_FILE_SAVE:
case ID_GUIED_FILE_SAVEAS:
case ID_GUIED_EDIT_COPY:
case ID_GUIED_EDIT_PASTE:
case ID_GUIED_ITEM_ARRANGEMAKECHILD:
case ID_GUIED_SOURCECONTROL_GETLATESTVERSION:
case ID_GUIED_SOURCECONTROL_CHECKIN:
case ID_GUIED_SOURCECONTROL_CHECKOUT:
case ID_GUIED_SOURCECONTROL_UNDOCHECKOUT:
case ID_GUIED_FILE_CLOSE:
EnableMenuItem ( hmenu, nPos, MF_GRAYED|MF_BYPOSITION );
break;
}
continue;
}
switch (id)
{
// Undo is greyed out when there is noting to undo and the text is
// modified to include the name of the modifier that will be undone
case ID_GUIED_EDIT_UNDO:
{
MENUITEMINFO info;
idStr undo;
info.cbSize = sizeof(info);
info.fMask = MIIM_STATE|MIIM_TYPE;
info.fType = MFT_STRING;
if ( !workspace->GetModifierStack().CanUndo ( ) )
{
undo = "Undo\tCtrl+Z";
info.fState = MFS_GRAYED;
}
else
{
undo = "Undo ";
undo.Append ( workspace->GetModifierStack().GetUndoModifier()->GetName ( ) );
undo.Append ( "\tCtrl+Z" );
info.fState = MFS_ENABLED;
}
info.dwTypeData = (LPSTR)undo.c_str();
info.cch = undo.Length ( );
SetMenuItemInfo ( hmenu, id, FALSE, &info );
break;
}
case ID_GUIED_EDIT_REDO:
{
MENUITEMINFO info;
idStr undo;
info.cbSize = sizeof(info);
info.fMask = MIIM_STATE|MIIM_TYPE;
info.fType = MFT_STRING;
if ( !workspace || !workspace->GetModifierStack().CanRedo ( ) )
{
undo = "Redo\tCtrl+Y";
info.fState = MFS_GRAYED;
}
else
{
undo = "Redo ";
undo.Append ( workspace->GetModifierStack().GetRedoModifier()->GetName ( ) );
undo.Append ( "\tCtrl+Y" );
info.fState = MFS_ENABLED;
}
info.dwTypeData = (LPSTR)undo.c_str();
info.cch = undo.Length ( );
SetMenuItemInfo ( hmenu, id, FALSE, &info );
break;
}
case ID_GUIED_VIEW_SHOWGRID:
flags = MF_BYCOMMAND | (mOptions.GetGridVisible()?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem ( hmenu, id, flags );
break;
case ID_GUIED_VIEW_SNAPTOGRID:
flags = MF_BYCOMMAND | (mOptions.GetGridSnap()?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem ( hmenu, id, flags );
break;
// All menu items that are greyed out when there is no workspace
case ID_GUIED_WINDOW_TILE:
case ID_GUIED_WINDOW_CASCADE:
case ID_GUIED_ITEM_NEWWINDOWDEF:
case ID_GUIED_ITEM_NEWEDITDEF:
case ID_GUIED_ITEM_NEWHTMLDEF:
case ID_GUIED_VIEW_ZOOMIN:
case ID_GUIED_VIEW_ZOOMOUT:
case ID_GUIED_FILE_SAVE:
case ID_GUIED_FILE_SAVEAS:
case ID_GUIED_FILE_CLOSE:
EnableMenuItem ( hmenu, nPos, MF_ENABLED|MF_BYPOSITION);
break;
// All menu items that are greyed out unless an item is selected
case ID_GUIED_VIEW_HIDESELECTED:
case ID_GUIED_VIEW_UNHIDESELECTED:
case ID_GUIED_EDIT_DELETE:
case ID_GUIED_EDIT_COPY:
EnableMenuItem ( hmenu, nPos, MF_BYPOSITION|(workspace->GetSelectionMgr().Num()>0?MF_ENABLED:MF_GRAYED) );
break;
// Enable paste if the clipboard has something in it
case ID_GUIED_EDIT_PASTE:
EnableMenuItem ( hmenu, nPos, MF_BYPOSITION|(workspace->GetClipboard().Num()>0?MF_ENABLED:MF_GRAYED) );
break;
// All menu items that are greyed out unless a single item is selected
case ID_GUIED_ITEM_ARRANGEBRINGTOFRONT:
case ID_GUIED_ITEM_ARRANGEBRINGFORWARD:
case ID_GUIED_ITEM_ARRANGESENDTOBACK:
case ID_GUIED_ITEM_ARRANGESENDBACKWARD:
case ID_GUIED_ITEM_PROPERTIES:
case ID_GUIED_ITEM_SCRIPTS:
EnableMenuItem ( hmenu, nPos, MF_BYPOSITION|(workspace->GetSelectionMgr().Num()==1?MF_ENABLED:MF_GRAYED) );
break;
// All menu items that are greyed out unless multiple itmes are selected
case ID_GUIED_ITEM_ALIGNLEFTS:
case ID_GUIED_ITEM_ALIGNCENTERS:
case ID_GUIED_ITEM_ALIGNRIGHTS:
case ID_GUIED_ITEM_ALIGNBOTTOMS:
case ID_GUIED_ITEM_ALIGNMIDDLES:
case ID_GUIED_ITEM_ALIGNTOPS:
case ID_GUIED_ITEM_MAKESAMESIZEHEIGHT:
case ID_GUIED_ITEM_MAKESAMESIZEBOTH:
case ID_GUIED_ITEM_MAKESAMESIZEWIDTH:
case ID_GUIED_ITEM_ARRANGEMAKECHILD:
EnableMenuItem ( hmenu, nPos, MF_BYPOSITION|(workspace->GetSelectionMgr().Num()>1?MF_ENABLED:MF_GRAYED) );
break;
case ID_GUIED_SOURCECONTROL_CHECKIN:
case ID_GUIED_SOURCECONTROL_UNDOCHECKOUT:
EnableMenuItem ( hmenu, nPos, MF_BYPOSITION|((workspace->GetSourceControlState()==rvGEWorkspace::SCS_CHECKEDOUT)?MF_ENABLED:MF_GRAYED) );
break;
case ID_GUIED_SOURCECONTROL_CHECKOUT:
EnableMenuItem ( hmenu, nPos, MF_BYPOSITION|((workspace->GetSourceControlState()==rvGEWorkspace::SCS_CHECKEDIN)?MF_ENABLED:MF_GRAYED) );
break;
default:
continue;
}
}
return 0;
}
/*
================
rvGEApp::NewFile
Creates a new file and opens a window for it
================
*/
bool rvGEApp::NewFile ( void )
{
rvGEWorkspace* workspace = new rvGEWorkspace ( this );
if ( workspace->NewFile ( ) )
{
HWND child;
child = CreateMDIWindow("QUAKE4_GUIEDITOR_CHILD_CLASS",
"Untitled.gui",
WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|WS_HSCROLL|WS_VSCROLL|WS_MAXIMIZE,
CW_USEDEFAULT,
CW_USEDEFAULT,
640,
480,
mMDIClient,
mInstance,
(LONG)workspace );
ShowWindow ( child, SW_SHOW );
}
return true;
}
/*
================
rvGEApp::OpenFile
Opens the given file and will fail if its already open or could not
be opened for some reason
================
*/
bool rvGEApp::OpenFile ( const char* filename )
{
int i;
bool result = false;
idStr error;
// See if the file is already open and if so just make it active
for ( i = 0; i < mWorkspaces.Num(); i ++ )
{
if ( !idStr::Icmp ( mWorkspaces[i]->GetFilename(), filename ) )
{
SendMessage ( mMDIClient, WM_MDIACTIVATE, (WPARAM)mWorkspaces[i]->GetWindow ( ), 0 );
return false;
}
}
SetCursor ( LoadCursor ( NULL, MAKEINTRESOURCE(IDC_WAIT ) ) );
// Setup the default error.
error = va("Failed to parse '%s'", filename );
rvGEWorkspace* workspace = new rvGEWorkspace ( this );
if ( workspace->LoadFile ( filename, &error ) )
{
HWND child;
child = CreateMDIWindow("QUAKE4_GUIEDITOR_CHILD_CLASS",
"Unamed.gui",
WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|WS_HSCROLL|WS_VSCROLL|WS_MAXIMIZE,
CW_USEDEFAULT,
CW_USEDEFAULT,
640,
480,
mMDIClient,
mInstance,
(LONG)workspace );
ShowWindow ( child, SW_SHOW );
mOptions.AddRecentFile ( filename );
UpdateRecentFiles ( );
result = true;
}
else
{
MessageBox ( error, MB_OK|MB_ICONERROR );
}
SetCursor ( LoadCursor ( NULL, MAKEINTRESOURCE(IDC_ARROW ) ) );
return result;;
}
/*
================
rvGEApp::InitRecentFiles
Finds the file menu and the location within it where the MRU should
be added.
================
*/
bool rvGEApp::InitRecentFiles ( void )
{
int i;
int count;
mRecentFileMenu = GetSubMenu ( GetMenu(mMDIFrame), 0 );
count = GetMenuItemCount ( mRecentFileMenu );
for ( i = 0; i < count; i ++ )
{
if ( GetMenuItemID ( mRecentFileMenu, i ) == ID_GUIED_FILE_MRU )
{
mRecentFileInsertPos = i;
DeleteMenu ( mRecentFileMenu, mRecentFileInsertPos, MF_BYPOSITION );
return true;
}
}
return false;
}
/*
================
rvGEApp::UpdateRecentFiles
Updates the mru in the menu
================
*/
void rvGEApp::UpdateRecentFiles ( void )
{
int i;
int j;
// Make sure everything is initialized
if ( !mRecentFileMenu )
{
InitRecentFiles ( );
}
// Delete all the old recent files from the menu's
for ( i = 0; i < rvGEOptions::MAX_MRU_SIZE; i ++ )
{
DeleteMenu ( mRecentFileMenu, ID_GUIED_FILE_MRU1 + i, MF_BYCOMMAND );
}
// Make sure there is a separator after the recent files
if ( mOptions.GetRecentFileCount() )
{
MENUITEMINFO info;
ZeroMemory ( &info, sizeof(info) );
info.cbSize = sizeof(info);
info.fMask = MIIM_FTYPE;
GetMenuItemInfo ( mRecentFileMenu, mRecentFileInsertPos+1,TRUE, &info );
if ( !(info.fType & MFT_SEPARATOR ) )
{
InsertMenu ( mRecentFileMenu, mRecentFileInsertPos, MF_BYPOSITION|MF_SEPARATOR|MF_ENABLED, 0, NULL );
}
}
// Add the recent files to the menu now
for ( j = 0, i = mOptions.GetRecentFileCount ( ) - 1; i >= 0; i --, j++ )
{
UINT id = ID_GUIED_FILE_MRU1 + j;
idStr str = va("&%d ", j+1);
str.Append ( mOptions.GetRecentFile ( i ) );
InsertMenu ( mRecentFileMenu, mRecentFileInsertPos+j+1, MF_BYPOSITION|MF_STRING|MF_ENABLED, id, str );
}
}
/*
================
rvGEApp::CloseViewer
Closes the gui viewer
================
*/
void rvGEApp::CloseViewer ( void )
{
if ( !mViewer )
{
return;
}
mViewer->Destroy ( );
delete mViewer;
mViewer = NULL;
}
/*
================
rvGEApp::ToolWindowActivate
Handles the nc activate message for all tool windows
================
*/
int rvGEApp::ToolWindowActivate ( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
bool keepActive;
bool syncOthers;
int i;
keepActive = ( wParam != 0 );
syncOthers = true;
for ( i = 0; i < mToolWindows.Num (); i ++ )
{
if ( (HWND)lParam == mToolWindows[i] )
{
keepActive = true;
syncOthers = false;
break;
}
}
if ( lParam == -1 )
{
return DefWindowProc ( hwnd, WM_NCACTIVATE, keepActive, 0 );
}
if ( syncOthers )
{
for ( i = 0; i < mToolWindows.Num(); i ++ )
{
if ( mToolWindows[i] != hwnd && mToolWindows[i] != (HWND) lParam )
{
SendMessage ( mToolWindows[i], WM_NCACTIVATE, keepActive, (LONG)-1 );
}
}
}
return DefWindowProc ( hwnd, WM_NCACTIVATE, keepActive, lParam );
}
/*
================
rvGEApp::MessageBox
Displays a modal message box
================
*/
int rvGEApp::MessageBox ( const char* text, int flags )
{
return ::MessageBox ( mMDIFrame, text, "Quake 4 GUI Editor", flags );
}