/* =========================================================================== Copyright (C) 1999-2005 Id Software, Inc. This file is part of Quake III Arena source code. Quake III Arena 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 2 of the License, or (at your option) any later version. Quake III Arena 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 Foobar; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ #include "stdafx.h" #include "qe3.h" #include "entityw.h" #include "TexWnd.h" #include "WaveOpen.h" int rgIds[EntLast] = { IDC_E_LIST, IDC_E_COMMENT, IDC_CHECK1, IDC_CHECK2, IDC_CHECK3, IDC_CHECK4, IDC_CHECK5, IDC_CHECK6, IDC_CHECK7, IDC_CHECK8, IDC_CHECK9, IDC_CHECK10, IDC_CHECK11, IDC_CHECK12, IDC_E_PROPS, IDC_E_0, IDC_E_45, IDC_E_90, IDC_E_135, IDC_E_180, IDC_E_225, IDC_E_270, IDC_E_315, IDC_E_UP, IDC_E_DOWN, IDC_E_DELPROP, IDC_STATIC_KEY, IDC_E_KEY_FIELD, IDC_STATIC_VALUE, IDC_E_VALUE_FIELD, IDC_E_COLOR, IDC_BTN_ASSIGNSOUND, IDC_BTN_ASSIGNMODEL }; HWND hwndEnt[EntLast]; CTabCtrl g_wndTabs; int inspector_mode; // W_TEXTURE, W_ENTITY, or W_CONSOLE qboolean multiple_entities; entity_t *edit_entity; BOOL CALLBACK EntityWndProc( HWND hwndDlg, // handle to dialog box UINT uMsg, // message WPARAM wParam, // first message parameter LPARAM lParam); // second message parameter void SizeEntityDlg(int iWidth, int iHeight); void AddProp(); void GetTexMods(void); LRESULT (CALLBACK* OldFieldWindowProc) (HWND, UINT, WPARAM, LPARAM); LRESULT (CALLBACK* OldEntityListWindowProc) (HWND, UINT, WPARAM, LPARAM); /* ========================= FieldWndProc Just to handle tab and enter... ========================= */ BOOL CALLBACK FieldWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CHAR: if (LOWORD(wParam) == VK_TAB) return FALSE; if (LOWORD(wParam) == VK_RETURN) return FALSE; if (LOWORD(wParam) == VK_ESCAPE) { SetFocus (g_qeglobals.d_hwndCamera); return FALSE; } break; case WM_KEYDOWN: if (LOWORD(wParam) == VK_TAB) { if (hwnd == hwndEnt[EntKeyField]) { SendMessage (hwndEnt[EntValueField], WM_SETTEXT, 0, (long)""); SetFocus (hwndEnt[EntValueField]); } else SetFocus (hwndEnt[EntKeyField]); } if (LOWORD(wParam) == VK_RETURN) { if (hwnd == hwndEnt[EntKeyField]) { SendMessage (hwndEnt[EntValueField], WM_SETTEXT, 0, (long)""); SetFocus (hwndEnt[EntValueField]); } else { AddProp (); SetFocus (g_qeglobals.d_hwndCamera); } } break; // case WM_NCHITTEST: case WM_LBUTTONDOWN: SetFocus (hwnd); break; } return CallWindowProc (OldFieldWindowProc, hwnd, uMsg, wParam, lParam); } /* ========================= EntityListWndProc Just to handle enter... ========================= */ BOOL CALLBACK EntityListWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_KEYDOWN: if (LOWORD(wParam) == VK_RETURN) { SendMessage ( g_qeglobals.d_hwndEntity, WM_COMMAND, (LBN_DBLCLK<<16) + IDC_E_LIST, 0 ); return 0; } break; } return CallWindowProc (OldEntityListWindowProc, hwnd, uMsg, wParam, lParam); } /* ================ GetEntityControls Finds the controls from the dialog and moves them to the window ================ */ void GetEntityControls(HWND ghwndEntity) { int i; for (i = 0; i < EntLast; i++) { if (i == EntList || i == EntProps || i == EntComment) continue; if (i == EntKeyField || i == EntValueField) continue; hwndEnt[i] = GetDlgItem(ghwndEntity, rgIds[i]); if (hwndEnt[i]) { SetParent (hwndEnt[i], g_qeglobals.d_hwndEntity ); SendMessage(hwndEnt[i], WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)TRUE); } } // SetParent apears to not modify some internal state // on listboxes, so create it from scratch... hwndEnt[EntList] = CreateWindow ("listbox", NULL, LBS_STANDARD | LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | WS_VSCROLL | WS_CHILD | WS_VISIBLE, 5, 5, 180, 99, g_qeglobals.d_hwndEntity, (HMENU)IDC_E_LIST, g_qeglobals.d_hInstance, NULL); if (!hwndEnt[EntList]) Error ("CreateWindow failed"); hwndEnt[EntProps] = CreateWindow ("listbox", NULL, LBS_STANDARD | LBS_NOINTEGRALHEIGHT | LBS_USETABSTOPS | WS_VSCROLL | WS_CHILD | WS_VISIBLE, 5, 100, 180, 99, g_qeglobals.d_hwndEntity, (HMENU)IDC_E_PROPS, g_qeglobals.d_hInstance, NULL); if (!hwndEnt[EntProps]) Error ("CreateWindow failed"); hwndEnt[EntComment] = CreateWindow ("edit", NULL, ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER, 5, 100, 180, 99, g_qeglobals.d_hwndEntity, (HMENU)IDC_E_COMMENT, g_qeglobals.d_hInstance, NULL); if (!hwndEnt[EntComment]) Error ("CreateWindow failed"); hwndEnt[EntKeyField] = CreateWindow ("edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 5, 100, 180, 99, g_qeglobals.d_hwndEntity, (HMENU)IDC_E_KEY_FIELD, g_qeglobals.d_hInstance, NULL); if (!hwndEnt[EntKeyField]) Error ("CreateWindow failed"); hwndEnt[EntValueField] = CreateWindow ("edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 5, 100, 180, 99, g_qeglobals.d_hwndEntity, (HMENU)IDC_E_VALUE_FIELD, g_qeglobals.d_hInstance, NULL); if (!hwndEnt[EntValueField]) Error ("CreateWindow failed"); g_wndTabs.SubclassDlgItem(IDC_TAB_MODE, CWnd::FromHandle(ghwndEntity)); hwndEnt[EntTab] = g_wndTabs.GetSafeHwnd(); g_wndTabs.InsertItem(0, "Groups"); ::SetParent(g_wndTabs.GetSafeHwnd(), g_qeglobals.d_hwndEntity); if (g_pParentWnd->CurrentStyle() > 0 && g_pParentWnd->CurrentStyle() < 3) { g_qeglobals.d_hwndEdit = CreateWindow ("edit", NULL, ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER, 5, 100, 180, 99, g_qeglobals.d_hwndEntity, (HMENU)IDC_E_STATUS, g_qeglobals.d_hInstance, NULL); if (!g_qeglobals.d_hwndEdit) Error ("CreateWindow failed"); g_wndTabs.InsertItem(0, "Console"); g_wndTabs.InsertItem(0, "Textures"); } g_wndTabs.InsertItem(0, "Entities"); g_wndTabs.ShowWindow(SW_SHOW); #if 0 for (i=0 ; i<12 ; i++) { hwndEnt[EntCheck1 + i] = CreateWindow ("button", NULL, BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE, 5, 100, 180, 99, entwindow, (HMENU)IDC_E_STATUS, main_instance, NULL); if (!hwndEnt[EntCheck1 + i]) Error ("CreateWindow failed"); } #endif SendMessage(hwndEnt[EntList], WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)TRUE); SendMessage(hwndEnt[EntProps], WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)TRUE); SendMessage(hwndEnt[EntComment], WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)TRUE); SendMessage(hwndEnt[EntKeyField], WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)TRUE); SendMessage(hwndEnt[EntValueField], WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)TRUE); SendMessage(hwndEnt[EntTab], WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)TRUE); if (g_pParentWnd->CurrentStyle() > 0 && g_pParentWnd->CurrentStyle() < 3) SendMessage(g_qeglobals.d_hwndEdit, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)TRUE); } /* =============================================================== ENTITY WINDOW =============================================================== */ void FillClassList (void) { eclass_t *pec; int iIndex; SendMessage(hwndEnt[EntList], LB_RESETCONTENT, 0 , 0); for (pec = eclass ; pec ; pec = pec->next) { iIndex = SendMessage(hwndEnt[EntList], LB_ADDSTRING, 0 , (LPARAM)pec->name); SendMessage(hwndEnt[EntList], LB_SETITEMDATA, iIndex, (LPARAM)pec); } } /* ============== WEnt_Create ============== */ void WEnt_Create (HINSTANCE hInstance) { WNDCLASS wc; /* Register the camera class */ memset (&wc, 0, sizeof(wc)); wc.style = CS_NOCLOSE | CS_OWNDC; wc.lpfnWndProc = (WNDPROC)EntityWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = 0; wc.hCursor = LoadCursor (NULL,IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject (LTGRAY_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = ENT_WINDOW_CLASS; RegisterClass (&wc); int nStyle = (g_pParentWnd->CurrentStyle() == QR_QE4) ? QE3_STYLE : QE3_STYLE2; g_qeglobals.d_hwndEntity = CreateWindow (ENT_WINDOW_CLASS , "Entity", nStyle, 20, 20, 100, 480, // size g_qeglobals.d_hwndMain, // parent 0, // no menu hInstance, NULL); if (!g_qeglobals.d_hwndEntity ) Error ("Couldn't create Entity window"); } /* ============== CreateEntityWindow ============== */ BOOL CreateEntityWindow(HINSTANCE hInstance) { HWND hwndEntityPalette; inspector_mode = W_ENTITY; WEnt_Create (hInstance); hwndEntityPalette = CreateDialog(hInstance, (char *)IDD_ENTITY, g_qeglobals.d_hwndMain, (DLGPROC)NULL); if (!hwndEntityPalette) Error ("CreateDialog failed"); GetEntityControls (hwndEntityPalette); DestroyWindow (hwndEntityPalette); OldFieldWindowProc = (WNDPROC)GetWindowLong (hwndEnt[EntKeyField], GWL_WNDPROC); SetWindowLong (hwndEnt[EntKeyField], GWL_WNDPROC, (long)FieldWndProc); SetWindowLong (hwndEnt[EntValueField], GWL_WNDPROC, (long)FieldWndProc); OldEntityListWindowProc = (WNDPROC)GetWindowLong (hwndEnt[EntList], GWL_WNDPROC); SetWindowLong (hwndEnt[EntList], GWL_WNDPROC, (long)EntityListWndProc); FillClassList (); LoadWindowPlacement(g_qeglobals.d_hwndEntity, "EntityWindowPlace"); ShowWindow (g_qeglobals.d_hwndEntity, SW_HIDE); SetInspectorMode (W_CONSOLE); return TRUE; } /* ============== SetInspectorMode ============== */ void SetInspectorMode(int iType) { RECT rc; HMENU hMenu = GetMenu( g_qeglobals.d_hwndMain ); if ((g_pParentWnd->CurrentStyle() == QR_SPLIT || g_pParentWnd->CurrentStyle() == QR_SPLITZ) && (iType == W_TEXTURE || iType == W_CONSOLE)) return; // Is the caller asking us to cycle to the next window? if (iType == -1) { if (inspector_mode == W_ENTITY) iType = W_TEXTURE; else if (inspector_mode == W_TEXTURE) iType = W_CONSOLE; else if (inspector_mode == W_CONSOLE) iType = W_GROUP; else iType = W_ENTITY; } inspector_mode = iType; switch(iType) { case W_ENTITY: SetWindowText(g_qeglobals.d_hwndEntity, "Entity"); EnableMenuItem( hMenu, ID_MISC_SELECTENTITYCOLOR, MF_ENABLED | MF_BYCOMMAND ); // entity is always first in the inspector g_wndTabs.SetCurSel(0); break; case W_TEXTURE: SetWindowText(g_qeglobals.d_hwndEntity, "Textures"); g_pParentWnd->GetTexWnd()->FocusEdit(); EnableMenuItem( hMenu, ID_MISC_SELECTENTITYCOLOR, MF_GRAYED | MF_DISABLED | MF_BYCOMMAND ); if (g_pParentWnd->CurrentStyle() > 0 && g_pParentWnd->CurrentStyle() < 3) g_wndTabs.SetCurSel(1); break; case W_CONSOLE: SetWindowText(g_qeglobals.d_hwndEntity, "Console"); EnableMenuItem( hMenu, ID_MISC_SELECTENTITYCOLOR, MF_GRAYED | MF_DISABLED | MF_BYCOMMAND ); if (g_pParentWnd->CurrentStyle() > 0 && g_pParentWnd->CurrentStyle() < 3) g_wndTabs.SetCurSel(2); break; case W_GROUP: SetWindowText(g_qeglobals.d_hwndEntity, "Groups"); EnableMenuItem( hMenu, ID_MISC_SELECTENTITYCOLOR, MF_GRAYED | MF_DISABLED | MF_BYCOMMAND ); if (g_pParentWnd->CurrentStyle() > 0 && g_pParentWnd->CurrentStyle() < 3) g_wndTabs.SetCurSel(3); else g_wndTabs.SetCurSel(1); break; default: break; } GetWindowRect (g_qeglobals.d_hwndEntity, &rc); SizeEntityDlg( rc.right - rc.left - 8, rc.bottom - rc.top - 20); // InvalidateRect(entwindow, NULL, true); // ShowWindow (entwindow, SW_SHOW); // UpdateWindow (entwindow); HWND hFlag = (g_pParentWnd->CurrentStyle() == QR_QE4) ? HWND_TOP : HWND_TOPMOST; SetWindowPos( g_qeglobals.d_hwndEntity, hFlag, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOSIZE | SWP_NOMOVE ); RedrawWindow (g_qeglobals.d_hwndEntity, NULL, NULL, RDW_ERASE | RDW_INVALIDATE| RDW_ERASENOW | RDW_UPDATENOW | RDW_ALLCHILDREN); } // SetKeyValuePairs // // Reset the key/value (aka property) listbox and fill it with the // k/v pairs from the entity being edited. // void SetKeyValuePairs (bool bClearMD3) { epair_t *pep; RECT rc; char sz[4096]; if (edit_entity == NULL) return; // set key/value pair list GetWindowRect(hwndEnt[EntProps], &rc); SendMessage(hwndEnt[EntProps], LB_SETCOLUMNWIDTH, (rc.right - rc.left)/2, 0); SendMessage(hwndEnt[EntProps], LB_RESETCONTENT, 0, 0); // Walk through list and add pairs for (pep = edit_entity->epairs ; pep ; pep = pep->next) { // if the key is less than 8 chars, add a tab for alignment if (strlen(pep->key) > 8) sprintf (sz, "%s\t%s", pep->key, pep->value); else sprintf (sz, "%s\t\t%s", pep->key, pep->value); SendMessage(hwndEnt[EntProps], LB_ADDSTRING, 0, (LPARAM)sz); } if (edit_entity->eclass->nShowFlags & ECLASS_MISCMODEL) { // if this is a misc_model // cache the md3 for display later if (bClearMD3) { edit_entity->md3Class = NULL; } //char *pModel = ValueForKey(edit_entity, "model"); /* if (pModel != NULL) { GetCachedModel(pModel, vMin, vMax); } */ } Sys_UpdateWindows(W_CAMERA | W_XY); } // SetSpawnFlags // // Update the checkboxes to reflect the flag state of the entity // void SetSpawnFlags(void) { int f; int i; int v; f = atoi(ValueForKey (edit_entity, "spawnflags")); for (i=0 ; i<12 ; i++) { v = !!(f&(1<next) SetKeyValue(b->owner, "spawnflags", sz); } else SetKeyValue (edit_entity, "spawnflags", sz); SetKeyValuePairs (); } // UpdateSel // // Update the listbox, checkboxes and k/v pairs to reflect the new selection // BOOL UpdateSel(int iIndex, eclass_t *pec) { int i; brush_t *b; if (selected_brushes.next == &selected_brushes) { edit_entity = world_entity; multiple_entities = false; } else { edit_entity = selected_brushes.next->owner; for (b=selected_brushes.next->next ; b != &selected_brushes ; b=b->next) { if (b->owner != edit_entity) { multiple_entities = true; break; } } } if (iIndex != LB_ERR) SendMessage(hwndEnt[EntList], LB_SETCURSEL, iIndex, 0); if (pec == NULL) return TRUE; // Set up the description SendMessage(hwndEnt[EntComment], WM_SETTEXT, 0, (LPARAM)TranslateString(pec->comments)); for (i=0 ; i<8 ; i++) { HWND hwnd = hwndEnt[EntCheck1+i]; if (pec->flagnames[i] && pec->flagnames[i][0] != 0) { EnableWindow(hwnd, TRUE); SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)pec->flagnames[i]); } else { // disable check box SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)" "); EnableWindow(hwnd, FALSE); } } SetSpawnFlags(); SetKeyValuePairs(); return TRUE; } BOOL UpdateEntitySel(eclass_t *pec) { int iIndex; iIndex = (int)SendMessage(hwndEnt[EntList], LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)pec->name); return UpdateSel(iIndex, pec); } // CreateEntity // // Creates a new entity based on the currently selected brush and entity type. // void CreateEntity(void) { eclass_t *pecNew; entity_t *petNew; int i; HWND hwnd; char sz[1024]; // check to make sure we have a brush if (selected_brushes.next == &selected_brushes) { MessageBox(g_qeglobals.d_hwndMain, "You must have a selected brush to create an entity" , "info", 0); return; } // find out what type of entity we are trying to create hwnd = hwndEnt[EntList]; i = SendMessage(hwndEnt[EntList], LB_GETCURSEL, 0, 0); if (i < 0) { MessageBox(g_qeglobals.d_hwndMain, "You must have a selected class to create an entity" , "info", 0); return; } SendMessage(hwnd, LB_GETTEXT, i, (LPARAM)sz); if (!stricmp(sz, "worldspawn")) { MessageBox(g_qeglobals.d_hwndMain, "Can't create an entity with worldspawn.", "info", 0); return; } pecNew = Eclass_ForName(sz, false); // create it petNew = Entity_Create(pecNew); if (petNew == NULL) { MessageBox(g_qeglobals.d_hwndMain, "Failed to create entity.", "info", 0); return; } if (selected_brushes.next == &selected_brushes) edit_entity = world_entity; else edit_entity = selected_brushes.next->owner; SetKeyValuePairs(); Select_Deselect (); Select_Brush (edit_entity->brushes.onext); Sys_UpdateWindows(W_ALL); } /* =============== AddProp =============== */ void AddProp() { char key[4096]; char value[4096]; if (edit_entity == NULL) return; // Get current selection text SendMessage(hwndEnt[EntKeyField], WM_GETTEXT, sizeof(key)-1, (LPARAM)key); SendMessage(hwndEnt[EntValueField], WM_GETTEXT, sizeof(value)-1, (LPARAM)value); if (multiple_entities) { brush_t *b; for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) SetKeyValue(b->owner, key, value); } else SetKeyValue(edit_entity, key, value); // refresh the prop listbox SetKeyValuePairs(); // if it's a plugin entity, perhaps we need to update some drawing parameters // NOTE: perhaps moving this code to a seperate func would help if we need it in other places // TODO: we need to call some update func in the IPluginEntity in case model name changes etc. // ( for the moment only bounding brush is updated ), see UpdateModelBrush in Ritual's Q3Radiant if (edit_entity->eclass->nShowFlags & ECLASS_PLUGINENTITY) { vec3_t mins, maxs; edit_entity->pPlugEnt->GetBounds( mins, maxs ); // replace old bounding brush by newly computed one // NOTE: this part is similar to Entity_BuildModelBrush in Ritual's Q3Radiant, it can be // usefull moved into a seperate func brush_t *b,*oldbrush; if (edit_entity->brushes.onext != &edit_entity->brushes) oldbrush = edit_entity->brushes.onext; b = Brush_Create (mins, maxs, &edit_entity->eclass->texdef); Entity_LinkBrush (edit_entity, b); Brush_Build( b, true ); Select_Deselect(); Brush_AddToList (edit_entity->brushes.onext, &selected_brushes); if (oldbrush) Brush_Free( oldbrush ); } } /* =============== DelProp =============== */ void DelProp(void) { char sz[4096]; if (edit_entity == NULL) return; // Get current selection text SendMessage(hwndEnt[EntKeyField], WM_GETTEXT, sizeof(sz)-1, (LPARAM)sz); if (multiple_entities) { brush_t *b; for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) DeleteKey(b->owner, sz); } else DeleteKey(edit_entity, sz); // refresh the prop listbox SetKeyValuePairs(); } BOOL GetSelectAllCriteria(CString &strKey, CString &strVal) { char sz[4096]; HWND hwnd = hwndEnt[EntProps]; int i = SendMessage(hwnd, LB_GETCURSEL, 0, 0); if (i >= 0 && inspector_mode == W_ENTITY) { SendMessage(hwndEnt[EntKeyField], WM_GETTEXT, sizeof(sz), (LPARAM)sz); strKey = sz; SendMessage(hwndEnt[EntValueField], WM_GETTEXT, sizeof(sz), (LPARAM)sz); strVal = sz; return TRUE; } return FALSE; } /* =============== EditProp =============== */ void EditProp(void) { int i; HWND hwnd; char sz[4096]; char *val; if (edit_entity == NULL) return; hwnd = hwndEnt[EntProps]; // Get current selection text i = SendMessage(hwnd, LB_GETCURSEL, 0, 0); if (i < 0) return; SendMessage(hwnd, LB_GETTEXT, i, (LPARAM)sz); // strip it down to the key name for(i=0;sz[i] != '\t';i++) ; sz[i] = '\0'; val = sz + i + 1; if (*val == '\t') val++; SendMessage(hwndEnt[EntKeyField], WM_SETTEXT, 0, (LPARAM)sz); SendMessage(hwndEnt[EntValueField], WM_SETTEXT, 0, (LPARAM)val); } HDWP defer; int col; void MOVE(HWND e, int x, int y, int w, int h, HWND hwndPlacement = HWND_TOP, int swp = SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOZORDER) { // defer=DeferWindowPos(defer,e,HWND_TOP,col+(x),y,w,h,SWP_SHOWWINDOW); // MoveWindow (e, col+x, y, w, h, FALSE); SetWindowPos (e, hwndPlacement, col+x, y, w, h, swp); } /* =============== SizeEnitityDlg Positions all controls so that the active inspector is displayed correctly and the inactive ones are off the side =============== */ void SizeEntityDlg(int iWidth, int iHeight) { int y, x, xCheck, yCheck; int i, iRow; int w, h; if (iWidth < 32 || iHeight < 32) return; SendMessage( g_qeglobals.d_hwndEntity, WM_SETREDRAW, 0, 0); iHeight -= 24; //========================================== // // console // if (inspector_mode == W_CONSOLE) { col = 0; } else { col = iWidth; } if (g_pParentWnd->CurrentStyle() > 0 && g_pParentWnd->CurrentStyle() < 3) MOVE(g_qeglobals.d_hwndEdit, DlgXBorder, DlgYBorder, iWidth - (2 * DlgXBorder), iHeight - (2 * DlgYBorder) ); //========================================== // // texture controls // if (inspector_mode == W_TEXTURE) { col = 0; } else { col = iWidth; } if (g_pParentWnd->CurrentStyle() > 0 && g_pParentWnd->CurrentStyle() < 3) MOVE(g_qeglobals.d_hwndTexture, DlgXBorder, DlgYBorder, iWidth - (2 * DlgXBorder), iHeight - (2 * DlgYBorder) ); if (inspector_mode == W_GROUP) { col = 0; } else { col = iWidth; } MOVE(g_qeglobals.d_hwndGroup, DlgXBorder, DlgYBorder, iWidth - (2 * DlgXBorder), iHeight - (2 * DlgYBorder) ); //========================================== // // entity controls // if (inspector_mode == W_ENTITY) { col = 0; } else { col = iWidth; } // top half includes the entity list (2/3) and the // comments (1/3) - 2 gaps, above and below. y = iHeight/2; y -= 2 * DlgYBorder; y = y / 3; w = iWidth - (2 * DlgXBorder); MOVE(hwndEnt[EntList], DlgXBorder, DlgYBorder, w, 2 * y); MOVE(hwndEnt[EntComment], DlgXBorder, 2 * DlgYBorder + 2 * y, w, y - (2 * DlgYBorder)); // bottom half includes flags (fixed), k/v pairs, // and buttons (fixed). // xCheck = width of a single check box // yCheck = distance from top of one check to the next xCheck = (iWidth - (2 * DlgXBorder)) / 3; yCheck = 18; x = DlgXBorder; for (iRow = 0; iRow <= 12; iRow += 4) { y = iHeight/2; for (i = 0; i < 4; i++) { MOVE(hwndEnt[EntCheck1 + i + iRow], x, y, xCheck, yCheck); y += yCheck; } x += xCheck; } // // properties scroll box // y = iHeight/2 + 4 * yCheck; w = iWidth - (2 * DlgXBorder); h = (iHeight - (yCheck * 5 + 2 * DlgYBorder) ) - y; MOVE(hwndEnt[EntProps], DlgXBorder, y, w, h); y += h + DlgYBorder; // // key / value fields // w = iWidth-(DlgXBorder+45); MOVE(hwndEnt[EntKeyLabel], DlgXBorder, y, 40, yCheck); MOVE(hwndEnt[EntKeyField], DlgXBorder+40, y, w, yCheck); y += yCheck; MOVE(hwndEnt[EntValueLabel], DlgXBorder, y, 40, yCheck); MOVE(hwndEnt[EntValueField], DlgXBorder+40, y, w, yCheck); y += yCheck; // // angle check boxes // y += 2; i = y; x = DlgXBorder; xCheck = yCheck*2; MOVE(hwndEnt[EntDir135], x, y, xCheck, yCheck); y += yCheck; MOVE(hwndEnt[EntDir180], x, y, xCheck, yCheck); y += yCheck; MOVE(hwndEnt[EntDir225], x, y, xCheck, yCheck); y = i; x += xCheck; MOVE(hwndEnt[EntDir90], x, y, xCheck, yCheck); y += yCheck; y += yCheck; MOVE(hwndEnt[EntDir270], x, y, xCheck, yCheck); y = i; x += xCheck; MOVE(hwndEnt[EntDir45], x, y, xCheck, yCheck); y += yCheck; MOVE(hwndEnt[EntDir0], x, y, xCheck, yCheck); y += yCheck; MOVE(hwndEnt[EntDir315], x, y, xCheck, yCheck); y = i + yCheck/2; x += xCheck + xCheck/2; MOVE(hwndEnt[EntDirUp], x, y, xCheck, yCheck); y += yCheck; MOVE(hwndEnt[EntDirDown], x, y, xCheck, yCheck); y = i; x += 1.5 * xCheck; MOVE(hwndEnt[EntDelProp], x, y, xCheck*2, yCheck); y += yCheck + 4; MOVE(hwndEnt[EntAssignSounds], x, y, xCheck*2, yCheck); y += yCheck; MOVE(hwndEnt[EntAssignModels], x, y, xCheck*2, yCheck); // tab selector is always visible col = 0; iHeight += 24; MOVE(hwndEnt[EntTab], 0,0,iWidth,iHeight, HWND_BOTTOM, SWP_NOACTIVATE | SWP_NOCOPYBITS); SendMessage( g_qeglobals.d_hwndEntity, WM_SETREDRAW, 1, 0); // InvalidateRect(entwindow, NULL, TRUE); } void AssignSound() { CString strBasePath = ValueForKey(g_qeglobals.d_project_entity, "basepath"); AddSlash(strBasePath); CString strPath = strBasePath; strPath += "sound\\"; CWaveOpen dlgFile(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "Sound files (*.wav)|*.wav||", g_pParentWnd); dlgFile.m_ofn.lpstrInitialDir = strPath; if (dlgFile.DoModal() == IDOK) { SendMessage(hwndEnt[EntKeyField], WM_SETTEXT, 0, (LPARAM)"noise"); CString str = dlgFile.GetPathName().GetBuffer(0); str.MakeLower(); strBasePath.MakeLower(); QE_ConvertDOSToUnixName(str.GetBuffer(0), str.GetBuffer(0)); QE_ConvertDOSToUnixName(strBasePath.GetBuffer(0), strBasePath.GetBuffer(0)); int n = str.Find(strBasePath); if (n == 0) { str = str.Right(str.GetLength() - strBasePath.GetLength()); } SendMessage(hwndEnt[EntValueField], WM_SETTEXT, 0, (LPARAM)str.GetBuffer(0)); AddProp(); g_pParentWnd->GetXYWnd()->SetFocus(); } } void AssignModel() { CString strBasePath = ValueForKey(g_qeglobals.d_project_entity, "basepath"); AddSlash(strBasePath); CString strPath = strBasePath; strPath += "models\\mapobjects\\"; CFileDialog dlgFile(TRUE, NULL, NULL, OFN_OVERWRITEPROMPT, "Model files (*.md3)|*.md3||", g_pParentWnd); dlgFile.m_ofn.lpstrInitialDir = strPath; if (dlgFile.DoModal() == IDOK) { SendMessage(hwndEnt[EntKeyField], WM_SETTEXT, 0, (LPARAM)"model"); CString str = dlgFile.GetPathName().GetBuffer(0); str.MakeLower(); strBasePath.MakeLower(); QE_ConvertDOSToUnixName(str.GetBuffer(0), str.GetBuffer(0)); QE_ConvertDOSToUnixName(strBasePath.GetBuffer(0), strBasePath.GetBuffer(0)); int n = str.Find(strBasePath); if (n == 0) { str = str.Right(str.GetLength() - strBasePath.GetLength()); } SendMessage(hwndEnt[EntValueField], WM_SETTEXT, 0, (LPARAM)str.GetBuffer(0)); AddProp(); edit_entity->md3Class = NULL; edit_entity->brushes.onext->bModelFailed = false; g_pParentWnd->GetXYWnd()->SetFocus(); } } /* ========================= EntityWndProc ========================= */ BOOL CALLBACK EntityWndProc( HWND hwndDlg, // handle to dialog box UINT uMsg, // message WPARAM wParam, // first message parameter LPARAM lParam) // second message parameter { LPNMHDR lpnmh = NULL; RECT rc; GetClientRect(hwndDlg, &rc); switch (uMsg) { case WM_CHAR : { char c = toupper(LOWORD(wParam)); // escape: hide the window if (c == 27) ShowWindow(hwndDlg, SW_HIDE); if (c == 'N') g_pParentWnd->PostMessage(WM_COMMAND, ID_VIEW_ENTITY, 0); else if (c == 'O') g_pParentWnd->PostMessage(WM_COMMAND, ID_VIEW_CONSOLE, 0); else if (c == 'T') g_pParentWnd->PostMessage(WM_COMMAND, ID_VIEW_TEXTURE, 0); else if (c == 'G') g_pParentWnd->PostMessage(WM_COMMAND, ID_VIEW_GROUPS, 0); else DefWindowProc (hwndDlg, uMsg, wParam, lParam); break; } case WM_NOTIFY: lpnmh = reinterpret_cast(lParam); if (lpnmh->hwndFrom == g_wndTabs.GetSafeHwnd()) { if ( lpnmh->code == TCN_SELCHANGE) { int n = g_wndTabs.GetCurSel(); if (g_pParentWnd->CurrentStyle() == 2 || g_pParentWnd->CurrentStyle() == 1) { if (n == 0) { SetInspectorMode(W_ENTITY); } else if (n == 1) { SetInspectorMode(W_TEXTURE); } else if (n == 2) { SetInspectorMode(W_CONSOLE); } else { SetInspectorMode(W_GROUP); } } else { if (n == 0) { SetInspectorMode(W_ENTITY); } else if (n == 1) { SetInspectorMode(W_GROUP); } } } } break; case WM_SIZE: DefWindowProc (hwndDlg, uMsg, wParam, lParam); break; case WM_DESTROY: SaveWindowPlacement(g_qeglobals.d_hwndEntity, "EntityWindowPlace"); DefWindowProc(hwndDlg, uMsg, wParam, lParam); break; case WM_GETMINMAXINFO: { LPMINMAXINFO lpmmi; lpmmi = (LPMINMAXINFO) lParam; lpmmi->ptMinTrackSize.x = 320; lpmmi->ptMinTrackSize.y = 500; } return 0; case WM_WINDOWPOSCHANGING: { LPWINDOWPOS lpwp; lpwp = (LPWINDOWPOS) lParam; DefWindowProc (hwndDlg, uMsg, wParam, lParam); lpwp->flags |= SWP_NOCOPYBITS; SizeEntityDlg(lpwp->cx-8, lpwp->cy-32); return 0; } return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_BTN_ASSIGNSOUND: AssignSound(); break; case IDC_BTN_ASSIGNMODEL: AssignModel(); break; case IDC_E_DELPROP: DelProp(); SetFocus (g_qeglobals.d_hwndCamera); break; case IDC_E_0: SetKeyValue (edit_entity, "angle", "360"); SetFocus (g_qeglobals.d_hwndCamera); SetKeyValuePairs (); break; case IDC_E_45: SetKeyValue (edit_entity, "angle", "45"); SetFocus (g_qeglobals.d_hwndCamera); SetKeyValuePairs (); break; case IDC_E_90: SetKeyValue (edit_entity, "angle", "90"); SetFocus (g_qeglobals.d_hwndCamera); SetKeyValuePairs (); break; case IDC_E_135: SetKeyValue (edit_entity, "angle", "135"); SetFocus (g_qeglobals.d_hwndCamera); SetKeyValuePairs (); break; case IDC_E_180: SetKeyValue (edit_entity, "angle", "180"); SetFocus (g_qeglobals.d_hwndCamera); SetKeyValuePairs (); break; case IDC_E_225: SetKeyValue (edit_entity, "angle", "225"); SetFocus (g_qeglobals.d_hwndCamera); SetKeyValuePairs (); break; case IDC_E_270: SetKeyValue (edit_entity, "angle", "270"); SetFocus (g_qeglobals.d_hwndCamera); SetKeyValuePairs (); break; case IDC_E_315: SetKeyValue (edit_entity, "angle", "315"); SetFocus (g_qeglobals.d_hwndCamera); SetKeyValuePairs (); break; case IDC_E_UP: SetKeyValue (edit_entity, "angle", "-1"); SetFocus (g_qeglobals.d_hwndCamera); SetKeyValuePairs (); break; case IDC_E_DOWN: SetKeyValue (edit_entity, "angle", "-2"); SetFocus (g_qeglobals.d_hwndCamera); SetKeyValuePairs (); break; case IDC_BTN_HIDE: ::PostMessage(g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_CAMERATOGGLE, 0); break; case IDC_CHECK1: case IDC_CHECK2: case IDC_CHECK3: case IDC_CHECK4: case IDC_CHECK5: case IDC_CHECK6: case IDC_CHECK7: case IDC_CHECK8: case IDC_CHECK9: case IDC_CHECK10: case IDC_CHECK11: case IDC_CHECK12: GetSpawnFlags(); SetFocus (g_qeglobals.d_hwndCamera); break; case IDC_E_PROPS: switch (HIWORD(wParam)) { case LBN_SELCHANGE: EditProp(); return TRUE; } break; case IDC_E_LIST: switch (HIWORD(wParam)) { case LBN_SELCHANGE: { int iIndex; eclass_t *pec; iIndex = SendMessage(hwndEnt[EntList], LB_GETCURSEL, 0, 0); pec = (eclass_t *)SendMessage(hwndEnt[EntList], LB_GETITEMDATA, iIndex, 0); UpdateSel(iIndex, pec); return TRUE; break; } case LBN_DBLCLK: CreateEntity (); SetFocus (g_qeglobals.d_hwndCamera); break; } break; default: return DefWindowProc( hwndDlg, uMsg, wParam, lParam ); } return 0; } return DefWindowProc (hwndDlg, uMsg, wParam, lParam); }