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 #include "../../renderer/tr_local.h"
34 #include "../../sys/win32/win_local.h"
35 #include "../../ui/DeviceContext.h"
36 #include "../../ui/EditWindow.h"
37 #include "../../ui/ListWindow.h"
38 #include "../../ui/BindWindow.h"
39 #include "../../ui/RenderWindow.h"
40 #include "../../ui/ChoiceWindow.h"
41
42 #include "GEApp.h"
43 #include "GEItemPropsDlg.h"
44 #include "GEItemScriptsDlg.h"
45
46 // Modifiers
47 #include "GEModifierGroup.h"
48 #include "GEMoveModifier.h"
49 #include "GESizeModifier.h"
50 #include "GEStateModifier.h"
51 #include "GEZOrderModifier.h"
52 #include "GEInsertModifier.h"
53 #include "GEHideModifier.h"
54 #include "GEDeleteModifier.h"
55
56 static float g_ZoomScales[rvGEWorkspace::ZOOM_MAX] = { 0, 0.25f, 0.33f, 0.50f, 0.66f, 1.0f, 1.5f, 2.0f, 3.0f };
57
58 static const int ID_GUIED_SELECT_FIRST = 9800;
59 static const int ID_GUIED_SELECT_LAST = 9900;
60
61 idList<rvGEClipboardItem*> rvGEWorkspace::mClipboard;
62
rvGEWorkspace(rvGEApp * app)63 rvGEWorkspace::rvGEWorkspace ( rvGEApp* app ) : mApplication ( app )
64 {
65 mWnd = 0;
66 mInterface = 0;
67 mZoom = ZOOM_100;
68 mScrollHorz = false;
69 mScrollVert = false;
70 mModified = false;
71 mNew = false;
72 mDragScroll = false;
73 mSourceControlState = SCS_CHECKEDOUT;
74 mFilename = "guis/Untitled.gui";
75 mDragType = rvGESelectionMgr::HT_NONE;
76 mHandCursor = LoadCursor ( app->GetInstance(), MAKEINTRESOURCE(IDC_GUIED_HAND) );
77 mDontAdd = false;
78
79 mSelections.SetWorkspace ( this );
80 }
81
~rvGEWorkspace()82 rvGEWorkspace::~rvGEWorkspace ( )
83 {
84 // Make sure all the wrappers get cleaned up
85 rvGEWindowWrapper::GetWrapper ( mInterface->GetDesktop ( ) )->EnumChildren ( CleanupEnumProc, NULL );
86
87 DestroyCursor ( mHandCursor );
88
89 delete mInterface;
90 }
91
92 /*
93 ================
94 rvGEWorkspace::CleanupEnumProc
95
96 Window enumeration procedure that deletes all the wrapper classes
97 ================
98 */
CleanupEnumProc(rvGEWindowWrapper * wrapper,void * data)99 bool rvGEWorkspace::CleanupEnumProc ( rvGEWindowWrapper* wrapper, void* data )
100 {
101 bool result;
102
103 if ( !wrapper )
104 {
105 return true;
106 }
107
108 result = wrapper->EnumChildren ( CleanupEnumProc, data );
109
110 // Cleanup the window wrapper
111 delete wrapper;
112
113 return result;
114 }
115
116 /*
117 ================
118 rvGEWorkspace::GetZoomScale
119
120 Returns the scale of the current zoom level
121 ================
122 */
GetZoomScale(void)123 float rvGEWorkspace::GetZoomScale ( void )
124 {
125 return g_ZoomScales [ mZoom ];
126 }
127
128 /*
129 ================
130 rvGEWorkspace::Attach
131
132 Attaches the workspace to the given window. This is usually done after the
133 window is created and the file has been loaded.
134 ================
135 */
Attach(HWND wnd)136 bool rvGEWorkspace::Attach ( HWND wnd )
137 {
138 assert ( wnd );
139
140 mWnd = wnd;
141
142 // Initialize the pixel format for this window
143 SetupPixelFormat ( );
144
145 // Jam the workspace pointer into the userdata window long so
146 // we can retrieve the workspace from the window later
147 SetWindowLong ( mWnd, GWL_USERDATA, (LONG) this );
148
149 UpdateTitle ( );
150
151 return true;
152 }
153
154 /*
155 ================
156 rvGEWorkspace::Detach
157
158 Detaches the workspace from the window it is currently attached to
159 ================
160 */
Detach(void)161 void rvGEWorkspace::Detach ( void )
162 {
163 assert ( mWnd );
164
165 SetWindowLong ( mWnd, GWL_USERDATA, 0 );
166 mWnd = NULL;
167 }
168
169 /*
170 ================
171 rvGEWorkspace::SetupPixelFormat
172
173 Setup the pixel format for the opengl context
174 ================
175 */
SetupPixelFormat(void)176 bool rvGEWorkspace::SetupPixelFormat ( void )
177 {
178 HDC hDC = GetDC ( mWnd );
179 bool result = true;
180
181 int pixelFormat = ChoosePixelFormat(hDC, &win32.pfd);
182 if (pixelFormat > 0)
183 {
184 if (SetPixelFormat(hDC, pixelFormat, &win32.pfd) == NULL)
185 {
186 result = false;
187 }
188 }
189 else
190 {
191 result = false;
192 }
193
194 ReleaseDC ( mWnd, hDC );
195
196 return result;
197 }
198
199 /*
200 ================
201 rvGEWorkspace::RenderGrid
202
203 Renders the grid on top of the user interface
204 ================
205 */
RenderGrid(void)206 void rvGEWorkspace::RenderGrid ( void )
207 {
208 float x;
209 float y;
210 float step;
211 idVec4& color = mApplication->GetOptions().GetGridColor ( );
212
213 // See if the grid is off before rendering it
214 if ( !mApplication->GetOptions().GetGridVisible ( ))
215 {
216 return;
217 }
218
219 qglEnable(GL_BLEND);
220 qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
221
222 qglColor4f ( color[0], color[1], color[2], 0.5f );
223
224 qglBegin ( GL_LINES );
225 step = mApplication->GetOptions().GetGridWidth ( ) * g_ZoomScales[mZoom];
226 for ( x = mRect.x + mRect.w; x >= mRect.x ; x -= step )
227 {
228 qglVertex2f ( x, mRect.y );
229 qglVertex2f ( x, mRect.y + mRect.h );
230 }
231 step = mApplication->GetOptions().GetGridHeight ( ) * g_ZoomScales[mZoom];
232 for ( y = mRect.y + mRect.h; y >= mRect.y ; y -= step )
233 {
234 qglVertex2f ( mRect.x, y );
235 qglVertex2f ( mRect.x + mRect.w, y );
236 }
237 qglEnd ( );
238
239 qglDisable(GL_BLEND);
240 qglColor3f ( color[0], color[1], color[2] );
241
242 qglBegin ( GL_LINES );
243 step = mApplication->GetOptions().GetGridWidth ( ) * g_ZoomScales[mZoom];
244 for ( x = mRect.x + mRect.w; x >= mRect.x ; x -= step * 4 )
245 {
246 qglVertex2f ( x, mRect.y );
247 qglVertex2f ( x, mRect.y + mRect.h );
248 }
249 step = mApplication->GetOptions().GetGridHeight ( ) * g_ZoomScales[mZoom];
250 for ( y = mRect.y + mRect.h; y >= mRect.y ; y -= step * 4 )
251 {
252 qglVertex2f ( mRect.x, y );
253 qglVertex2f ( mRect.x + mRect.w, y );
254 }
255 qglEnd ( );
256 }
257
258 /*
259 ================
260 rvGEWorkspace::Render
261
262 Renders the workspace to the given DC
263 ================
264 */
Render(HDC hdc)265 void rvGEWorkspace::Render ( HDC hdc )
266 {
267 int front;
268 int back;
269 float scale;
270
271 scale = g_ZoomScales[mZoom];
272
273 // Switch GL contexts to our dc
274 if (!qwglMakeCurrent( hdc, win32.hGLRC ))
275 {
276 common->Printf("ERROR: wglMakeCurrent failed.. Error:%i\n", qglGetError());
277 common->Printf("Please restart Q3Radiant if the Map view is not working\n");
278 return;
279 }
280
281 // Prepare the view and clear it
282 GL_State( GLS_DEFAULT );
283 qglViewport(0, 0, mWindowWidth, mWindowHeight );
284 qglScissor(0, 0, mWindowWidth, mWindowHeight );
285 qglClearColor ( 0.75f, 0.75f, 0.75f, 0 );
286
287 qglDisable(GL_DEPTH_TEST);
288 qglDisable(GL_CULL_FACE);
289 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
290
291 // Render the workspace below
292 qglMatrixMode(GL_PROJECTION);
293 qglLoadIdentity();
294 qglOrtho(0,mWindowWidth, mWindowHeight, 0, -1, 1);
295 qglMatrixMode(GL_MODELVIEW);
296 qglLoadIdentity();
297
298 qglColor3f ( mApplication->GetOptions().GetWorkspaceColor()[0], mApplication->GetOptions().GetWorkspaceColor()[1], mApplication->GetOptions().GetWorkspaceColor()[2] );
299 qglBegin ( GL_QUADS );
300 qglVertex2f ( mRect.x, mRect.y );
301 qglVertex2f ( mRect.x + mRect.w, mRect.y );
302 qglVertex2f ( mRect.x + mRect.w, mRect.y + mRect.h );
303 qglVertex2f ( mRect.x, mRect.y + mRect.h );
304 qglEnd ( );
305
306 // Prepare the renderSystem view to draw the GUI in
307 viewDef_t viewDef;
308 memset ( &viewDef, 0, sizeof(viewDef) );
309 tr.viewDef = &viewDef;
310 tr.viewDef->renderView.x = mRect.x;
311 tr.viewDef->renderView.y = mWindowHeight - mRect.y - mRect.h;
312 tr.viewDef->renderView.width = mRect.w;
313 tr.viewDef->renderView.height = mRect.h;
314 tr.viewDef->scissor.x1 = 0;
315 tr.viewDef->scissor.y1 = 0;
316 tr.viewDef->scissor.x2 = mRect.w;
317 tr.viewDef->scissor.y2 = mRect.h;
318 tr.viewDef->isEditor = true;
319 renderSystem->BeginFrame(mWindowWidth, mWindowHeight );
320
321 // Draw the gui
322 mInterface->Redraw ( 0 ); // eventLoop->Milliseconds() );
323
324 // We are done using the renderSystem now
325 renderSystem->EndFrame( &front, &back );
326
327 if ( mApplication->GetActiveWorkspace ( ) == this )
328 {
329 mApplication->GetStatusBar().SetTriangles ( backEnd.pc.c_drawIndexes/3 );
330 }
331
332 // Prepare the viewport for drawing selections, etc.
333 GL_State( GLS_DEFAULT );
334 qglDisable( GL_TEXTURE_CUBE_MAP_EXT );
335 // qglDisable(GL_BLEND);
336 qglDisable(GL_CULL_FACE);
337
338 qglViewport(0, 0, mWindowWidth, mWindowHeight );
339 qglScissor(0, 0, mWindowWidth, mWindowHeight );
340 qglMatrixMode(GL_PROJECTION);
341 qglLoadIdentity();
342 qglOrtho(0,mWindowWidth, mWindowHeight, 0, -1, 1);
343 qglMatrixMode(GL_MODELVIEW);
344 qglLoadIdentity();
345
346 RenderGrid ( );
347
348 mSelections.Render ( );
349
350 qglFinish ( );
351 qwglSwapBuffers(hdc);
352
353 qglEnable( GL_TEXTURE_CUBE_MAP_EXT );
354 qglEnable( GL_CULL_FACE);
355 }
356
357 /*
358 ================
359 rvGEWorkspace::UpdateTitle
360
361 Updates the window title with the name of the file and the zoom level and weither its open or not
362 ================
363 */
UpdateTitle(void)364 void rvGEWorkspace::UpdateTitle ( void )
365 {
366 // Set the window title based on the current filename
367 SetWindowText ( mWnd, va("%s%s (%d%%)", idStr(mFilename).StripPath ( ).c_str( ), mModified?"*":"", (int) (g_ZoomScales[mZoom] * 100)) );
368
369 gApp.GetStatusBar().SetZoom ( (int)(g_ZoomScales[mZoom] * 100.0f) );
370 }
371
372 /*
373 ================
374 rvGEWorkspace::UpdateRectangle
375
376 Updates the rectangle (not counting scrolling)
377 ================
378 */
UpdateRectangle(bool useScroll)379 void rvGEWorkspace::UpdateRectangle ( bool useScroll )
380 {
381 RECT rcClient;
382 float x;
383 float y;
384 float scale;
385
386 scale = g_ZoomScales[mZoom];
387
388 // Grab the current client rectangle of the window and cache off the width and height
389 GetClientRect ( mWnd, &rcClient );
390 mWindowWidth = rcClient.right - rcClient.left;
391 mWindowHeight = rcClient.bottom - rcClient.top;
392
393 // The workspace is always centered in the window
394 x = mRect.x = mWindowWidth / 2 - (SCREEN_WIDTH * scale) / 2;
395 y = mRect.y = mWindowHeight / 2 - (SCREEN_HEIGHT * scale) / 2;
396 mRect.w = (SCREEN_WIDTH * scale);
397 mRect.h = (SCREEN_HEIGHT * scale);
398
399 // When using the scroll position offset the rectangle based on the scrollbar positions
400 if ( useScroll )
401 {
402 // Adjust the start of the rectangle for the scroll positiond
403 mRect.y -= (float)GetScrollPos ( mWnd, SB_VERT ) / 1000.0f;
404 mRect.x -= (float)GetScrollPos ( mWnd, SB_HORZ ) / 1000.0f;
405 }
406 }
407
408 /*
409 ================
410 rvGEWorkspace::Scroll
411
412 Adjusts the given scrollbar by the given offset
413 ================
414 */
Scroll(int scrollbar,int offset)415 void rvGEWorkspace::Scroll ( int scrollbar, int offset )
416 {
417 SCROLLINFO si;
418
419 if ( scrollbar == SB_HORZ && !mScrollHorz )
420 {
421 return;
422 }
423 else if ( scrollbar == SB_VERT && !mScrollVert )
424 {
425 return;
426 }
427
428 // Get all the vertial scroll bar information
429 si.cbSize = sizeof (si);
430 si.fMask = SIF_ALL;
431
432 // Save the position for comparison later on
433 GetScrollInfo ( mWnd, scrollbar, &si);
434
435 si.nPos += (1000 * offset);
436 if ( si.nPos < si.nMin ) si.nPos = si.nMin;
437 if ( si.nPos > si.nMax ) si.nPos = si.nMax;
438
439 si.fMask = SIF_POS;
440 SetScrollInfo (mWnd, scrollbar, &si, TRUE);
441 GetScrollInfo (mWnd, scrollbar, &si);
442
443 UpdateRectangle ( );
444 }
445
HandleScroll(int scrollbar,WPARAM wParam,LPARAM lParam)446 int rvGEWorkspace::HandleScroll ( int scrollbar, WPARAM wParam, LPARAM lParam )
447 {
448 SCROLLINFO si;
449
450 // Get all the vertial scroll bar information
451 si.cbSize = sizeof (si);
452 si.fMask = SIF_ALL;
453
454 // Save the position for comparison later on
455 GetScrollInfo ( mWnd, scrollbar, &si);
456
457 switch (LOWORD (wParam))
458 {
459 // user clicked left or up arrow
460 case SB_LINELEFT:
461 si.nPos -= 1000;
462 break;
463
464 // user clicked right or down arrow
465 case SB_LINERIGHT:
466 si.nPos += 1000;
467 break;
468
469 // user clicked shaft left of the scroll box
470 case SB_PAGELEFT:
471 si.nPos -= si.nPage;
472 break;
473
474 // user clicked shaft right of the scroll box
475 case SB_PAGERIGHT:
476 si.nPos += si.nPage;
477 break;
478
479 // user dragged the scroll box
480 case SB_THUMBTRACK:
481 si.nPos = si.nTrackPos;
482 break;
483
484 default :
485 break;
486 }
487
488 // Set the position and then retrieve it. Due to adjustments
489 // by Windows it may not be the same as the value set.
490 si.fMask = SIF_POS;
491 SetScrollInfo (mWnd, scrollbar, &si, TRUE);
492 GetScrollInfo (mWnd, scrollbar, &si);
493
494 UpdateRectangle ( );
495
496 return 0;
497 }
498
499 /*
500 ================
501 rvGEWorkspace::UpdateScrollbars
502
503 Updates the states and the ranges of the scrollbars as well as the rectangle
504 ================
505 */
UpdateScrollbars(void)506 void rvGEWorkspace::UpdateScrollbars ( void )
507 {
508 SCROLLINFO info;
509
510 // First update the rectangle without applying scroll positions so
511 // we know the real sizes and coordinates
512 UpdateRectangle ( false );
513
514 // Setup the veritcal scrollbar
515 info.cbSize = sizeof(info);
516 info.fMask = SIF_RANGE|SIF_PAGE;
517 info.nMax = (mRect.h - mWindowHeight + 10) * 1000 / 2;
518 info.nMin = -info.nMax;
519 info.nPage = (int)((float)info.nMax * (float)((float)mWindowHeight / mRect.h));
520 info.nMax += info.nPage;
521
522 // If there is something to scroll then turn on the vertical scroll bar
523 // if its not on and update the scroll info.
524 if ( info.nMax > 0 )
525 {
526 if ( !mScrollVert )
527 {
528 mScrollVert = true;
529 ShowScrollBar ( mWnd, SB_VERT, mScrollVert );
530 }
531 SetScrollInfo ( mWnd, SB_VERT, &info, TRUE );
532 }
533 // Nothing to scroll, turn off the scrollbar if its on.
534 else if ( mScrollVert )
535 {
536 mScrollVert = false;
537 SetScrollPos ( mWnd, SB_VERT, 0, FALSE );
538 ShowScrollBar ( mWnd, SB_VERT, mScrollVert );
539 }
540
541 // Setup the horizontal scrollbar
542 info.nMax = (mRect.w - mWindowWidth + 10) * 1000 / 2;
543 info.nMin = -info.nMax;
544 info.nPage = (int)((float)info.nMax * (float)((float)mWindowWidth / mRect.w));
545 info.nMax += info.nPage;
546
547 // If there is something to scroll then turn on the vertical scroll bar
548 // if its not on and update the scroll info.
549 if ( info.nMax > 0 )
550 {
551 if ( !mScrollHorz )
552 {
553 mScrollHorz = true;
554 ShowScrollBar ( mWnd, SB_HORZ, mScrollHorz );
555 }
556
557 SetScrollInfo ( mWnd, SB_HORZ, &info, TRUE );
558 }
559 // Nothing to scroll, turn off the scrollbar if its on.
560 else if ( mScrollHorz )
561 {
562 mScrollHorz = false;
563 SetScrollPos ( mWnd, SB_HORZ, 0, FALSE );
564 ShowScrollBar ( mWnd, SB_HORZ, mScrollHorz );
565 }
566
567 // Need to update the rectangle again to take the scrollbar changes into account
568 UpdateRectangle ( true );
569 }
570
571 /*
572 ================
573 rvGEWorkspace::UpdateCursor
574
575 Called to update the cursor when the mouse is within the workspace window
576 ================
577 */
UpdateCursor(rvGESelectionMgr::EHitTest type)578 void rvGEWorkspace::UpdateCursor ( rvGESelectionMgr::EHitTest type )
579 {
580 switch ( type )
581 {
582 case rvGESelectionMgr::HT_SELECT:
583 SetCursor ( LoadCursor ( NULL, MAKEINTRESOURCE(IDC_ARROW) ) );
584 break;
585
586 case rvGESelectionMgr::HT_MOVE:
587 SetCursor ( LoadCursor ( NULL, MAKEINTRESOURCE(IDC_SIZEALL) ) );
588 break;
589
590 case rvGESelectionMgr::HT_SIZE_LEFT:
591 case rvGESelectionMgr::HT_SIZE_RIGHT:
592 SetCursor ( LoadCursor ( NULL, MAKEINTRESOURCE(IDC_SIZEWE ) ) );
593 break;
594
595 case rvGESelectionMgr::HT_SIZE_TOP:
596 case rvGESelectionMgr::HT_SIZE_BOTTOM:
597 SetCursor ( LoadCursor ( NULL, MAKEINTRESOURCE(IDC_SIZENS ) ) );
598 break;
599
600 case rvGESelectionMgr::HT_SIZE_TOPRIGHT:
601 case rvGESelectionMgr::HT_SIZE_BOTTOMLEFT:
602 SetCursor ( LoadCursor ( NULL, MAKEINTRESOURCE(IDC_SIZENESW ) ) );
603 break;
604
605 case rvGESelectionMgr::HT_SIZE_BOTTOMRIGHT:
606 case rvGESelectionMgr::HT_SIZE_TOPLEFT:
607 SetCursor ( LoadCursor ( NULL, MAKEINTRESOURCE(IDC_SIZENWSE ) ) );
608 break;
609 }
610 }
611
UpdateCursor(float x,float y)612 void rvGEWorkspace::UpdateCursor ( float x, float y )
613 {
614 idVec2 point;
615 rvGESelectionMgr::EHitTest type;
616
617 // First convert the worspace coord to a window coord
618 point = WorkspaceToWindow ( idVec2( x, y ) );
619
620 // See if it hits anything
621 type = mSelections.HitTest ( point.x, point.y );
622
623 // If it hits something then use it to update the cursor
624 if ( rvGESelectionMgr::HT_NONE != type )
625 {
626 UpdateCursor ( type );
627 }
628 else
629 {
630 SetCursor ( LoadCursor ( NULL, MAKEINTRESOURCE(IDC_ARROW ) ) );
631 }
632 }
633
UpdateCursor(void)634 void rvGEWorkspace::UpdateCursor ( void )
635 {
636 if ( mDragType == rvGESelectionMgr::HT_NONE )
637 {
638 POINT point;
639 idVec2 cursor;
640
641 GetCursorPos ( &point );
642 cursor.Set ( point.x, point.y );
643 WindowToWorkspace ( cursor );
644
645 UpdateCursor ( cursor.x, cursor.y );
646 }
647 else
648 {
649 UpdateCursor ( mDragType );
650 }
651 }
652
653 /*
654 ================
655 rvGEWorkspace::HandleMessage
656
657 Handles window messages to the workspace
658 ================
659 */
HandleMessage(UINT msg,WPARAM wParam,LPARAM lParam)660 void rvGEWorkspace::HandleMessage ( UINT msg, WPARAM wParam, LPARAM lParam )
661 {
662 switch ( msg )
663 {
664 case WM_CLOSE:
665 {
666
667 if ( IsModified ( ) )
668 {
669 if ( IDYES == gApp.MessageBox ( va("Save changes to the document \"%s\" before closing?", GetFilename() ), MB_YESNO|MB_ICONQUESTION ) )
670 {
671 SendMessage ( mApplication->GetMDIFrame(), WM_COMMAND, MAKELONG(ID_GUIED_FILE_SAVE,0), 0 );
672 }
673 }
674
675
676 GetApplication ( )->GetNavigator().SetWorkspace(NULL);
677 GetApplication ( )->GetTransformer().SetWorkspace(NULL);
678 GetApplication ( )->GetProperties().SetWorkspace(NULL);
679 break;
680 }
681
682 case WM_CAPTURECHANGED:
683 if ( (HWND)lParam != mWnd )
684 {
685 mDragScroll = false;
686 mDragType = rvGESelectionMgr::HT_NONE;
687 }
688 break;
689
690 case WM_SETCURSOR:
691 {
692 POINT point;
693 idVec2 cursor;
694 GetCursorPos ( &point );
695 cursor.Set ( point.x, point.y );
696 WindowToWorkspace ( cursor );
697 if ( mDragType == rvGESelectionMgr::HT_NONE )
698 {
699 UpdateCursor ( cursor.x, cursor.y );
700 }
701 else
702 {
703 UpdateCursor ( mDragType );
704 }
705 break;
706 }
707
708 case WM_MOUSEWHEEL:
709 if ( (short)HIWORD(wParam) > 0 )
710 {
711 ZoomIn ( );
712 }
713 else if ( (short)HIWORD(wParam) < 0 )
714 {
715 ZoomOut ( );
716 }
717 break;
718
719 case WM_MOUSEMOVE:
720 HandleMouseMove ( wParam, lParam );
721 break;
722
723 case WM_MBUTTONDOWN:
724 HandleMButtonDown ( wParam, lParam );
725 break;
726
727 case WM_MBUTTONUP:
728 HandleMButtonUp ( wParam, lParam );
729 break;
730
731 case WM_LBUTTONDOWN:
732 HandleLButtonDown ( wParam, lParam );
733 break;
734
735 case WM_LBUTTONUP:
736 HandleLButtonUp ( wParam, lParam );
737 break;
738
739 case WM_LBUTTONDBLCLK:
740 HandleLButtonDblClk ( wParam, lParam );
741 break;
742
743 case WM_INITMENUPOPUP:
744 SendMessage ( mApplication->GetMDIFrame(), msg, wParam, lParam );
745 break;
746
747 case WM_COMMAND:
748 HandleCommand ( wParam, lParam );
749 break;
750
751 case WM_RBUTTONDOWN:
752 HandleRButtonDown ( wParam, lParam );
753 break;
754
755 case WM_SIZE:
756 UpdateScrollbars();
757 break;
758
759 case WM_VSCROLL:
760 HandleScroll ( SB_VERT, wParam, lParam );
761 break;
762
763 case WM_HSCROLL:
764 HandleScroll ( SB_HORZ, wParam, lParam );
765 break;
766
767 case WM_KEYDOWN:
768 HandleKeyDown ( wParam, lParam );
769 break;
770 }
771 }
772 /*
773 ================
774 rvGEWorkspace::HandleCommand
775
776 Handles command messages destined for the workspace window. This is for
777 special workspace commands, any unhandled commands are forwarded to the main window
778 ================
779 */
HandleCommand(WPARAM wParam,LPARAM lParam)780 int rvGEWorkspace::HandleCommand ( WPARAM wParam, LPARAM lParam )
781 {
782 // Select command
783 if ( LOWORD(wParam) >= ID_GUIED_SELECT_FIRST && LOWORD(wParam) <= ID_GUIED_SELECT_LAST )
784 {
785 idWindow* window = mSelectMenu[LOWORD(wParam)-ID_GUIED_SELECT_FIRST];
786 rvGEWindowWrapper* wrapper = rvGEWindowWrapper::GetWrapper ( window );
787
788 // Handle multi select as well
789 if ( GetAsyncKeyState ( VK_SHIFT ) & 0x8000 )
790 {
791 if ( wrapper->IsSelected ( ) )
792 {
793 mSelections.Remove ( window );
794 }
795 else
796 {
797 mSelections.Add ( window );
798 }
799 }
800 else
801 {
802 mSelections.Set ( window );
803 }
804 }
805
806 return SendMessage ( mApplication->GetMDIFrame(), WM_COMMAND, wParam, lParam );
807 }
808
809 /*
810 ================
811 rvGEWorkspace::HandleMButtonDown
812
813 Handles the middle mouse down message in the workspace
814 ================
815 */
HandleMButtonDown(WPARAM wParam,LPARAM lParam)816 int rvGEWorkspace::HandleMButtonDown ( WPARAM wParam, LPARAM lParam )
817 {
818 if ( mDragType != rvGESelectionMgr::HT_NONE )
819 {
820 return 0;
821 }
822
823 mDragPoint.Set ( LOWORD(lParam), HIWORD(lParam) );
824 mDragScroll = true;
825 SetCursor ( mHandCursor );
826 SetCapture ( mWnd );
827
828 WindowToWorkspace ( mDragPoint );
829
830 return 0;
831 }
832
833 /*
834 ================
835 rvGEWorkspace::HandleMButtonUp
836
837 Handles the middle mouse up message in the workspace
838 ================
839 */
HandleMButtonUp(WPARAM wParam,LPARAM lParam)840 int rvGEWorkspace::HandleMButtonUp ( WPARAM wParam, LPARAM lParam )
841 {
842 if ( mDragScroll )
843 {
844 mDragScroll = false;
845 ReleaseCapture ( );
846 }
847
848 return 0;
849 }
850
851 /*
852 ================
853 rvGEWorkspace::HandleRButtonDown
854
855 Handles the left mouse down message in the workspace
856 ================
857 */
HandleRButtonDown(WPARAM wParam,LPARAM lParam)858 int rvGEWorkspace::HandleRButtonDown ( WPARAM wParam, LPARAM lParam )
859 {
860 POINT point = { LOWORD(lParam), HIWORD(lParam) };
861 HMENU menu;
862
863 // Add the select menu
864 mSelectMenu.Clear ( );
865
866 // Cache where the menu is being brought up so we can
867 // figure out which windows are under the point
868 mSelectMenuPos[0] = point.x;
869 mSelectMenuPos[1] = point.y;
870 WindowToWorkspace ( mSelectMenuPos );
871
872 // Build a list of all the windows under the menu point
873 rvGEWindowWrapper::GetWrapper ( mInterface->GetDesktop() )->EnumChildren ( BuildSelectMenuEnumProc, this );
874
875 // Add the desktop window always
876 mSelectMenu.Append ( mInterface->GetDesktop() );
877
878 //
879 menu = GetSubMenu ( LoadMenu ( mApplication->GetInstance(), MAKEINTRESOURCE(IDR_GUIED_ITEM_POPUP) ), 0 );
880
881 HMENU popup = CreatePopupMenu ( );
882
883 int i;
884 for ( i = 0; i < mSelectMenu.Num(); i ++ )
885 {
886 rvGEWindowWrapper* wrapper = rvGEWindowWrapper::GetWrapper ( mSelectMenu[i] );
887 AppendMenu ( popup, MF_STRING|MF_ENABLED|(wrapper->IsSelected()?MF_CHECKED:0), ID_GUIED_SELECT_FIRST + i, mSelectMenu[i]->GetName() );
888 }
889
890 InsertMenu ( menu, 1, MF_POPUP|MF_BYPOSITION, (LONG) popup, "Select" );
891
892 // Bring up the popup menu
893 ClientToScreen ( mWnd, &point );
894 TrackPopupMenu ( menu, TPM_RIGHTBUTTON|TPM_LEFTALIGN, point.x, point.y, 0, mWnd, NULL );
895
896 DestroyMenu ( popup );
897 DestroyMenu ( menu );
898
899 return 0;
900 }
901
902 /*
903 ================
904 rvGEWorkspace::HandleLButtonDown
905
906 Handles the left mouse down message in the workspace
907 ================
908 */
HandleLButtonDown(WPARAM wParam,LPARAM lParam)909 int rvGEWorkspace::HandleLButtonDown ( WPARAM wParam, LPARAM lParam )
910 {
911 if ( mDragScroll )
912 {
913 return 0;
914 }
915
916 idVec2 point ( LOWORD(lParam), HIWORD(lParam) );
917 WindowToWorkspace ( point );
918
919 // Make sure whatever modifications get generated cant be merged into whats already there
920 mModifiers.BlockNextMerge ( );
921
922 mDragPoint.Set ( LOWORD(lParam), HIWORD(lParam) );
923 mDragTime = Sys_Milliseconds ( );
924 mDragX = true;
925 mDragY = true;
926
927 // If we have selections then start a drag
928 if ( mSelections.Num ( ) )
929 {
930 mDragType = mSelections.HitTest ( mDragPoint.x, mDragPoint.y );
931 }
932
933 rvGEWindowWrapper* wrapper;
934 wrapper = rvGEWindowWrapper::GetWrapper ( mInterface->GetDesktop ( ) );
935
936 idWindow* window = wrapper->WindowFromPoint ( point.x, point.y );
937
938 // dissallow selection of the desktop.
939 if ( gApp.GetOptions().GetIgnoreDesktopSelect() && window == mInterface->GetDesktop ( ) )
940 {
941 window = NULL;
942 }
943
944 if ( mDragType == rvGESelectionMgr::HT_MOVE || mDragType == rvGESelectionMgr::HT_NONE )
945 {
946 if ( window )
947 {
948 bool selected;
949
950 selected = mSelections.IsSelected ( window );
951
952 if ( GetAsyncKeyState ( VK_SHIFT ) & 0x8000 )
953 {
954 if ( !selected )
955 {
956 mSelections.Add ( window );
957 mDragType = rvGESelectionMgr::HT_MOVE;
958 }
959 else
960 {
961 mSelections.Remove ( window );
962 }
963 }
964 else if ( !selected && mDragType == rvGESelectionMgr::HT_NONE )
965 {
966 mSelections.Set ( window );
967 mDragType = rvGESelectionMgr::HT_MOVE;
968 }
969 }
970 else
971 {
972 mSelections.Clear ( );
973 }
974 }
975
976 if ( mSelections.IsExpression ( ) )
977 {
978 mDragType = rvGESelectionMgr::HT_SELECT;
979 }
980 // Windows capture
981 else if ( mDragType != rvGESelectionMgr::HT_NONE )
982 {
983 SetCapture ( mWnd );
984 }
985
986 WindowToWorkspace ( mDragPoint );
987
988 return 0;
989 }
990
991 /*
992 ================
993 rvGEWorkspace::HandleLButtonUp
994
995 Handles the left mouse up message in the workspace
996 ================
997 */
HandleLButtonUp(WPARAM wParam,LPARAM lParam)998 int rvGEWorkspace::HandleLButtonUp ( WPARAM wParam, LPARAM lParam )
999 {
1000 if ( mDragType != rvGESelectionMgr::HT_NONE )
1001 {
1002 ReleaseCapture ( );
1003 mModifiers.BlockNextMerge ( );
1004
1005 // Update the transformer
1006 mApplication->GetTransformer().Update ( );
1007 }
1008
1009 // No more dragging
1010 mDragType = rvGESelectionMgr::HT_NONE;
1011
1012 return 0;
1013 }
1014
1015 /*
1016 ================
1017 rvGEWorkspace::HandleLButtonDblClk
1018
1019 Handle a double click by opening properties
1020 ================
1021 */
HandleLButtonDblClk(WPARAM wParam,LPARAM lParam)1022 int rvGEWorkspace::HandleLButtonDblClk ( WPARAM wParam, LPARAM lParam )
1023 {
1024 EditSelectedProperties ( );
1025 return 0;
1026 }
1027
1028 /*
1029 ================
1030 rvGEWorkspace::HandleMouseMove
1031
1032 Handles the moving of the mouse for dragging and cursor updating
1033 ================
1034 */
HandleMouseMove(WPARAM wParam,LPARAM lParam)1035 int rvGEWorkspace::HandleMouseMove ( WPARAM wParam, LPARAM lParam )
1036 {
1037 idVec2 cursor;
1038
1039 cursor.Set ( (short)LOWORD(lParam), (short)HIWORD(lParam) );
1040
1041 // Convert the window point to the workspace before updating the
1042 // cursor with the position
1043 WindowToWorkspace ( cursor );
1044
1045 // Scrolling the window around
1046 if ( mDragScroll )
1047 {
1048 Scroll ( SB_HORZ, mDragPoint.x - cursor.x );
1049 Scroll ( SB_VERT, mDragPoint.y - cursor.y );
1050
1051 SetCursor ( mHandCursor );
1052
1053 mDragPoint = cursor;
1054
1055 return 0;
1056 }
1057
1058 // If not dragging then just update the cursor and return
1059 if ( mDragType == rvGESelectionMgr::HT_NONE )
1060 {
1061 UpdateCursor ( cursor.x, cursor.y );
1062 return 0;
1063 }
1064
1065 // Dont allow a drag move start until the button has been down for 100 ms or so
1066 if ( mDragType == rvGESelectionMgr::HT_MOVE && Sys_Milliseconds() - mDragTime <= 50 )
1067 {
1068 return 0;
1069 }
1070
1071 // Handle grid snapping
1072 if ( gApp.GetOptions().GetGridSnap ( ) )
1073 {
1074 cursor.x = (float)(((int)cursor.x + gApp.GetOptions().GetGridWidth()/2) / gApp.GetOptions().GetGridWidth() * gApp.GetOptions().GetGridWidth());
1075 cursor.y = (float)(((int)cursor.y + gApp.GetOptions().GetGridWidth()/2) / gApp.GetOptions().GetGridWidth() * gApp.GetOptions().GetGridWidth());
1076 }
1077
1078 // If the cursor hasnt moved then there is nothing to update with the drag
1079 if ( (int) cursor.x == (int) mDragPoint.x && (int) cursor.y == (int) mDragPoint.y )
1080 {
1081 return 0;
1082 }
1083
1084 switch ( mDragType )
1085 {
1086 case rvGESelectionMgr::HT_MOVE:
1087 AddModifierMove ( "Move", cursor.x - mDragPoint.x, cursor.y - mDragPoint.y, mApplication->GetOptions().GetGridSnap ( ) );
1088 break;
1089
1090 case rvGESelectionMgr::HT_SIZE_BOTTOM:
1091 AddModifierSize ( "Size", 0, 0, 0, cursor.y - mDragPoint.y, mApplication->GetOptions().GetGridSnap ( ) );
1092 break;
1093
1094 case rvGESelectionMgr::HT_SIZE_TOP:
1095 AddModifierSize ( "Size", 0, cursor.y - mDragPoint.y, 0, 0, mApplication->GetOptions().GetGridSnap ( ) );
1096 break;
1097
1098 case rvGESelectionMgr::HT_SIZE_RIGHT:
1099 AddModifierSize ( "Size", 0, 0, cursor.x - mDragPoint.x, 0, mApplication->GetOptions().GetGridSnap ( ) );
1100 break;
1101
1102 case rvGESelectionMgr::HT_SIZE_LEFT:
1103 AddModifierSize ( "Size", cursor.x - mDragPoint.x, 0, 0, 0, mApplication->GetOptions().GetGridSnap ( ) );
1104 break;
1105
1106 case rvGESelectionMgr::HT_SIZE_TOPLEFT:
1107 AddModifierSize ( "Size", cursor.x - mDragPoint.x, cursor.y - mDragPoint.y, 0, 0, mApplication->GetOptions().GetGridSnap ( ) );
1108 break;
1109
1110 case rvGESelectionMgr::HT_SIZE_TOPRIGHT:
1111 AddModifierSize ( "Size", 0, cursor.y - mDragPoint.y, cursor.x - mDragPoint.x, 0, mApplication->GetOptions().GetGridSnap ( ) );
1112 break;
1113
1114 case rvGESelectionMgr::HT_SIZE_BOTTOMLEFT:
1115 AddModifierSize ( "Size", cursor.x - mDragPoint.x, 0, 0, cursor.y - mDragPoint.y, mApplication->GetOptions().GetGridSnap ( ) );
1116 break;
1117
1118 case rvGESelectionMgr::HT_SIZE_BOTTOMRIGHT:
1119 AddModifierSize ( "Size", 0, 0, cursor.x - mDragPoint.x, cursor.y - mDragPoint.y, mApplication->GetOptions().GetGridSnap ( ) );
1120 break;
1121 }
1122
1123 UpdateCursor ( mDragType );
1124
1125 // If the x coordinate has changed then update it
1126 if ( (int)cursor.x != (int)mDragPoint.x && mDragX )
1127 {
1128 mDragPoint.x = cursor.x;
1129 }
1130
1131 // If the y coordinate has changed then update it
1132 if ( (int)cursor.y != (int)mDragPoint.y && mDragY )
1133 {
1134 mDragPoint.y = cursor.y;
1135 }
1136
1137 return 0;
1138 }
1139
1140 /*
1141 ================
1142 rvGEWorkspace::HandleKeyDown
1143
1144 Handles the the pressing of a key
1145 ================
1146 */
HandleKeyDown(WPARAM wParam,LPARAM lParam)1147 int rvGEWorkspace::HandleKeyDown ( WPARAM wParam, LPARAM lParam )
1148 {
1149 bool shift = (GetAsyncKeyState ( VK_SHIFT ) & 0x8000) ? true : false;
1150
1151 switch ( wParam )
1152 {
1153 case VK_LEFT:
1154 if ( shift )
1155 {
1156 AddModifierSizeNudge ( -1, 0, false );
1157 }
1158 else
1159 {
1160 AddModifierMoveNudge ( -1, 0, false );
1161 }
1162 break;
1163
1164 case VK_RIGHT:
1165 if ( shift )
1166 {
1167 AddModifierSizeNudge ( 1, 0, false );
1168 }
1169 else
1170 {
1171 AddModifierMoveNudge ( 1, 0, false );
1172 }
1173 break;
1174
1175 case VK_DOWN:
1176 if ( shift )
1177 {
1178 AddModifierSizeNudge ( 0, 1, false );
1179 }
1180 else
1181 {
1182 AddModifierMoveNudge ( 0, 1, false );
1183 }
1184 break;
1185
1186 case VK_UP:
1187 if ( shift )
1188 {
1189 AddModifierSizeNudge ( 0, -1, false );
1190 }
1191 else
1192 {
1193 AddModifierMoveNudge ( 0, -1, false );
1194 }
1195 break;
1196
1197 case VK_ESCAPE:
1198 mSelections.Clear ( );
1199 mApplication->GetNavigator().Update ( );
1200 break;
1201 }
1202
1203 return 0;
1204 }
1205
1206 /*
1207 ================
1208 rvGEWorkspace::WindowToWorkspace
1209
1210 Converts the given coordinates in windows space to the workspace's coordinates.
1211 ================
1212 */
WindowToWorkspace(idVec2 & point)1213 idVec2& rvGEWorkspace::WindowToWorkspace ( idVec2& point )
1214 {
1215 point.x = (point.x - mRect.x) / mRect.w * SCREEN_WIDTH;
1216 point.y = (point.y - mRect.y) / mRect.h * SCREEN_HEIGHT;
1217
1218 return point;
1219 }
1220
WindowToWorkspace(idRectangle & rect)1221 idRectangle& rvGEWorkspace::WindowToWorkspace ( idRectangle& rect )
1222 {
1223 rect.x = (rect.x - mRect.x) / mRect.w * SCREEN_WIDTH;
1224 rect.y = (rect.y - mRect.y) / mRect.h * SCREEN_HEIGHT;
1225 rect.w = rect.w / mRect.w * SCREEN_WIDTH;
1226 rect.h = rect.h / mRect.h * SCREEN_HEIGHT;
1227
1228 return rect;
1229 }
1230
1231 /*
1232 ================
1233 rvGEWorkspace::WindowToWorkspace
1234
1235 Converts the given workspace coordinates to the windows coordinates.
1236 ================
1237 */
WorkspaceToWindow(idVec2 & point)1238 idVec2& rvGEWorkspace::WorkspaceToWindow ( idVec2& point )
1239 {
1240 point.x = mRect.x + (point.x / SCREEN_WIDTH * mRect.w);
1241 point.y = mRect.y + (point.y / SCREEN_HEIGHT * mRect.h);
1242
1243 return point;
1244 }
1245
WorkspaceToWindow(idRectangle & rect)1246 idRectangle& rvGEWorkspace::WorkspaceToWindow ( idRectangle& rect )
1247 {
1248 rect.x = mRect.x + (rect.x / SCREEN_WIDTH * mRect.w);
1249 rect.y = mRect.y + (rect.y / SCREEN_HEIGHT * mRect.h);
1250 rect.w = rect.w / SCREEN_WIDTH * mRect.w;
1251 rect.h = rect.h / SCREEN_HEIGHT * mRect.h;
1252
1253 return rect;
1254 }
1255
1256 /*
1257 ================
1258 rvGEWorkspace::ZoomIn
1259
1260 Zooms the workspace in by one zoom level
1261 ================
1262 */
ZoomIn(void)1263 rvGEWorkspace::EZoomLevel rvGEWorkspace::ZoomIn ( void )
1264 {
1265 mZoom = mZoom + 1;
1266 if ( mZoom >= ZOOM_MAX )
1267 {
1268 mZoom = ZOOM_MAX - 1;
1269 }
1270
1271 UpdateScrollbars ( );
1272 UpdateTitle ( );
1273
1274 InvalidateRect ( mWnd, NULL, FALSE );
1275
1276 return (EZoomLevel)mZoom;
1277 }
1278
1279 /*
1280 ================
1281 rvGEWorkspace::ZoomOut
1282
1283 Zooms the workspace out by one level
1284 ================
1285 */
ZoomOut(void)1286 rvGEWorkspace::EZoomLevel rvGEWorkspace::ZoomOut ( void )
1287 {
1288 mZoom--;
1289 if ( mZoom <= ZOOM_MIN )
1290 {
1291 mZoom = ZOOM_MIN + 1;
1292 }
1293
1294 UpdateScrollbars ( );
1295 UpdateTitle ( );
1296
1297 InvalidateRect ( mWnd, NULL, FALSE );
1298
1299 return (EZoomLevel)mZoom;
1300 }
1301
1302 /*
1303 ================
1304 rvGEWorkspace::CreateModifier
1305
1306 Creates a new modifier of the given type for the given window. This function is called
1307 specifically from the add modifiers function with the variable args list forwarded.
1308 ================
1309 */
CreateModifier(EModifierType type,idWindow * window,va_list args)1310 rvGEModifier* rvGEWorkspace::CreateModifier ( EModifierType type, idWindow* window, va_list args )
1311 {
1312 rvGEModifier* mod;
1313
1314 switch ( type )
1315 {
1316 case MOD_DELETE:
1317 mod = new rvGEDeleteModifier ( "Delete", window );
1318 break;
1319
1320 case MOD_HIDE:
1321 mod = new rvGEHideModifier ( "Hide", window, true );
1322 break;
1323
1324 case MOD_UNHIDE:
1325 mod = new rvGEHideModifier ( "Hide", window, false );
1326 break;
1327
1328 case MOD_SEND_BACKWARD:
1329 mod = new rvGEZOrderModifier ( "Send Backward", window, rvGEZOrderModifier::ZO_BACKWARD );
1330 break;
1331
1332 case MOD_SEND_BACK:
1333 mod = new rvGEZOrderModifier ( "Send to Back", window, rvGEZOrderModifier::ZO_BACK );
1334 break;
1335
1336 case MOD_BRING_FORWARD:
1337 mod = new rvGEZOrderModifier ( "Bring Forward", window, rvGEZOrderModifier::ZO_FORWARD );
1338 break;
1339
1340 case MOD_BRING_FRONT:
1341 mod = new rvGEZOrderModifier ( "Bring to Front", window, rvGEZOrderModifier::ZO_FRONT );
1342 break;
1343
1344 default:
1345 mod = NULL;
1346 break;
1347 }
1348
1349 return mod;
1350 }
1351
1352 /*
1353 ================
1354 rvGEWorkspace::AddModifiers
1355
1356 Add the specific modifier for the given window
1357 ================
1358 */
AddModifiers(idWindow * window,EModifierType type,...)1359 void rvGEWorkspace::AddModifiers ( idWindow* window, EModifierType type, ... )
1360 {
1361 va_list args;
1362
1363 va_start(args,type) ;
1364 mModifiers.Append ( CreateModifier ( type, window, args ) );
1365 va_end (args) ;
1366
1367 SetModified ( true );
1368 }
1369
AddModifiers(EModifierType type,...)1370 void rvGEWorkspace::AddModifiers ( EModifierType type, ... )
1371 {
1372 va_list args;
1373
1374 // Nothing to move if there is no selection
1375 if ( !mSelections.Num ( ) )
1376 {
1377 return;
1378 }
1379 // More than one selection requires a modifier group
1380 else if ( mSelections.Num ( ) > 1 )
1381 {
1382 rvGEModifierGroup* group = new rvGEModifierGroup;
1383 int i;
1384
1385 for ( i = 0; i < mSelections.Num(); i ++ )
1386 {
1387 va_start(args,type);
1388 group->Append ( CreateModifier ( type, mSelections[i], args ) );
1389 va_end (args);
1390 }
1391
1392 mModifiers.Append ( group );
1393 }
1394 // Single modifier
1395 else
1396 {
1397 va_start(args,type) ;
1398 mModifiers.Append ( CreateModifier ( type, mSelections[0], args ) );
1399 va_end (args) ;
1400 }
1401
1402 SetModified ( true );
1403 }
1404
BuildSelectMenuEnumProc(rvGEWindowWrapper * wrapper,void * data)1405 bool rvGEWorkspace::BuildSelectMenuEnumProc ( rvGEWindowWrapper* wrapper, void* data )
1406 {
1407 rvGEWorkspace* workspace;
1408
1409 workspace = (rvGEWorkspace*) data;
1410 assert ( workspace );
1411
1412 if ( !wrapper )
1413 {
1414 return true;
1415 }
1416
1417 wrapper->EnumChildren ( BuildSelectMenuEnumProc, data );
1418
1419 if ( wrapper->IsDeleted ( ) || wrapper->IsHidden ( ) )
1420 {
1421 return true;
1422 }
1423
1424 if ( wrapper->GetScreenRect ( ).Contains ( workspace->mSelectMenuPos[0], workspace->mSelectMenuPos[1] ) )
1425 {
1426 workspace->mSelectMenu.Append ( wrapper->GetWindow ( ));
1427 }
1428
1429 return true;
1430 }
1431
ShowAllEnumProc(rvGEWindowWrapper * wrapper,void * data)1432 bool rvGEWorkspace::ShowAllEnumProc ( rvGEWindowWrapper* wrapper, void* data )
1433 {
1434 rvGEModifierGroup* group = (rvGEModifierGroup*) data;
1435
1436 wrapper->EnumChildren ( ShowAllEnumProc, data );
1437
1438 if ( wrapper->IsHidden ( ) )
1439 {
1440 group->Append ( new rvGEHideModifier ( "Show Hidden", wrapper->GetWindow ( ), false ) );
1441 }
1442
1443 return true;
1444 }
1445
AddModifierShowAll(void)1446 void rvGEWorkspace::AddModifierShowAll ( void )
1447 {
1448 rvGEModifierGroup* group = new rvGEModifierGroup;
1449
1450 rvGEWindowWrapper::GetWrapper( mInterface->GetDesktop ( ) )->EnumChildren ( ShowAllEnumProc, group );
1451
1452 if ( !group->GetCount ( ) )
1453 {
1454 delete group;
1455 }
1456 else
1457 {
1458 mModifiers.Append ( group );
1459 }
1460
1461 mApplication->GetNavigator().Refresh ( );
1462 }
1463
DeleteSelected(void)1464 void rvGEWorkspace::DeleteSelected ( void )
1465 {
1466 AddModifiers ( MOD_DELETE );
1467 mSelections.Clear ( );
1468 mApplication->GetNavigator().Update ( );
1469 }
1470
1471 /*
1472 ================
1473 rvGEWorkspace::NewWindow
1474
1475 Create a new window
1476 ================
1477 */
NewWindow(idDict * state,rvGEWindowWrapper::EWindowType type)1478 idWindow* rvGEWorkspace::NewWindow ( idDict* state, rvGEWindowWrapper::EWindowType type )
1479 {
1480 idWindow* window = new idWindow ( mInterface->GetDesktop()->GetDC(), mInterface );
1481 rvGEWindowWrapper* wrapper;
1482 int count;
1483 idStr baseName;
1484
1485 switch ( type )
1486 {
1487 case rvGEWindowWrapper::WT_NORMAL:
1488 window = new idWindow ( mInterface->GetDesktop()->GetDC(), mInterface );
1489 break;
1490
1491 case rvGEWindowWrapper::WT_BIND:
1492 window = new idBindWindow ( mInterface->GetDesktop()->GetDC(), mInterface );
1493 break;
1494
1495 case rvGEWindowWrapper::WT_RENDER:
1496 window = new idRenderWindow ( mInterface->GetDesktop()->GetDC(), mInterface );
1497 break;
1498
1499 case rvGEWindowWrapper::WT_CHOICE:
1500 window = new idChoiceWindow ( mInterface->GetDesktop()->GetDC(), mInterface );
1501 break;
1502
1503 case rvGEWindowWrapper::WT_EDIT:
1504 window = new idEditWindow ( mInterface->GetDesktop()->GetDC(), mInterface );
1505 break;
1506
1507 default:
1508 assert ( false );
1509 return NULL;
1510 }
1511
1512 baseName = state ? state->GetString("name","unnamed") : "unnamed";
1513 baseName.StripQuotes ( );
1514
1515 count = 0;
1516 if ( mInterface->GetDesktop()->FindChildByName ( baseName ) )
1517 {
1518 count = 1;
1519 while ( 1 )
1520 {
1521 drawWin_t* dw = mInterface->GetDesktop()->FindChildByName ( va("%s%d",baseName.c_str(),count) );
1522 if ( !dw )
1523 {
1524 break;
1525 }
1526 assert ( dw->win );
1527 wrapper = rvGEWindowWrapper::GetWrapper ( dw->win );
1528 if ( wrapper && wrapper->IsDeleted ( ) )
1529 {
1530 break;
1531 }
1532 count++;
1533 }
1534 }
1535
1536 idStr winName;
1537 idStr winTemplate;
1538
1539 if ( count )
1540 {
1541 winName = va("%s%d", baseName.c_str(), count );
1542 }
1543 else
1544 {
1545 winName = baseName;
1546 }
1547 winTemplate = winName + " { }";
1548
1549 idParser src( winTemplate, winTemplate.Length(), "", LEXFL_ALLOWMULTICHARLITERALS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
1550 window->Parse ( &src );
1551
1552 wrapper = rvGEWindowWrapper::GetWrapper ( window );
1553
1554 if ( state )
1555 {
1556 wrapper->SetState ( *state );
1557 }
1558
1559 wrapper->SetStateKey ( "name", winName );
1560 wrapper->Finish ( );
1561
1562 SetModified ( true );
1563
1564
1565 return window;
1566 }
1567
AddWindow(rvGEWindowWrapper::EWindowType type)1568 idWindow* rvGEWorkspace::AddWindow ( rvGEWindowWrapper::EWindowType type )
1569 {
1570 idWindow* window;
1571 idDict state;
1572
1573 state.Set ( "rect", "0,0,100,100" );
1574 state.Set ( "visible", "1" );
1575
1576 window = NewWindow ( &state, type );
1577 assert ( window );
1578
1579 mModifiers.Append ( new rvGEInsertModifier ( "New", window, mInterface->GetDesktop(), NULL ) );
1580
1581 mSelections.Set ( window );
1582 mApplication->GetNavigator().Update ( );
1583 mApplication->GetTransformer().Update ( );
1584 mApplication->GetProperties().Update ( );
1585
1586 return window;
1587 }
1588
EditSelectedProperties(void)1589 bool rvGEWorkspace::EditSelectedProperties ( void )
1590 {
1591 if ( !mSelections.Num ( ) || mSelections.Num() > 1 )
1592 {
1593 return false;
1594 }
1595
1596 idDict dict;
1597 if ( GEItemPropsDlg_DoModal ( mWnd, mSelections[0], dict ) )
1598 {
1599 mModifiers.Append ( new rvGEStateModifier ( "Item Properties", mSelections[0], dict ) );
1600 SetModified ( true );
1601 }
1602
1603 mApplication->GetNavigator().Update ( );
1604 mApplication->GetTransformer().Update ( );
1605 mApplication->GetProperties().Update ( );
1606
1607 return true;
1608 }
1609
EditSelectedScripts(void)1610 bool rvGEWorkspace::EditSelectedScripts ( void )
1611 {
1612 if ( GEItemScriptsDlg_DoModal ( mWnd, mSelections[0] ) )
1613 {
1614 gApp.GetNavigator().Refresh ( );
1615 SetModified ( true );
1616 }
1617
1618 return true;
1619 }
1620
BringSelectedForward(void)1621 void rvGEWorkspace::BringSelectedForward ( void )
1622 {
1623 AddModifiers ( MOD_BRING_FORWARD );
1624 mApplication->GetNavigator().Update ( );
1625 }
1626
BringSelectedToFront(void)1627 void rvGEWorkspace::BringSelectedToFront ( void )
1628 {
1629 AddModifiers ( MOD_BRING_FRONT );
1630 mApplication->GetNavigator().Update ( );
1631 }
1632
SendSelectedToBack(void)1633 void rvGEWorkspace::SendSelectedToBack ( void )
1634 {
1635 AddModifiers ( MOD_SEND_BACK );
1636 mApplication->GetNavigator().Update ( );
1637 }
1638
SendSelectedBackward(void)1639 void rvGEWorkspace::SendSelectedBackward ( void )
1640 {
1641 AddModifiers ( MOD_SEND_BACKWARD );
1642 mApplication->GetNavigator().Update ( );
1643 }
1644
1645 /*
1646 ================
1647 rvGEWorkspace::MakeSelectedSameSize
1648
1649 Align the selected items to the first one using the given align type
1650 ================
1651 */
MakeSelectedSameSize(bool changeWidth,bool changeHeight)1652 void rvGEWorkspace::MakeSelectedSameSize ( bool changeWidth, bool changeHeight )
1653 {
1654 rvGEModifierGroup* group;
1655 idRectangle rectTo;
1656 int i;
1657
1658 group = new rvGEModifierGroup ( );
1659
1660 rectTo = rvGEWindowWrapper::GetWrapper ( mSelections[0] )->GetClientRect ( );
1661
1662 for ( i = 1; i < mSelections.Num(); i ++ )
1663 {
1664 idRectangle rectFrom;
1665 float width = 0;
1666 float height = 0;
1667
1668 rectFrom = rvGEWindowWrapper::GetWrapper(mSelections[i])->GetClientRect ();
1669
1670 if ( changeWidth )
1671 {
1672 width = rectTo.w - rectFrom.w;
1673 }
1674
1675 if ( changeHeight )
1676 {
1677 height = rectTo.h - rectFrom.h;
1678 }
1679
1680 group->Append ( new rvGESizeModifier ( "Make Same Size", mSelections[i], 0, 0, width, height ) );
1681 }
1682
1683 mModifiers.Append ( group );
1684
1685 // Cant merge alignments
1686 mModifiers.BlockNextMerge ( );
1687
1688 SetModified ( true );
1689 }
1690
1691 /*
1692 ================
1693 rvGEWorkspace::AlignSelected
1694
1695 Align the selected items to the first one using the given align type
1696 ================
1697 */
AlignSelected(EItemAlign align)1698 void rvGEWorkspace::AlignSelected ( EItemAlign align )
1699 {
1700 static const char* alignNames[]={"Lefts","Centers","Rights","Tops","Middles","Bottoms" };
1701 int i;
1702 idStr modName;
1703 rvGEModifierGroup* group;
1704
1705 assert ( mSelections.Num() > 1 );
1706
1707 modName = "Align " + idStr(alignNames[align]);
1708
1709 group = new rvGEModifierGroup ( );
1710
1711 idRectangle rectTo;
1712 rectTo = rvGEWindowWrapper::GetWrapper ( mSelections[0] )->GetScreenRect ( );
1713
1714 // Everything gets aligned to the first selection so run
1715 // through all other selections and move them.
1716 for ( i = 1; i < mSelections.Num(); i ++ )
1717 {
1718 float x;
1719 float y;
1720 idRectangle rectFrom;
1721
1722 rectFrom = rvGEWindowWrapper::GetWrapper ( mSelections[i] )->GetScreenRect ( );
1723
1724 switch ( align )
1725 {
1726 case ALIGN_LEFTS:
1727 x = rectTo[0] - rectFrom[0];
1728 y = 0;
1729 break;
1730
1731 case ALIGN_RIGHTS:
1732 x = (rectTo[0]+rectTo[2]) - (rectFrom[0]+rectFrom[2]);
1733 y = 0;
1734 break;
1735
1736 case ALIGN_CENTERS:
1737 x = (rectTo[0]+rectTo[2]/2) - (rectFrom[0]+rectFrom[2]/2);
1738 y = 0;
1739 break;
1740
1741 case ALIGN_TOPS:
1742 y = rectTo[1] - rectFrom[1];
1743 x = 0;
1744 break;
1745
1746 case ALIGN_BOTTOMS:
1747 x = 0;
1748 y = (rectTo[1]+rectTo[3]) - (rectFrom[1]+rectFrom[3]);
1749 break;
1750
1751 case ALIGN_MIDDLES:
1752 x = 0;
1753 y = (rectTo[1]+rectTo[3]/2) - (rectFrom[1]+rectFrom[3]/2);
1754 break;
1755
1756 default:
1757 assert ( false );
1758 break;
1759 }
1760
1761 group->Append ( new rvGEMoveModifier ( modName, mSelections[i], x, y ) );
1762 }
1763
1764 mModifiers.Append ( group );
1765
1766 // Cant merge alignments
1767 mModifiers.BlockNextMerge ( );
1768
1769 SetModified ( true );
1770 }
1771
1772 /*
1773 ================
1774 rvGEWorkspace::AddModifierMove
1775
1776 Adds a move modifier with the given offsets
1777 ================
1778 */
AddModifierMove(const char * modName,float x,float y,bool snap)1779 void rvGEWorkspace::AddModifierMove ( const char* modName, float x, float y, bool snap )
1780 {
1781 idRectangle scaleRect;
1782 idRectangle newRect;
1783
1784 scaleRect = mSelections.GetRect ( );
1785 WindowToWorkspace ( scaleRect );
1786 newRect = scaleRect;
1787 newRect.x += x;
1788 newRect.y += y;
1789
1790 if ( snap )
1791 {
1792 gApp.GetOptions ().SnapRectToGrid ( newRect, true, true, false, false );
1793 }
1794
1795 rvGEModifierGroup* group = new rvGEModifierGroup;
1796 for ( int i = 0; i < mSelections.Num(); i ++ )
1797 {
1798 if ( !mSelections[i]->GetParent ( ) )
1799 {
1800 continue;
1801 }
1802
1803 // IF the parent window is being moved around as well then dont move this one.
1804 if ( rvGEWindowWrapper::GetWrapper ( mSelections[i]->GetParent ( ) )->IsSelected ( ) )
1805 {
1806 // We still need the modifier there so the selection can be restored and
1807 // so the rectangle gets updated
1808 group->Append ( new rvGEMoveModifier ( modName, mSelections[i], 0, 0 ) );
1809 continue;
1810 }
1811
1812 group->Append ( new rvGEMoveModifier ( modName, mSelections[i], newRect.x-scaleRect.x, newRect.y-scaleRect.y ) );
1813 }
1814
1815 mModifiers.Append ( group );
1816
1817 SetModified ( true );
1818 }
1819
1820 /*
1821 ================
1822 rvGEWorkspace::AddModifierSize
1823
1824 Adds a size modifier with the given offsets
1825 ================
1826 */
AddModifierSize(const char * modName,float l,float t,float r,float b,bool snap)1827 void rvGEWorkspace::AddModifierSize ( const char* modName, float l, float t, float r, float b, bool snap )
1828 {
1829 idRectangle scaleRect;
1830 idRectangle sizeRect;
1831 idRectangle newRect;
1832
1833 scaleRect = mSelections.GetRect ( );
1834 WindowToWorkspace ( scaleRect );
1835 newRect = scaleRect;
1836 newRect.x += l;
1837 newRect.y += t;
1838 newRect.w += (r - l);
1839 newRect.h += (b - t);
1840
1841 // Restrict sizing below 1 width
1842 if ( newRect.w <= 1 )
1843 {
1844 newRect.x = newRect.x - (l ? (1 - newRect.w) : 0);
1845 mDragPoint.x = newRect.x;
1846 newRect.w = 1;
1847 mDragX = false;
1848 }
1849 else
1850 {
1851 mDragX = true;
1852 }
1853
1854 // Restrict sizing below 1 height
1855 if ( newRect.h <= 1 )
1856 {
1857 newRect.y = newRect.y - (t ? (1 - newRect.h) : 0);
1858 mDragPoint.y = newRect.y;
1859 newRect.h = 1;
1860 mDragY = false;
1861 }
1862 else
1863 {
1864 mDragY = true;
1865 }
1866
1867 if ( snap )
1868 {
1869 gApp.GetOptions ().SnapRectToGrid ( newRect, l != 0.0f, t != 0.0f, r != 0.0f, b != 0.0f );
1870 }
1871
1872 rvGEModifierGroup* group = new rvGEModifierGroup;
1873 for ( int i = 0; i < mSelections.Num(); i ++ )
1874 {
1875 sizeRect = rvGEWindowWrapper::GetWrapper ( mSelections[i] )->GetScreenRect ( );
1876
1877 l = (newRect.x + ((sizeRect.x - scaleRect.x) / scaleRect.w) * newRect.w) - sizeRect.x;
1878 t = (newRect.y + ((sizeRect.y - scaleRect.y) / scaleRect.h) * newRect.h) - sizeRect.y;
1879 r = (sizeRect.w / scaleRect.w * newRect.w) - sizeRect.w + l;
1880 b = (sizeRect.h / scaleRect.h * newRect.h) - sizeRect.h + t;
1881
1882 // This is sorta crufty but needs to be done. When a parent is being sized at the same
1883 // time as a child you will get double movement because the child is relative to the parent. Therefore
1884 // we need to subtract out the closest parents sizing.
1885 idWindow* parent = mSelections[i];
1886 while ( NULL != (parent = parent->GetParent ( ) ) )
1887 {
1888 rvGEWindowWrapper* pwrapper = rvGEWindowWrapper::GetWrapper ( parent );
1889 float offset;
1890
1891 if ( !pwrapper->IsSelected ( ) )
1892 {
1893 continue;
1894 }
1895
1896 sizeRect = pwrapper->GetScreenRect ( );
1897
1898 // Subtract out the left and right modifications
1899 offset = ((newRect.x + ((sizeRect.x - scaleRect.x) / scaleRect.w) * newRect.w) - sizeRect.x);
1900 l -= offset;
1901 r -= offset;
1902
1903 // Subtract out the top and bottom modifications
1904 offset = ((newRect.y + ((sizeRect.y - scaleRect.y) / scaleRect.h) * newRect.h) - sizeRect.y);
1905 t -= offset;
1906 b -= offset;
1907
1908 break;
1909 }
1910
1911 group->Append ( new rvGESizeModifier ( modName, mSelections[i], l, t, r, b ) );
1912 }
1913
1914 mModifiers.Append ( group );
1915
1916 SetModified ( true );
1917 }
1918
1919 /*
1920 ================
1921 rvGEWorkspace::MakeSelectedAChild
1922
1923 Makes the selected windows a child of the first selected window
1924 ================
1925 */
MakeSelectedAChild(void)1926 void rvGEWorkspace::MakeSelectedAChild ( void )
1927 {
1928 rvGEModifierGroup* group;
1929 int i;
1930
1931 if ( !rvGEWindowWrapper::GetWrapper ( mSelections[0] )->CanHaveChildren ( ) )
1932 {
1933 gApp.MessageBox ( "Cannot add children to an htmlDef item", MB_OK|MB_ICONERROR );
1934 return;
1935 }
1936
1937 group = new rvGEModifierGroup;
1938
1939 for ( i = 1; i < mSelections.Num(); i ++ )
1940 {
1941 if ( mSelections[i]->GetParent ( ) == mSelections[0] )
1942 {
1943 continue;
1944 }
1945
1946 if ( !mSelections[i]->GetParent ( ) )
1947 {
1948 continue;
1949 }
1950
1951 group->Append ( new rvGEInsertModifier ( "Make Child", mSelections[i], mSelections[0], NULL ) );
1952 }
1953
1954 mModifiers.Append ( group );
1955
1956 // Navigator needs an update since the ordering has changed
1957 gApp.GetNavigator().Update ( );
1958
1959 SetModified ( true );
1960 }
1961
Copy(void)1962 void rvGEWorkspace::Copy ( void )
1963 {
1964 int i;
1965
1966 // Clear the current clipboard
1967 for ( i = 0; i < mClipboard.Num(); i ++ )
1968 {
1969 delete mClipboard[i];
1970 }
1971
1972 mClipboard.Clear ( );
1973
1974 for ( i = 0; i < mSelections.Num(); i ++ )
1975 {
1976 rvGEWindowWrapper* wrapper = rvGEWindowWrapper::GetWrapper ( mSelections[i] );
1977 assert ( wrapper );
1978
1979 rvGEClipboardItem* item = new rvGEClipboardItem;
1980 item->mStateDict = wrapper->GetStateDict ( );
1981 item->mScriptDict = wrapper->GetScriptDict ( );
1982 item->mVarDict = wrapper->GetVariableDict ( );
1983
1984 item->mStateDict.Set ( "windowType", rvGEWindowWrapper::WindowTypeToString ( wrapper->GetWindowType ( ) ) );
1985
1986 mClipboard.Append ( item );
1987 }
1988 }
1989
Paste(void)1990 void rvGEWorkspace::Paste ( void )
1991 {
1992 int i;
1993
1994 rvGEModifierGroup* group = new rvGEModifierGroup;
1995
1996 mSelections.Clear ( );
1997
1998 for ( i = 0; i < mClipboard.Num(); i ++ )
1999 {
2000 idDict state;
2001 rvGEWindowWrapper::EWindowType type;
2002
2003 state.Copy ( mClipboard[i]->mStateDict );
2004 type = rvGEWindowWrapper::StringToWindowType ( state.GetString ( "windowType", "windowDef" ) );
2005 state.Delete ( "windowType" );
2006
2007 idWindow* window = NewWindow ( &state, type );
2008 group->Append ( new rvGEInsertModifier ( "Paste", window, mInterface->GetDesktop(), NULL ) );
2009 mSelections.Add ( window );
2010
2011 rvGEWindowWrapper::GetWrapper ( window )->GetScriptDict ( ) = mClipboard[i]->mScriptDict;
2012 rvGEWindowWrapper::GetWrapper ( window )->GetVariableDict ( ) = mClipboard[i]->mVarDict;
2013 }
2014
2015 mModifiers.Append ( group );
2016
2017 mApplication->GetNavigator().Update ( );
2018
2019 SetModified ( true );
2020 }
2021
HideSelected(void)2022 void rvGEWorkspace::HideSelected ( void )
2023 {
2024 AddModifiers ( MOD_HIDE );
2025 mSelections.Clear ( );
2026 mApplication->GetNavigator().Refresh ( );
2027 }
2028
UnhideSelected(void)2029 void rvGEWorkspace::UnhideSelected ( void )
2030 {
2031 AddModifiers ( MOD_UNHIDE );
2032 mApplication->GetNavigator().Refresh ( );
2033 }
2034
HideWindow(idWindow * window)2035 void rvGEWorkspace::HideWindow ( idWindow* window )
2036 {
2037 AddModifiers ( window, MOD_HIDE );
2038 mApplication->GetNavigator().Refresh ( );
2039 }
2040
UnhideWindow(idWindow * window)2041 void rvGEWorkspace::UnhideWindow ( idWindow* window )
2042 {
2043 AddModifiers ( window, MOD_UNHIDE );
2044 mApplication->GetNavigator().Refresh ( );
2045 }
2046
2047 /*
2048 ================
2049 rvGEWorkspace::SetModified
2050
2051 Sets the modified state of the window and if source control is enabled it
2052 will attempt to check out the file
2053 ================
2054 */
SetModified(bool mod)2055 void rvGEWorkspace::SetModified ( bool mod )
2056 {
2057 if ( mModified != mod )
2058 {
2059
2060 mModified = mod;
2061 UpdateTitle ( );
2062
2063 }
2064 }
2065