1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 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.
23
24 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.
25
26 ===========================================================================
27 */
28
29 #include "tools/edit_gui_common.h"
30
31
32 #include "../../sys/win32/rc/guied_resource.h"
33
34 #include "GEApp.h"
35
36 #define GENAV_ITEMHEIGHT 22
37
rvGENavigator()38 rvGENavigator::rvGENavigator ( )
39 {
40 mWnd = NULL;
41 mWorkspace = NULL;
42 mVisibleIcon = NULL;
43 mScriptsIcon = NULL;
44 mVisibleIconDisabled = NULL;
45 mScriptsLightIcon = NULL;
46 }
47
48 /*
49 ================
50 rvGENavigator::Create
51
52 Creates the navigator window
53 ================
54 */
Create(HWND parent,bool visible)55 bool rvGENavigator::Create ( HWND parent, bool visible )
56 {
57 WNDCLASSEX wndClass;
58 memset ( &wndClass, 0, sizeof(wndClass) );
59 wndClass.cbSize = sizeof(WNDCLASSEX);
60 wndClass.lpszClassName = "GUIEDITOR_NAVIGATOR_CLASS";
61 wndClass.lpfnWndProc = rvGENavigator::WndProc;
62 wndClass.hbrBackground = (HBRUSH)GetStockObject( LTGRAY_BRUSH );;
63 wndClass.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW);
64 wndClass.lpszMenuName = NULL;
65 wndClass.hInstance = win32.hInstance;
66 RegisterClassEx ( &wndClass );
67
68 mVisibleIcon = (HICON)LoadImage ( win32.hInstance, MAKEINTRESOURCE(IDI_GUIED_NAV_VISIBLE), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR|LR_LOADMAP3DCOLORS );
69 mScriptsIcon = (HICON)LoadImage ( win32.hInstance, MAKEINTRESOURCE(IDI_GUIED_NAV_SCRIPTS), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR );
70 mScriptsLightIcon = (HICON)LoadImage ( win32.hInstance, MAKEINTRESOURCE(IDI_GUIED_NAV_SCRIPTSHI), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR );
71 mVisibleIconDisabled = (HICON)LoadImage ( win32.hInstance, MAKEINTRESOURCE(IDI_GUIED_NAV_VISIBLEDISABLED), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR|LR_LOADMAP3DCOLORS );
72 mExpandIcon = (HICON)LoadImage ( win32.hInstance, MAKEINTRESOURCE(IDI_GUIED_NAV_EXPAND), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR|LR_LOADMAP3DCOLORS );
73 mCollapseIcon = (HICON)LoadImage ( win32.hInstance, MAKEINTRESOURCE(IDI_GUIED_NAV_COLLAPSE), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR|LR_LOADMAP3DCOLORS );
74
75 mWnd = CreateWindowEx ( WS_EX_TOOLWINDOW,
76 "GUIEDITOR_NAVIGATOR_CLASS",
77 "Navigator",
78 WS_SYSMENU|WS_THICKFRAME|WS_CAPTION|WS_POPUP|WS_OVERLAPPED|WS_BORDER|WS_CLIPSIBLINGS|WS_CHILD,
79 0, 0, 200,300,
80 parent,
81 NULL,
82 win32.hInstance,
83 this );
84
85 if ( !mWnd )
86 {
87 return false;
88 }
89
90 if ( !gApp.GetOptions().GetWindowPlacement ( "navigator", mWnd ) )
91 {
92 RECT rParent;
93 RECT rNav;
94
95 GetWindowRect ( parent, &rParent );
96 GetWindowRect ( mWnd, &rNav );
97 SetWindowPos ( mWnd, NULL,
98 rParent.right - 10 - (rNav.right-rNav.left),
99 rParent.bottom - 10 - (rNav.bottom-rNav.top),
100 0,0,
101 SWP_NOZORDER|SWP_NOSIZE );
102 }
103
104 Show ( visible );
105
106 return true;
107 }
108
109 /*
110 ================
111 Draw3dRect
112
113 Draws a 3d rectangle using the given brushes
114 ================
115 */
Draw3dRect(HDC hDC,RECT * rect,HBRUSH topLeft,HBRUSH bottomRight)116 void Draw3dRect ( HDC hDC, RECT* rect, HBRUSH topLeft, HBRUSH bottomRight )
117 {
118 RECT rOut;
119
120 SetRect ( &rOut, rect->left, rect->top, rect->right - 1, rect->top + 1 );
121 FillRect ( hDC,&rOut, topLeft );
122
123 SetRect ( &rOut, rect->left, rect->top, rect->left + 1, rect->bottom );
124 FillRect( hDC,&rOut, topLeft );
125
126 SetRect ( &rOut, rect->right, rect->top, rect->right -1, rect->bottom );
127 FillRect( hDC,&rOut, bottomRight );
128
129 SetRect ( &rOut, rect->left, rect->bottom, rect->right, rect->bottom - 1 );
130 FillRect( hDC,&rOut, bottomRight );
131 }
132
133 /*
134 ================
135 rvGENavigator::WndProc
136
137 Window Procedure
138 ================
139 */
WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)140 LRESULT CALLBACK rvGENavigator::WndProc ( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
141 {
142 rvGENavigator* nav = (rvGENavigator*) GetWindowLong ( hWnd, GWL_USERDATA );
143
144 switch ( msg )
145 {
146 case WM_INITMENUPOPUP:
147 return SendMessage ( gApp.GetMDIFrame ( ), msg, wParam, lParam );
148
149 case WM_ACTIVATE:
150 common->ActivateTool( LOWORD( wParam ) != WA_INACTIVE );
151 break;
152
153 case WM_ERASEBKGND:
154 return TRUE;
155
156 case WM_DESTROY:
157 gApp.GetOptions().SetWindowPlacement ( "navigator", hWnd );
158 break;
159
160 case WM_CLOSE:
161 gApp.GetOptions().SetNavigatorVisible ( false );
162 nav->Show ( false );
163 return 0;
164
165 case WM_DRAWITEM:
166 {
167 DRAWITEMSTRUCT* dis = (DRAWITEMSTRUCT*) lParam;
168 idWindow* window = (idWindow*)dis->itemData;
169
170 if ( window )
171 {
172 rvGEWindowWrapper* wrapper = rvGEWindowWrapper::GetWrapper ( window );
173 idStr name = window->GetName();
174 RECT rDraw;
175 float offset;
176 bool disabled;
177
178 idWindow* parent = window;
179 offset = 1;
180 disabled = false;
181 while ( parent = parent->GetParent ( ) )
182 {
183 if ( rvGEWindowWrapper::GetWrapper ( parent )->IsHidden ( ) )
184 {
185 disabled = true;
186 }
187
188 offset += 10;
189 }
190
191 CopyRect ( &rDraw, &dis->rcItem );
192 rDraw.right = rDraw.left + GENAV_ITEMHEIGHT;
193 rDraw.top ++;
194
195 rDraw.right ++;
196 FrameRect ( dis->hDC, &rDraw, (HBRUSH)GetStockObject ( BLACK_BRUSH ) );
197 rDraw.right --;
198
199 FillRect ( dis->hDC, &rDraw, GetSysColorBrush ( COLOR_3DFACE ) );
200
201 Draw3dRect ( dis->hDC, &rDraw, GetSysColorBrush ( COLOR_3DHILIGHT ), GetSysColorBrush ( COLOR_3DSHADOW ) );
202
203 InflateRect ( &rDraw, -3, -3 );
204 Draw3dRect ( dis->hDC, &rDraw, GetSysColorBrush ( COLOR_3DSHADOW ), GetSysColorBrush ( COLOR_3DHILIGHT ) );
205
206 if ( !wrapper->IsHidden ( ) )
207 {
208 DrawIconEx ( dis->hDC, rDraw.left, rDraw.top, disabled?nav->mVisibleIconDisabled:nav->mVisibleIcon, 16, 16,0, NULL, DI_NORMAL );
209 }
210
211 CopyRect ( &rDraw, &dis->rcItem );
212 rDraw.left += GENAV_ITEMHEIGHT;
213 rDraw.left += 1;
214
215 if ( dis->itemState & ODS_SELECTED )
216 {
217 FillRect ( dis->hDC, &rDraw, GetSysColorBrush ( COLOR_HIGHLIGHT ) );
218 }
219 else
220 {
221 FillRect ( dis->hDC, &rDraw, GetSysColorBrush ( COLOR_WINDOW ) );
222 }
223
224 if ( wrapper->CanHaveChildren ( ) && window->GetChildCount ( ) )
225 {
226 if ( wrapper->IsExpanded ( ) )
227 {
228 DrawIconEx ( dis->hDC, rDraw.left + offset, rDraw.top + 3, nav->mCollapseIcon, 16, 16,0, NULL, DI_NORMAL );
229 }
230 else
231 {
232 DrawIconEx ( dis->hDC, rDraw.left + offset, rDraw.top + 3, nav->mExpandIcon, 16, 16,0, NULL, DI_NORMAL );
233 }
234 }
235
236 HPEN pen = CreatePen ( PS_SOLID, 1, GetSysColor ( COLOR_3DSHADOW ) );
237 HPEN oldpen = (HPEN)SelectObject ( dis->hDC, pen );
238 MoveToEx ( dis->hDC, rDraw.left, dis->rcItem.top, NULL );
239 LineTo ( dis->hDC, dis->rcItem.right, dis->rcItem.top );
240 MoveToEx ( dis->hDC, rDraw.left, dis->rcItem.bottom, NULL );
241 LineTo ( dis->hDC, dis->rcItem.right, dis->rcItem.bottom);
242 SelectObject ( dis->hDC, oldpen );
243 DeleteObject ( pen );
244
245 rDraw.left += offset;
246 rDraw.left += 20;
247
248 int colorIndex = ( (dis->itemState & ODS_SELECTED ) ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT );
249 SetTextColor ( dis->hDC, GetSysColor ( colorIndex ) );
250 DrawText ( dis->hDC, name, name.Length(), &rDraw, DT_LEFT|DT_VCENTER|DT_SINGLELINE );
251
252 if ( wrapper->GetVariableDict().GetNumKeyVals ( ) || wrapper->GetScriptDict().GetNumKeyVals ( ) )
253 {
254 DrawIconEx ( dis->hDC, dis->rcItem.right - 16, (dis->rcItem.bottom+dis->rcItem.top)/2-6, (dis->itemState & ODS_SELECTED)?nav->mScriptsLightIcon:nav->mScriptsIcon, 13, 13,0, NULL, DI_NORMAL );
255 }
256 }
257
258 break;
259 }
260
261 case WM_MEASUREITEM:
262 {
263 MEASUREITEMSTRUCT* mis = (MEASUREITEMSTRUCT*) lParam;
264 mis->itemHeight = 22;
265 break;
266 }
267
268 case WM_CREATE:
269 {
270 LPCREATESTRUCT cs;
271 LVCOLUMN col;
272
273 // Attach the class to the window first
274 cs = (LPCREATESTRUCT) lParam;
275 nav = (rvGENavigator*) cs->lpCreateParams;
276 SetWindowLong ( hWnd, GWL_USERDATA, (LONG)nav );
277
278 // Create the List view
279 nav->mTree = CreateWindowEx ( 0, "SysListView32", "", WS_VSCROLL|WS_CHILD|WS_VISIBLE|LVS_REPORT|LVS_OWNERDRAWFIXED|LVS_NOCOLUMNHEADER|LVS_SHOWSELALWAYS, 0, 0, 0, 0, hWnd, (HMENU)IDC_GUIED_WINDOWTREE, win32.hInstance, 0 );
280 ListView_SetExtendedListViewStyle ( nav->mTree, LVS_EX_FULLROWSELECT );
281 ListView_SetBkColor ( nav->mTree, GetSysColor ( COLOR_3DFACE ) );
282 ListView_SetTextBkColor ( nav->mTree, GetSysColor ( COLOR_3DFACE ) );
283 nav->mListWndProc = (WNDPROC)GetWindowLong ( nav->mTree, GWL_WNDPROC );
284 SetWindowLong ( nav->mTree, GWL_USERDATA, (LONG)nav );
285 SetWindowLong ( nav->mTree, GWL_WNDPROC, (LONG)ListWndProc );
286
287 // Insert the only column
288 col.mask = 0;
289 ListView_InsertColumn ( nav->mTree, 0, &col );
290
291 break;
292 }
293
294 case WM_SIZE:
295 {
296 RECT rClient;
297 MoveWindow ( nav->mTree, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE );
298 GetClientRect ( nav->mTree, &rClient );
299 ListView_SetColumnWidth ( nav->mTree, 0, rClient.right-rClient.left-1 );
300 break;
301 }
302
303 case WM_NCACTIVATE:
304 return gApp.ToolWindowActivate ( gApp.GetMDIFrame(), msg, wParam, lParam );
305
306 case WM_NOTIFY:
307 {
308 LPNMHDR nh;
309
310 nh = (LPNMHDR) lParam;
311
312 switch ( nh->code )
313 {
314 case NM_CLICK:
315 case NM_DBLCLK:
316 {
317 DWORD dwpos = GetMessagePos();
318 LVHITTESTINFO info;
319 info.pt.x = LOWORD(dwpos);
320 info.pt.y = HIWORD(dwpos);
321 MapWindowPoints(HWND_DESKTOP, nh->hwndFrom, &info.pt, 1);
322 int index = ListView_HitTest ( nav->mTree, &info );
323 if ( index != -1 )
324 {
325 RECT rItem;
326 int offset;
327 ListView_GetItemRect ( nav->mTree, index, &rItem, LVIR_BOUNDS );
328 LVITEM item;
329 item.mask = LVIF_PARAM;
330 item.iItem = index;
331 ListView_GetItem ( nav->mTree, &item );
332 idWindow* window = (idWindow*)item.lParam;
333 rvGEWindowWrapper* wrapper = rvGEWindowWrapper::GetWrapper(window);
334
335 offset = wrapper->GetDepth ( ) * 10 + 1;
336
337 if ( info.pt.x < GENAV_ITEMHEIGHT )
338 {
339 if ( !rvGEWindowWrapper::GetWrapper(window)->IsHidden ( ) )
340 {
341 nav->mWorkspace->HideWindow ( window );
342 }
343 else
344 {
345 nav->mWorkspace->UnhideWindow ( window );
346 }
347 }
348 else if ( info.pt.x > GENAV_ITEMHEIGHT + offset && info.pt.x < GENAV_ITEMHEIGHT + offset + 16 )
349 {
350 if ( wrapper->CanHaveChildren ( ) && window->GetChildCount ( ) )
351 {
352 if ( wrapper->IsExpanded ( ) )
353 {
354 wrapper->Collapse ( );
355 nav->Update ( );
356 }
357 else
358 {
359 wrapper->Expand ( );
360 nav->Update ( );
361 }
362 }
363 }
364 else if ( nh->code == NM_DBLCLK )
365 {
366 SendMessage ( gApp.GetMDIFrame ( ), WM_COMMAND, MAKELONG(ID_GUIED_ITEM_PROPERTIES,0), 0 );
367 }
368 }
369
370 break;
371 }
372
373 case NM_RCLICK:
374 {
375 DWORD dwpos = GetMessagePos();
376 LVHITTESTINFO info;
377 info.pt.x = LOWORD(dwpos);
378 info.pt.y = HIWORD(dwpos);
379 MapWindowPoints(HWND_DESKTOP, nh->hwndFrom, &info.pt, 1);
380 int index = ListView_HitTest ( nav->mTree, &info );
381
382 if ( index != -1 )
383 {
384 ClientToScreen ( hWnd, &info.pt );
385 HMENU menu = GetSubMenu ( LoadMenu ( gApp.GetInstance(), MAKEINTRESOURCE(IDR_GUIED_ITEM_POPUP) ), 0 );
386 TrackPopupMenu ( menu, TPM_RIGHTBUTTON|TPM_LEFTALIGN, info.pt.x, info.pt.y, 0, gApp.GetMDIFrame ( ), NULL );
387 DestroyMenu ( menu );
388 }
389
390 break;
391 }
392
393 case LVN_ITEMCHANGED:
394 {
395 NMLISTVIEW* nml = (NMLISTVIEW*) nh;
396 if ( (nml->uNewState & LVIS_SELECTED) != (nml->uOldState & LVIS_SELECTED) )
397 {
398 LVITEM item;
399 item.iItem = nml->iItem;
400 item.mask = LVIF_PARAM;
401 ListView_GetItem ( nav->mTree, &item );
402
403 if ( nml->uNewState & LVIS_SELECTED )
404 {
405 nav->mWorkspace->GetSelectionMgr().Add ( (idWindow*)item.lParam, false );
406 }
407 else
408 {
409 nav->mWorkspace->GetSelectionMgr().Remove ( (idWindow*)item.lParam );
410 }
411 }
412 break;
413 }
414 }
415
416 break;
417 }
418 }
419
420 return DefWindowProc ( hWnd, msg, wParam, lParam );
421 }
422
423 /*
424 ================
425 rvGENavigator::ListWndProc
426
427 Window Procedure for the embedded list control
428 ================
429 */
ListWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)430 LRESULT CALLBACK rvGENavigator::ListWndProc ( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
431 {
432 rvGENavigator* nav = (rvGENavigator*) GetWindowLong ( hWnd, GWL_USERDATA );
433 assert ( nav );
434
435 switch ( msg )
436 {
437 case WM_KEYDOWN:
438 case WM_KEYUP:
439 case WM_CHAR:
440 if ( nav->mWorkspace )
441 {
442 return SendMessage ( nav->mWorkspace->GetWindow(), msg, wParam, lParam );
443 }
444 break;
445 }
446
447 return CallWindowProc ( nav->mListWndProc, hWnd, msg, wParam, lParam );
448 }
449
450 /*
451 ================
452 rvGENavigator::AddWindow
453
454 Adds a new window to the navigator
455 ================
456 */
AddWindow(idWindow * window)457 void rvGENavigator::AddWindow ( idWindow* window )
458 {
459 int index;
460 LVITEM item;
461 rvGEWindowWrapper* wrapper;
462
463 wrapper = rvGEWindowWrapper::GetWrapper ( window );
464
465 // Dont add deleted windows
466 if ( !wrapper || wrapper->IsDeleted ( ) )
467 {
468 return;
469 }
470
471 // Insert the window into the tree
472 ZeroMemory ( &item, sizeof(item) );
473 item.mask = LVIF_PARAM|LVIF_STATE|LVIF_IMAGE;
474 item.iItem = ListView_GetItemCount ( mTree );
475 item.lParam = (LONG) window;
476 item.iImage = 0;
477 item.state = rvGEWindowWrapper::GetWrapper(window)->IsSelected ()? LVIS_SELECTED:0;
478 item.stateMask = LVIS_SELECTED;
479 ListView_InsertItem ( mTree, &item );
480
481 if ( item.state & LVIS_SELECTED )
482 {
483 ListView_EnsureVisible ( mTree, item.iItem, false );
484 }
485
486 // Dont continue if not expanded.
487 if ( !wrapper->IsExpanded ( ) )
488 {
489 return;
490 }
491
492 // Insert all the child windows into the tree
493 for ( index = 0; index < wrapper->GetChildCount(); index ++ )
494 {
495 AddWindow ( wrapper->GetChild(index) );
496 }
497 }
498
499 /*
500 ================
501 rvGENavigator::SetWorkspace
502
503 Sets a new workspace for the navigator window
504 ================
505 */
SetWorkspace(rvGEWorkspace * workspace)506 void rvGENavigator::SetWorkspace ( rvGEWorkspace* workspace )
507 {
508 mWorkspace = workspace;
509
510 Update ( );
511 }
512
513 /*
514 ================
515 rvGENavigator::Update
516
517 Updates the contents of the navigator window from the current workspace
518 ================
519 */
Update(void)520 void rvGENavigator::Update ( void )
521 {
522 // Clear the list first
523 ListView_DeleteAllItems ( mTree );
524
525 // Add starting with the desktop window
526 if ( mWorkspace )
527 {
528 AddWindow ( mWorkspace->GetInterface ( )->GetDesktop ( ) );
529 }
530
531 // For some reason the horizontal scrollbar wants to show up initially after an update
532 // so this forces it not to
533 RECT rClient;
534 GetClientRect ( mTree, &rClient );
535 ListView_SetColumnWidth ( mTree, 0, rClient.right-rClient.left-1 );
536 }
537
538 /*
539 ================
540 rvGENavigator::UpdateSelection
541
542 Updates the currently selected items
543 ================
544 */
UpdateSelections(void)545 void rvGENavigator::UpdateSelections ( void )
546 {
547 int count = ListView_GetItemCount ( mTree );
548 int i;
549
550 for ( i = 0; i < count; i++ )
551 {
552 LVITEM item;
553 idWindow* window;
554 rvGEWindowWrapper* wrapper;
555
556 item.iItem = i;
557 item.mask = LVIF_PARAM;
558 ListView_GetItem ( mTree, &item );
559 window = (idWindow*) item.lParam;
560 wrapper = rvGEWindowWrapper::GetWrapper ( window );
561
562 ListView_SetItemState ( mTree, i, wrapper->IsSelected ( )?LVIS_SELECTED:0, LVIS_SELECTED );
563
564 if ( wrapper->IsSelected ( ) )
565 {
566 ListView_EnsureVisible ( mTree, i, false );
567 }
568 }
569 }
570
571 /*
572 ================
573 rvGENavigator::Refresh
574
575 Repaints the navigator window
576 ================
577 */
Refresh(void)578 void rvGENavigator::Refresh ( void )
579 {
580 InvalidateRect ( mTree, NULL, FALSE );
581 // UpdateWindow ( mTree );
582 }
583
584 /*
585 ================
586 rvGENavigator::Show
587
588 Shows and hides the navigator window
589 ================
590 */
Show(bool visible)591 void rvGENavigator::Show ( bool visible )
592 {
593 gApp.GetOptions().SetNavigatorVisible ( visible );
594 ShowWindow ( mWnd, visible?SW_SHOW:SW_HIDE );
595 }
596