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