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 "../../renderer/tr_local.h"
33 #include "../../sys/win32/win_local.h"
34
35 #include "GEApp.h"
36 #include "GESelectionMgr.h"
37
38 #define GUIED_GRABSIZE 7
39 #define GUIED_CENTERSIZE 5
40
rvGESelectionMgr()41 rvGESelectionMgr::rvGESelectionMgr ( )
42 {
43 mWorkspace = NULL;
44 }
45
46 /*
47 ================
48 rvGESelectionMgr::SetSelection
49
50 Sets the only selection for the workspace to the given window
51 ================
52 */
Set(idWindow * window)53 void rvGESelectionMgr::Set ( idWindow* window )
54 {
55 // Get rid of any current selections
56 Clear ( );
57
58 // Add this selection now
59 return Add ( window );
60 }
61
62 /*
63 ================
64 rvGESelectionMgr::Add
65
66 Adds the given window to the selection list
67 ================
68 */
Add(idWindow * window,bool expand)69 void rvGESelectionMgr::Add ( idWindow* window, bool expand )
70 {
71 rvGEWindowWrapper* wrapper;
72
73 wrapper = rvGEWindowWrapper::GetWrapper ( window );
74 assert ( wrapper );
75
76 // If the window is already selected then dont add the selection
77 if ( wrapper->IsSelected ( ) )
78 {
79 return;
80 }
81
82 wrapper->SetSelected ( true );
83
84 mSelections.Append ( window );
85
86 if ( expand && wrapper->Expand ( ) )
87 {
88 gApp.GetNavigator ( ).Update ( );
89 }
90
91 gApp.GetNavigator ( ).UpdateSelections ( );
92 gApp.GetNavigator ( ).Refresh ( );
93 gApp.GetTransformer ( ).Update ( );
94 gApp.GetProperties().Update ( );
95
96 UpdateExpression ( );
97 }
98
99 /*
100 ================
101 rvGESelectionMgr::RemoveSelection
102
103 Removes the selection from the current workspace
104 ================
105 */
Remove(idWindow * window)106 void rvGESelectionMgr::Remove ( idWindow* window )
107 {
108 rvGEWindowWrapper* wrapper;
109
110 wrapper = rvGEWindowWrapper::GetWrapper ( window );
111 assert ( wrapper );
112
113 // Dont bother if the window isnt selectd already
114 if ( !wrapper->IsSelected ( ) )
115 {
116 return;
117 }
118
119 wrapper->SetSelected ( false );
120
121 mSelections.Remove ( window );
122
123 gApp.GetNavigator ( ).UpdateSelections ( );
124 gApp.GetNavigator ( ).Refresh ( );
125 gApp.GetTransformer ( ).Update ( );
126 gApp.GetProperties().Update ( );
127
128 UpdateExpression ( );
129 }
130
131 /*
132 ================
133 rvGESelectionMgr::ClearSelections
134
135 Remove all of the current selections
136 ================
137 */
Clear(void)138 void rvGESelectionMgr::Clear ( void )
139 {
140 int i;
141
142 for ( i = 0; i < mSelections.Num ( ); i ++ )
143 {
144 rvGEWindowWrapper::GetWrapper ( mSelections[i] )->SetSelected ( false );
145 }
146
147 mSelections.Clear ( );
148
149 gApp.GetNavigator ( ).UpdateSelections ( );
150 gApp.GetNavigator ( ).Refresh ( );
151 gApp.GetTransformer ( ).Update ( );
152 gApp.GetProperties().Update ( );
153
154 mExpression = false;
155 }
156
157 /*
158 ================
159 rvGESelectionMgr::Render
160
161 Render the selections including the move/size bars
162 ================
163 */
Render(void)164 void rvGESelectionMgr::Render ( void )
165 {
166 if ( !mSelections.Num ( ) )
167 {
168 return;
169 }
170
171 qglEnable(GL_BLEND);
172 qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
173
174 UpdateRectangle ( );
175
176 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE );
177
178 idVec4& color = gApp.GetOptions().GetSelectionColor ( );
179 qglColor4f ( color[0],color[1],color[2], 1.0f );
180
181 qglBegin(GL_LINE_LOOP );
182 qglVertex2f ( mRect.x, mRect.y );
183 qglVertex2f ( mRect.x + mRect.w, mRect.y );
184 qglVertex2f ( mRect.x + mRect.w, mRect.y + mRect.h);
185 qglVertex2f ( mRect.x, mRect.y + mRect.h);
186 qglEnd ( );
187
188 qglColor4f ( color[0],color[1],color[2], 0.75f );
189
190 int i;
191 for ( i = 0; i < mSelections.Num(); i ++ )
192 {
193 rvGEWindowWrapper* wrapper;
194 idRectangle rect;
195
196 wrapper = rvGEWindowWrapper::GetWrapper ( mSelections[i] );
197 assert ( wrapper );
198
199 rect = wrapper->GetScreenRect ( );
200 mWorkspace->WorkspaceToWindow ( rect );
201
202 if ( i == 0 )
203 {
204 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL );
205 qglBegin ( GL_TRIANGLES );
206 qglVertex2f ( rect.x, rect.y );
207 qglVertex2f ( rect.x + GUIED_GRABSIZE, rect.y );
208 qglVertex2f ( rect.x, rect.y + GUIED_GRABSIZE );
209 qglEnd ( );
210 }
211
212 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE );
213 qglBegin(GL_LINE_LOOP );
214 qglVertex2f ( rect.x, rect.y );
215 qglVertex2f ( rect.x + rect.w, rect.y );
216 qglVertex2f ( rect.x + rect.w, rect.y + rect.h);
217 qglVertex2f ( rect.x, rect.y + rect.h);
218 qglEnd ( );
219
220 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL );
221 qglBegin( GL_QUADS );
222 qglVertex2f ( rect.x + (rect.w - GUIED_CENTERSIZE) / 2, rect.y + (rect.h - GUIED_CENTERSIZE) / 2 );
223 qglVertex2f ( rect.x + (rect.w + GUIED_CENTERSIZE) / 2, rect.y + (rect.h - GUIED_CENTERSIZE) / 2 );
224 qglVertex2f ( rect.x + (rect.w + GUIED_CENTERSIZE) / 2, rect.y + (rect.h + GUIED_CENTERSIZE) / 2 );
225 qglVertex2f ( rect.x + (rect.w - GUIED_CENTERSIZE) / 2, rect.y + (rect.h + GUIED_CENTERSIZE) / 2 );
226 qglEnd ( );
227 }
228
229 if ( mExpression )
230 {
231 return;
232 }
233
234 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE );
235
236 qglColor4f ( color[0],color[1],color[2], 1.0f );
237 qglBegin(GL_QUADS);
238
239 // Top Left
240 qglVertex2f ( mRect.x - GUIED_GRABSIZE, mRect.y - GUIED_GRABSIZE );
241 qglVertex2f ( mRect.x - 1, mRect.y - GUIED_GRABSIZE );
242 qglVertex2f ( mRect.x - 1, mRect.y - 1 );
243 qglVertex2f ( mRect.x - GUIED_GRABSIZE, mRect.y - 1 );
244
245 // Left
246 qglVertex2f ( mRect.x - GUIED_GRABSIZE, mRect.y + mRect.h / 2 - GUIED_GRABSIZE / 2);
247 qglVertex2f ( mRect.x - 1, mRect.y + mRect.h / 2 - GUIED_GRABSIZE / 2 );
248 qglVertex2f ( mRect.x - 1, mRect.y + mRect.h / 2 + GUIED_GRABSIZE / 2 );
249 qglVertex2f ( mRect.x - GUIED_GRABSIZE, mRect.y + mRect.h / 2 + GUIED_GRABSIZE / 2 );
250
251 // Bototm Left
252 qglVertex2f ( mRect.x - GUIED_GRABSIZE, mRect.y + mRect.h + 1 );
253 qglVertex2f ( mRect.x - 1, mRect.y + mRect.h + 1 );
254 qglVertex2f ( mRect.x - 1, mRect.y + mRect.h + GUIED_GRABSIZE );
255 qglVertex2f ( mRect.x - GUIED_GRABSIZE, mRect.y + mRect.h + GUIED_GRABSIZE );
256
257 // Bottom
258 qglVertex2f ( mRect.x - GUIED_GRABSIZE / 2 + mRect.w / 2, mRect.y + mRect.h + 1 );
259 qglVertex2f ( mRect.x + GUIED_GRABSIZE / 2 + mRect.w / 2, mRect.y + mRect.h + 1 );
260 qglVertex2f ( mRect.x + GUIED_GRABSIZE / 2 + mRect.w / 2, mRect.y + mRect.h + GUIED_GRABSIZE );
261 qglVertex2f ( mRect.x - GUIED_GRABSIZE / 2 + mRect.w / 2, mRect.y + mRect.h + GUIED_GRABSIZE );
262
263 // Bottom Right
264 qglVertex2f ( mRect.x + mRect.w + 1, mRect.y + mRect.h + 1 );
265 qglVertex2f ( mRect.x + mRect.w + GUIED_GRABSIZE, mRect.y + mRect.h + 1 );
266 qglVertex2f ( mRect.x + mRect.w + GUIED_GRABSIZE, mRect.y + mRect.h + GUIED_GRABSIZE );
267 qglVertex2f ( mRect.x + mRect.w + 1, mRect.y + mRect.h + GUIED_GRABSIZE );
268
269 // Right
270 qglVertex2f ( mRect.x + mRect.w + 1, mRect.y + mRect.h / 2 - GUIED_GRABSIZE / 2);
271 qglVertex2f ( mRect.x + mRect.w + GUIED_GRABSIZE, mRect.y + mRect.h / 2 - GUIED_GRABSIZE / 2 );
272 qglVertex2f ( mRect.x + mRect.w + GUIED_GRABSIZE, mRect.y + mRect.h / 2 + GUIED_GRABSIZE / 2 );
273 qglVertex2f ( mRect.x + mRect.w + 1, mRect.y + mRect.h / 2 + GUIED_GRABSIZE / 2 );
274
275 // Top Right
276 qglVertex2f ( mRect.x + mRect.w + 1, mRect.y - GUIED_GRABSIZE );
277 qglVertex2f ( mRect.x + mRect.w + GUIED_GRABSIZE, mRect.y - GUIED_GRABSIZE );
278 qglVertex2f ( mRect.x + mRect.w + GUIED_GRABSIZE, mRect.y - 1 );
279 qglVertex2f ( mRect.x + mRect.w + 1, mRect.y - 1 );
280
281 // Top
282 qglVertex2f ( mRect.x - GUIED_GRABSIZE / 2 + mRect.w / 2, mRect.y - GUIED_GRABSIZE );
283 qglVertex2f ( mRect.x + GUIED_GRABSIZE / 2 + mRect.w / 2, mRect.y - GUIED_GRABSIZE );
284 qglVertex2f ( mRect.x + GUIED_GRABSIZE / 2 + mRect.w / 2, mRect.y - 1 );
285 qglVertex2f ( mRect.x - GUIED_GRABSIZE / 2 + mRect.w / 2, mRect.y - 1 );
286
287 qglEnd ( );
288
289 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL );
290 }
291
292 /*
293 ================
294 rvGESelectionMgr::UpdateRectangle
295
296 Update the selection rectangle from all the currently selected items.
297 ================
298 */
UpdateRectangle(void)299 void rvGESelectionMgr::UpdateRectangle ( void )
300 {
301 int i;
302 idVec2 point;
303
304 assert ( mWorkspace );
305
306 if ( mSelections.Num ( ) <= 0 )
307 {
308 return;
309 }
310
311 // Start with the first selections retangle
312 mRect = rvGEWindowWrapper::GetWrapper( mSelections[0] )->GetScreenRect ( );
313
314 // Its easier to do the calculates with it being top left and bottom right
315 // so temporarly convert width and height to right and bottom
316 mRect.w += mRect.x;
317 mRect.h += mRect.y;
318
319 // Merge all the rest of the rectangles to make the actual selection rectangle
320 for ( i = 1; i < mSelections.Num(); i ++ )
321 {
322 idRectangle selRect;
323 selRect = rvGEWindowWrapper::GetWrapper ( mSelections[i] )->GetScreenRect ( );
324
325 mRect.w = max(selRect.x+selRect.w,mRect.w);
326 mRect.h = max(selRect.y+selRect.h,mRect.h);
327 mRect.x = min(selRect.x,mRect.x);
328 mRect.y = min(selRect.y,mRect.y);
329 }
330
331 mRect.w -= mRect.x;
332 mRect.h -= mRect.y;
333
334 mWorkspace->WorkspaceToWindow ( mRect );
335 }
336
337 /*
338 ================
339 rvGESelectionMgr::UpdateExpression
340
341 Update whether or not the selection has an expression in it
342 ================
343 */
UpdateExpression(void)344 void rvGESelectionMgr::UpdateExpression ( void )
345 {
346 int i;
347
348 mExpression = false;
349 for ( i = 0; i < mSelections.Num(); i ++ )
350 {
351 rvGEWindowWrapper* wrapper;
352 wrapper = rvGEWindowWrapper::GetWrapper ( mSelections[i] );
353 if ( wrapper && !wrapper->CanMoveAndSize ( ) )
354 {
355 mExpression = true;
356 break;
357 }
358 }
359 }
360
361 /*
362 ================
363 rvGESelectionMgr::HitTest
364
365 Test to see if the given coordinate is within the selection rectangle and if it is
366 see what its over.
367 ================
368 */
HitTest(float x,float y)369 rvGESelectionMgr::EHitTest rvGESelectionMgr::HitTest ( float x, float y )
370 {
371 if ( !mSelections.Num ( ) )
372 {
373 return HT_NONE;
374 }
375
376 UpdateRectangle ( );
377
378 // Inside the rectangle is moving
379 if ( mRect.Contains ( x, y ) )
380 {
381 return mExpression?HT_SELECT:HT_MOVE;
382 }
383
384 if ( mExpression )
385 {
386 return HT_NONE;
387 }
388
389 // Check for top left sizing
390 if ( idRectangle ( mRect.x - GUIED_GRABSIZE, mRect.y - GUIED_GRABSIZE, GUIED_GRABSIZE, GUIED_GRABSIZE ).Contains ( x, y ) )
391 {
392 return HT_SIZE_TOPLEFT;
393 }
394
395 // Check for left sizing
396 if ( idRectangle ( mRect.x - GUIED_GRABSIZE, mRect.y + mRect.h / 2 - GUIED_GRABSIZE / 2, GUIED_GRABSIZE, GUIED_GRABSIZE ).Contains ( x, y ) )
397 {
398 return HT_SIZE_LEFT;
399 }
400
401 // Check for bottom left sizing
402 if ( idRectangle ( mRect.x - GUIED_GRABSIZE, mRect.y + mRect.h, GUIED_GRABSIZE, GUIED_GRABSIZE ).Contains ( x, y ) )
403 {
404 return HT_SIZE_BOTTOMLEFT;
405 }
406
407 // Check for bottom sizing
408 if ( idRectangle ( mRect.x + mRect.w / 2 - GUIED_GRABSIZE / 2, mRect.y + mRect.h, GUIED_GRABSIZE, GUIED_GRABSIZE ).Contains ( x, y ) )
409 {
410 return HT_SIZE_BOTTOM;
411 }
412
413 // Check for bottom right sizing
414 if ( idRectangle ( mRect.x + mRect.w, mRect.y + mRect.h, GUIED_GRABSIZE, GUIED_GRABSIZE ).Contains ( x, y ) )
415 {
416 return HT_SIZE_BOTTOMRIGHT;
417 }
418
419 // Check for right sizing
420 if ( idRectangle ( mRect.x + mRect.w, mRect.y + mRect.h / 2 - GUIED_GRABSIZE / 2, GUIED_GRABSIZE, GUIED_GRABSIZE ).Contains ( x, y ) )
421 {
422 return HT_SIZE_RIGHT;
423 }
424
425 // Check for top right sizing
426 if ( idRectangle ( mRect.x + mRect.w, mRect.y - GUIED_GRABSIZE, GUIED_GRABSIZE, GUIED_GRABSIZE ).Contains ( x, y ) )
427 {
428 return HT_SIZE_TOPRIGHT;
429 }
430
431 // Check for top sizing
432 if ( idRectangle ( mRect.x + mRect.w / 2 - GUIED_GRABSIZE / 2, mRect.y - GUIED_GRABSIZE, GUIED_GRABSIZE, GUIED_GRABSIZE ).Contains ( x, y ) )
433 {
434 return HT_SIZE_TOP;
435 }
436
437 return HT_NONE;
438 }
439
440 /*
441 ================
442 rvGESelectionMgr::GetBottomMost
443
444 Returns the bottom most selected window.
445 ================
446 */
GetBottomMost(void)447 idWindow* rvGESelectionMgr::GetBottomMost ( void )
448 {
449 idWindow* bottom;
450 int depth;
451 int i;
452
453 depth = 9999;
454 bottom = NULL;
455
456 // Loop through all the selections and find the bottom most window
457 for ( i = 0; i < mSelections.Num(); i ++ )
458 {
459 idWindow* parent;
460 int tempDepth;
461
462 // Calculate the depth of the window by iterating back through the windows parents
463 for ( tempDepth = 0, parent = mSelections[i]; parent; parent = parent->GetParent ( ), tempDepth++ );
464
465 // If the new depth is less than the current depth then this window is below
466 if ( tempDepth < depth )
467 {
468 depth = tempDepth;
469 bottom = mSelections[i];
470 }
471 }
472
473 return bottom;
474 }
475