2 ===========================================================================
3 Copyright (C) 1997-2006 Id Software, Inc.
5 This file is part of Quake 2 Tools source code.
7 Quake 2 Tools source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
12 Quake 2 Tools source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Quake 2 Tools source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 ===========================================================================
26 int rgIds[EntLast] = {
62 HWND hwndEnt[EntLast];
64 int inspector_mode; // W_TEXTURE, W_ENTITY, or W_CONSOLE
66 qboolean multiple_entities;
68 entity_t *edit_entity;
70 HWND CreateTextureWindow (void);
72 BOOL CALLBACK EntityWndProc(
73 HWND hwndDlg, // handle to dialog box
75 WPARAM wParam, // first message parameter
76 LPARAM lParam); // second message parameter
78 void SizeEntityDlg(int iWidth, int iHeight);
80 void GetTexMods(void);
83 LRESULT (CALLBACK* OldFieldWindowProc) (HWND, UINT, WPARAM, LPARAM);
84 LRESULT (CALLBACK* OldEntityListWindowProc) (HWND, UINT, WPARAM, LPARAM);
87 =========================
90 Just to handle tab and enter...
91 =========================
93 BOOL CALLBACK FieldWndProc(
102 if (LOWORD(wParam) == VK_TAB)
104 if (LOWORD(wParam) == VK_RETURN)
106 if (LOWORD(wParam) == VK_ESCAPE)
108 SetFocus (g_qeglobals.d_hwndCamera);
114 if (LOWORD(wParam) == VK_TAB)
116 if (hwnd == hwndEnt[EntKeyField])
118 SendMessage (hwndEnt[EntValueField], WM_SETTEXT, 0, (long)"");
119 SetFocus (hwndEnt[EntValueField]);
122 SetFocus (hwndEnt[EntKeyField]);
124 if (LOWORD(wParam) == VK_RETURN)
126 if (hwnd == hwndEnt[EntKeyField])
128 SendMessage (hwndEnt[EntValueField], WM_SETTEXT, 0, (long)"");
129 SetFocus (hwndEnt[EntValueField]);
134 SetFocus (g_qeglobals.d_hwndCamera);
138 // case WM_NCHITTEST:
143 return CallWindowProc (OldFieldWindowProc, hwnd, uMsg, wParam, lParam);
148 =========================
151 Just to handle enter...
152 =========================
154 BOOL CALLBACK EntityListWndProc(
163 if (LOWORD(wParam) == VK_RETURN)
165 SendMessage ( g_qeglobals.d_hwndEntity,
167 (LBN_DBLCLK<<16) + IDC_E_LIST,
173 return CallWindowProc (OldEntityListWindowProc, hwnd, uMsg, wParam, lParam);
181 Finds the controls from the dialog and
182 moves them to the window
185 void GetEntityControls(HWND ghwndEntity)
189 for (i = 0; i < EntLast; i++)
191 if (i == EntList || i == EntProps || i == EntComment)
193 if (i == EntKeyField || i == EntValueField)
195 hwndEnt[i] = GetDlgItem(ghwndEntity, rgIds[i]);
197 SetParent (hwndEnt[i], g_qeglobals.d_hwndEntity );
201 // SetParent apears to not modify some internal state
202 // on listboxes, so create it from scratch...
204 hwndEnt[EntList] = CreateWindow ("listbox", NULL,
205 LBS_STANDARD | LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT
206 | WS_VSCROLL | WS_CHILD | WS_VISIBLE,
208 g_qeglobals.d_hwndEntity,
210 g_qeglobals.d_hInstance,
212 if (!hwndEnt[EntList])
213 Error ("CreateWindow failed");
215 hwndEnt[EntProps] = CreateWindow ("listbox", NULL,
216 LBS_STANDARD | LBS_NOINTEGRALHEIGHT | LBS_USETABSTOPS
217 | WS_VSCROLL | WS_CHILD | WS_VISIBLE,
219 g_qeglobals.d_hwndEntity,
221 g_qeglobals.d_hInstance,
223 if (!hwndEnt[EntProps])
224 Error ("CreateWindow failed");
226 hwndEnt[EntComment] = CreateWindow ("edit", NULL,
227 ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER,
229 g_qeglobals.d_hwndEntity,
230 (void *)IDC_E_COMMENT,
231 g_qeglobals.d_hInstance,
233 if (!hwndEnt[EntComment])
234 Error ("CreateWindow failed");
236 hwndEnt[EntKeyField] = CreateWindow ("edit", NULL,
237 WS_CHILD | WS_VISIBLE | WS_BORDER,
239 g_qeglobals.d_hwndEntity,
240 (void *)IDC_E_KEY_FIELD,
241 g_qeglobals.d_hInstance,
243 if (!hwndEnt[EntKeyField])
244 Error ("CreateWindow failed");
246 hwndEnt[EntValueField] = CreateWindow ("edit", NULL,
247 WS_CHILD | WS_VISIBLE | WS_BORDER,
249 g_qeglobals.d_hwndEntity,
250 (void *)IDC_E_VALUE_FIELD,
251 g_qeglobals.d_hInstance,
253 if (!hwndEnt[EntValueField])
254 Error ("CreateWindow failed");
256 g_qeglobals.d_hwndEdit = CreateWindow ("edit", NULL,
257 ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER,
259 g_qeglobals.d_hwndEntity,
260 (void *)IDC_E_STATUS,
261 g_qeglobals.d_hInstance,
263 if (!g_qeglobals.d_hwndEdit)
264 Error ("CreateWindow failed");
266 g_qeglobals.d_hwndTexture = CreateTextureWindow ();
269 for (i=0 ; i<12 ; i++)
271 hwndEnt[EntCheck1 + i] = CreateWindow ("button", NULL,
272 BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE,
275 (void *)IDC_E_STATUS,
278 if (!hwndEnt[EntCheck1 + i])
279 Error ("CreateWindow failed");
287 ===============================================================
291 ===============================================================
295 void FillClassList (void)
300 SendMessage(hwndEnt[EntList], LB_RESETCONTENT, 0 , 0);
302 for (pec = eclass ; pec ; pec = pec->next)
304 iIndex = SendMessage(hwndEnt[EntList], LB_ADDSTRING, 0 , (LPARAM)pec->name);
305 SendMessage(hwndEnt[EntList], LB_SETITEMDATA, iIndex, (LPARAM)pec);
316 void WEnt_Create (HINSTANCE hInstance)
320 /* Register the camera class */
321 memset (&wc, 0, sizeof(wc));
324 wc.lpfnWndProc = (WNDPROC)EntityWndProc;
327 wc.hInstance = hInstance;
329 wc.hCursor = LoadCursor (NULL,IDC_ARROW);
330 wc.hbrBackground = GetStockObject (LTGRAY_BRUSH);
331 wc.lpszMenuName = NULL;
332 wc.lpszClassName = ENT_WINDOW_CLASS;
334 if (!RegisterClass (&wc) )
335 Error ("RegisterClass: failed");
337 g_qeglobals.d_hwndEntity = CreateWindow (ENT_WINDOW_CLASS ,
345 g_qeglobals.d_hwndMain, // parent
350 if (!g_qeglobals.d_hwndEntity )
351 Error ("Couldn't create Entity window");
359 BOOL CreateEntityWindow(HINSTANCE hInstance)
361 HWND hwndEntityPalette;
363 inspector_mode = W_ENTITY;
365 WEnt_Create (hInstance);
367 hwndEntityPalette = CreateDialog(hInstance, (char *)IDD_ENTITY, g_qeglobals.d_hwndMain, (DLGPROC)NULL);
368 if (!hwndEntityPalette)
369 Error ("CreateDialog failed");
371 GetEntityControls (hwndEntityPalette);
372 DestroyWindow (hwndEntityPalette);
374 OldFieldWindowProc = (void *)GetWindowLong (hwndEnt[EntKeyField], GWL_WNDPROC);
375 SetWindowLong (hwndEnt[EntKeyField], GWL_WNDPROC, (long)FieldWndProc);
376 SetWindowLong (hwndEnt[EntValueField], GWL_WNDPROC, (long)FieldWndProc);
378 OldEntityListWindowProc = (void *)GetWindowLong (hwndEnt[EntList], GWL_WNDPROC);
379 SetWindowLong (hwndEnt[EntList], GWL_WNDPROC, (long)EntityListWndProc);
383 LoadWindowState(g_qeglobals.d_hwndEntity, "EntityWindow");
385 ShowWindow (g_qeglobals.d_hwndEntity, SW_SHOW);
386 SetInspectorMode (W_CONSOLE);
396 void SetInspectorMode(int iType)
399 HMENU hMenu = GetMenu( g_qeglobals.d_hwndMain );
401 // Is the caller asking us to cycle to the next window?
405 if (inspector_mode == W_ENTITY)
407 else if (inspector_mode == W_TEXTURE)
413 inspector_mode = iType;
418 SetWindowText(g_qeglobals.d_hwndEntity, "Entity");
419 EnableMenuItem( hMenu, ID_MISC_SELECTENTITYCOLOR, MF_ENABLED | MF_BYCOMMAND );
423 // title is set by textures.c SetWindowText(g_qeglobals.d_hwndEntity, "Textures");
424 EnableMenuItem( hMenu, ID_MISC_SELECTENTITYCOLOR, MF_GRAYED | MF_DISABLED | MF_BYCOMMAND );
428 SetWindowText(g_qeglobals.d_hwndEntity, "Console");
429 EnableMenuItem( hMenu, ID_MISC_SELECTENTITYCOLOR, MF_GRAYED | MF_DISABLED | MF_BYCOMMAND );
436 GetWindowRect (g_qeglobals.d_hwndEntity, &rc);
437 SizeEntityDlg( rc.right - rc.left - 8, rc.bottom - rc.top - 32);
439 RedrawWindow (g_qeglobals.d_hwndEntity, NULL, NULL, RDW_ERASE | RDW_INVALIDATE
440 | RDW_ERASENOW | RDW_UPDATENOW | RDW_ALLCHILDREN);
442 // InvalidateRect(entwindow, NULL, true);
443 // ShowWindow (entwindow, SW_SHOW);
444 // UpdateWindow (entwindow);
446 SetWindowPos( g_qeglobals.d_hwndEntity,
449 rc.right - rc.left, rc.bottom - rc.top,
450 SWP_NOSIZE | SWP_NOMOVE );
459 // Reset the key/value (aka property) listbox and fill it with the
460 // k/v pairs from the entity being edited.
463 void SetKeyValuePairs (void)
469 if (edit_entity == NULL)
472 // set key/value pair list
474 GetWindowRect(hwndEnt[EntProps], &rc);
475 SendMessage(hwndEnt[EntProps], LB_SETCOLUMNWIDTH, (rc.right - rc.left)/2, 0);
476 SendMessage(hwndEnt[EntProps], LB_RESETCONTENT, 0, 0);
478 // Walk through list and add pairs
480 for (pep = edit_entity->epairs ; pep ; pep = pep->next)
482 // if the key is less than 8 chars, add a tab for alignment
483 if (strlen(pep->key) > 8)
484 sprintf (sz, "%s\t%s", pep->key, pep->value);
486 sprintf (sz, "%s\t\t%s", pep->key, pep->value);
487 SendMessage(hwndEnt[EntProps], LB_ADDSTRING, 0, (LPARAM)sz);
494 // Update the checkboxes to reflect the flag state of the entity
496 void SetSpawnFlags(void)
502 f = atoi(ValueForKey (edit_entity, "spawnflags"));
503 for (i=0 ; i<12 ; i++)
506 SendMessage(hwndEnt[EntCheck1+i], BM_SETCHECK, v, 0);
513 // Update the entity flags to reflect the state of the checkboxes
515 void GetSpawnFlags(void)
522 for (i=0 ; i<12 ; i++)
524 v = SendMessage(hwndEnt[EntCheck1+i], BM_GETCHECK, 0, 0);
528 sprintf (sz, "%i", f);
530 if (multiple_entities)
534 for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
535 SetKeyValue(b->owner, "spawnflags", sz);
538 SetKeyValue (edit_entity, "spawnflags", sz);
544 // Update the listbox, checkboxes and k/v pairs to reflect the new selection
547 BOOL UpdateSel(int iIndex, eclass_t *pec)
552 if (selected_brushes.next == &selected_brushes)
554 edit_entity = world_entity;
555 multiple_entities = false;
559 edit_entity = selected_brushes.next->owner;
560 for (b=selected_brushes.next->next ; b != &selected_brushes ; b=b->next)
562 if (b->owner != edit_entity)
564 multiple_entities = true;
570 if (iIndex != LB_ERR)
571 SendMessage(hwndEnt[EntList], LB_SETCURSEL, iIndex, 0);
576 // Set up the description
578 SendMessage(hwndEnt[EntComment], WM_SETTEXT, 0,
579 (LPARAM)TranslateString(pec->comments));
581 for (i=0 ; i<8 ; i++)
583 HWND hwnd = hwndEnt[EntCheck1+i];
584 if (pec->flagnames[i] && pec->flagnames[i][0] != 0)
586 EnableWindow(hwnd, TRUE);
587 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)pec->flagnames[i]);
591 SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)" ");
592 EnableWindow(hwnd, FALSE);
601 BOOL UpdateEntitySel(eclass_t *pec)
605 iIndex = (int)SendMessage(hwndEnt[EntList], LB_FINDSTRINGEXACT,
606 (WPARAM)-1, (LPARAM)pec->name);
608 return UpdateSel(iIndex, pec);
613 // Creates a new entity based on the currently selected brush and entity type.
616 void CreateEntity(void)
624 // check to make sure we have a brush
626 if (selected_brushes.next == &selected_brushes)
628 MessageBox(g_qeglobals.d_hwndMain, "You must have a selected brush to create an entity"
634 // find out what type of entity we are trying to create
636 hwnd = hwndEnt[EntList];
638 i = SendMessage(hwndEnt[EntList], LB_GETCURSEL, 0, 0);
642 MessageBox(g_qeglobals.d_hwndMain, "You must have a selected class to create an entity"
647 SendMessage(hwnd, LB_GETTEXT, i, (LPARAM)sz);
649 if (!stricmp(sz, "worldspawn"))
651 MessageBox(g_qeglobals.d_hwndMain, "Can't create an entity with worldspawn.", "info", 0);
655 pecNew = Eclass_ForName(sz, false);
659 petNew = Entity_Create(pecNew);
663 MessageBox(g_qeglobals.d_hwndMain, "Failed to create entity.", "info", 0);
667 if (selected_brushes.next == &selected_brushes)
668 edit_entity = world_entity;
670 edit_entity = selected_brushes.next->owner;
674 Select_Brush (edit_entity->brushes.onext);
690 if (edit_entity == NULL)
693 // Get current selection text
695 SendMessage(hwndEnt[EntKeyField], WM_GETTEXT, sizeof(key)-1, (LPARAM)key);
696 SendMessage(hwndEnt[EntValueField], WM_GETTEXT, sizeof(value)-1, (LPARAM)value);
698 if (multiple_entities)
702 for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
703 SetKeyValue(b->owner, key, value);
706 SetKeyValue(edit_entity, key, value);
708 // refresh the prop listbox
723 if (edit_entity == NULL)
726 // Get current selection text
728 SendMessage(hwndEnt[EntKeyField], WM_GETTEXT, sizeof(sz)-1, (LPARAM)sz);
730 if (multiple_entities)
734 for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
735 DeleteKey(b->owner, sz);
738 DeleteKey(edit_entity, sz);
740 // refresh the prop listbox
758 if (edit_entity == NULL)
761 hwnd = hwndEnt[EntProps];
763 // Get current selection text
765 i = SendMessage(hwnd, LB_GETCURSEL, 0, 0);
770 SendMessage(hwnd, LB_GETTEXT, i, (LPARAM)sz);
772 // strip it down to the key name
774 for(i=0;sz[i] != '\t';i++)
783 SendMessage(hwndEnt[EntKeyField], WM_SETTEXT, 0, (LPARAM)sz);
784 SendMessage(hwndEnt[EntValueField], WM_SETTEXT, 0, (LPARAM)val);
790 void MOVE(HWND e, int x, int y, int w, int h)
792 // defer=DeferWindowPos(defer,e,HWND_TOP,col+(x),y,w,h,SWP_SHOWWINDOW);
793 // MoveWindow (e, col+x, y, w, h, FALSE);
794 SetWindowPos (e, HWND_TOP, col+x, y, w, h,
795 SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOZORDER);
803 Positions all controls so that the active inspector
804 is displayed correctly and the inactive ones are
808 void SizeEntityDlg(int iWidth, int iHeight)
810 int y, x, xCheck, yCheck;
814 if (iWidth < 32 || iHeight < 32)
817 SendMessage( g_qeglobals.d_hwndEntity, WM_SETREDRAW, 0, 0);
819 //==========================================
825 if (inspector_mode == W_CONSOLE)
830 MOVE(g_qeglobals.d_hwndEdit, DlgXBorder, DlgYBorder, iWidth - (2 * DlgXBorder), iHeight - (2 * DlgYBorder) );
832 //==========================================
837 if (inspector_mode == W_TEXTURE)
842 MOVE(g_qeglobals.d_hwndTexture, DlgXBorder, DlgYBorder, iWidth - (2 * DlgXBorder), iHeight - (2 * DlgYBorder) );
844 //==========================================
849 if (inspector_mode == W_ENTITY)
855 // top half includes the entity list (2/3) and the
856 // comments (1/3) - 2 gaps, above and below.
861 w = iWidth - (2 * DlgXBorder);
862 MOVE(hwndEnt[EntList], DlgXBorder, DlgYBorder, w, 2 * y);
864 MOVE(hwndEnt[EntComment],
865 DlgXBorder, 2 * DlgYBorder + 2 * y,
866 w, y - (2 * DlgYBorder));
868 // bottom half includes flags (fixed), k/v pairs,
869 // and buttons (fixed).
871 // xCheck = width of a single check box
872 // yCheck = distance from top of one check to the next
874 xCheck = (iWidth - (2 * DlgXBorder)) / 3;
879 for (iRow = 0; iRow <= 12; iRow += 4)
883 for (i = 0; i < 4; i++)
885 MOVE(hwndEnt[EntCheck1 + i + iRow],
886 x, y, xCheck, yCheck);
894 // properties scroll box
896 y = iHeight/2 + 4 * yCheck;
898 w = iWidth - (2 * DlgXBorder);
899 h = (iHeight - (yCheck * 5 + 2 * DlgYBorder) ) - y;
901 MOVE(hwndEnt[EntProps], DlgXBorder, y, w, h);
906 // key / value fields
908 w = iWidth-(DlgXBorder+45);
909 MOVE(hwndEnt[EntKeyLabel], DlgXBorder, y, 40, yCheck);
910 MOVE(hwndEnt[EntKeyField], DlgXBorder+40, y, w, yCheck);
913 MOVE(hwndEnt[EntValueLabel], DlgXBorder, y, 40, yCheck);
914 MOVE(hwndEnt[EntValueField], DlgXBorder+40, y, w, yCheck);
925 MOVE(hwndEnt[EntDir135], x, y, xCheck, yCheck);
928 MOVE(hwndEnt[EntDir180], x, y, xCheck, yCheck);
931 MOVE(hwndEnt[EntDir225], x, y, xCheck, yCheck);
937 MOVE(hwndEnt[EntDir90], x, y, xCheck, yCheck);
941 MOVE(hwndEnt[EntDir270], x, y, xCheck, yCheck);
947 MOVE(hwndEnt[EntDir45], x, y, xCheck, yCheck);
950 MOVE(hwndEnt[EntDir0], x, y, xCheck, yCheck);
953 MOVE(hwndEnt[EntDir315], x, y, xCheck, yCheck);
956 x += xCheck + xCheck/2;
959 MOVE(hwndEnt[EntDirUp], x, y, xCheck, yCheck);
962 MOVE(hwndEnt[EntDirDown], x, y, xCheck, yCheck);
967 MOVE(hwndEnt[EntDelProp], x, y, xCheck*2, yCheck);
970 SendMessage( g_qeglobals.d_hwndEntity, WM_SETREDRAW, 1, 0);
971 // InvalidateRect(entwindow, NULL, TRUE);
976 =========================
978 =========================
980 BOOL CALLBACK EntityWndProc(
981 HWND hwndDlg, // handle to dialog box
982 UINT uMsg, // message
983 WPARAM wParam, // first message parameter
984 LPARAM lParam) // second message parameter
988 GetClientRect(hwndDlg, &rc);
992 case WM_GETMINMAXINFO:
996 lpmmi = (LPMINMAXINFO) lParam;
997 lpmmi->ptMinTrackSize.x = 320;
998 lpmmi->ptMinTrackSize.y = 500;
1002 case WM_WINDOWPOSCHANGING:
1005 lpwp = (LPWINDOWPOS) lParam;
1007 DefWindowProc (hwndDlg, uMsg, wParam, lParam);
1009 lpwp->flags |= SWP_NOCOPYBITS;
1010 SizeEntityDlg(lpwp->cx-8, lpwp->cy-32);
1018 switch (LOWORD(wParam)) {
1021 SetFocus (g_qeglobals.d_hwndCamera);
1025 SetKeyValue (edit_entity, "angle", "0");
1026 SetFocus (g_qeglobals.d_hwndCamera);
1027 SetKeyValuePairs ();
1030 SetKeyValue (edit_entity, "angle", "45");
1031 SetFocus (g_qeglobals.d_hwndCamera);
1032 SetKeyValuePairs ();
1035 SetKeyValue (edit_entity, "angle", "90");
1036 SetFocus (g_qeglobals.d_hwndCamera);
1037 SetKeyValuePairs ();
1040 SetKeyValue (edit_entity, "angle", "135");
1041 SetFocus (g_qeglobals.d_hwndCamera);
1042 SetKeyValuePairs ();
1045 SetKeyValue (edit_entity, "angle", "180");
1046 SetFocus (g_qeglobals.d_hwndCamera);
1047 SetKeyValuePairs ();
1050 SetKeyValue (edit_entity, "angle", "225");
1051 SetFocus (g_qeglobals.d_hwndCamera);
1052 SetKeyValuePairs ();
1055 SetKeyValue (edit_entity, "angle", "270");
1056 SetFocus (g_qeglobals.d_hwndCamera);
1057 SetKeyValuePairs ();
1060 SetKeyValue (edit_entity, "angle", "315");
1061 SetFocus (g_qeglobals.d_hwndCamera);
1062 SetKeyValuePairs ();
1065 SetKeyValue (edit_entity, "angle", "-1");
1066 SetFocus (g_qeglobals.d_hwndCamera);
1067 SetKeyValuePairs ();
1070 SetKeyValue (edit_entity, "angle", "-2");
1071 SetFocus (g_qeglobals.d_hwndCamera);
1072 SetKeyValuePairs ();
1088 SetFocus (g_qeglobals.d_hwndCamera);
1093 switch (HIWORD(wParam))
1104 switch (HIWORD(wParam)) {
1111 iIndex = SendMessage(hwndEnt[EntList], LB_GETCURSEL, 0, 0);
1112 pec = (eclass_t *)SendMessage(hwndEnt[EntList], LB_GETITEMDATA,
1115 UpdateSel(iIndex, pec);
1123 SetFocus (g_qeglobals.d_hwndCamera);
1130 return DefWindowProc( hwndDlg, uMsg, wParam, lParam );
1136 return DefWindowProc (hwndDlg, uMsg, wParam, lParam);