/* =========================================================================== Doom 3 GPL Source Code Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). Doom 3 Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Doom 3 Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Doom 3 Source Code. If not, see . 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. 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. =========================================================================== */ #include "tools/edit_gui_common.h" #include "../../renderer/tr_local.h" #include "../../sys/win32/win_local.h" #include "GEApp.h" #include "GESelectionMgr.h" #define GUIED_GRABSIZE 7 #define GUIED_CENTERSIZE 5 rvGESelectionMgr::rvGESelectionMgr ( ) { mWorkspace = NULL; } /* ================ rvGESelectionMgr::SetSelection Sets the only selection for the workspace to the given window ================ */ void rvGESelectionMgr::Set ( idWindow* window ) { // Get rid of any current selections Clear ( ); // Add this selection now return Add ( window ); } /* ================ rvGESelectionMgr::Add Adds the given window to the selection list ================ */ void rvGESelectionMgr::Add ( idWindow* window, bool expand ) { rvGEWindowWrapper* wrapper; wrapper = rvGEWindowWrapper::GetWrapper ( window ); assert ( wrapper ); // If the window is already selected then dont add the selection if ( wrapper->IsSelected ( ) ) { return; } wrapper->SetSelected ( true ); mSelections.Append ( window ); if ( expand && wrapper->Expand ( ) ) { gApp.GetNavigator ( ).Update ( ); } gApp.GetNavigator ( ).UpdateSelections ( ); gApp.GetNavigator ( ).Refresh ( ); gApp.GetTransformer ( ).Update ( ); gApp.GetProperties().Update ( ); UpdateExpression ( ); } /* ================ rvGESelectionMgr::RemoveSelection Removes the selection from the current workspace ================ */ void rvGESelectionMgr::Remove ( idWindow* window ) { rvGEWindowWrapper* wrapper; wrapper = rvGEWindowWrapper::GetWrapper ( window ); assert ( wrapper ); // Dont bother if the window isnt selectd already if ( !wrapper->IsSelected ( ) ) { return; } wrapper->SetSelected ( false ); mSelections.Remove ( window ); gApp.GetNavigator ( ).UpdateSelections ( ); gApp.GetNavigator ( ).Refresh ( ); gApp.GetTransformer ( ).Update ( ); gApp.GetProperties().Update ( ); UpdateExpression ( ); } /* ================ rvGESelectionMgr::ClearSelections Remove all of the current selections ================ */ void rvGESelectionMgr::Clear ( void ) { int i; for ( i = 0; i < mSelections.Num ( ); i ++ ) { rvGEWindowWrapper::GetWrapper ( mSelections[i] )->SetSelected ( false ); } mSelections.Clear ( ); gApp.GetNavigator ( ).UpdateSelections ( ); gApp.GetNavigator ( ).Refresh ( ); gApp.GetTransformer ( ).Update ( ); gApp.GetProperties().Update ( ); mExpression = false; } /* ================ rvGESelectionMgr::Render Render the selections including the move/size bars ================ */ void rvGESelectionMgr::Render ( void ) { if ( !mSelections.Num ( ) ) { return; } qglEnable(GL_BLEND); qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); UpdateRectangle ( ); qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE ); idVec4& color = gApp.GetOptions().GetSelectionColor ( ); qglColor4f ( color[0],color[1],color[2], 1.0f ); qglBegin(GL_LINE_LOOP ); qglVertex2f ( mRect.x, mRect.y ); qglVertex2f ( mRect.x + mRect.w, mRect.y ); qglVertex2f ( mRect.x + mRect.w, mRect.y + mRect.h); qglVertex2f ( mRect.x, mRect.y + mRect.h); qglEnd ( ); qglColor4f ( color[0],color[1],color[2], 0.75f ); int i; for ( i = 0; i < mSelections.Num(); i ++ ) { rvGEWindowWrapper* wrapper; idRectangle rect; wrapper = rvGEWindowWrapper::GetWrapper ( mSelections[i] ); assert ( wrapper ); rect = wrapper->GetScreenRect ( ); mWorkspace->WorkspaceToWindow ( rect ); if ( i == 0 ) { qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL ); qglBegin ( GL_TRIANGLES ); qglVertex2f ( rect.x, rect.y ); qglVertex2f ( rect.x + GUIED_GRABSIZE, rect.y ); qglVertex2f ( rect.x, rect.y + GUIED_GRABSIZE ); qglEnd ( ); } qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE ); qglBegin(GL_LINE_LOOP ); qglVertex2f ( rect.x, rect.y ); qglVertex2f ( rect.x + rect.w, rect.y ); qglVertex2f ( rect.x + rect.w, rect.y + rect.h); qglVertex2f ( rect.x, rect.y + rect.h); qglEnd ( ); qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL ); qglBegin( GL_QUADS ); qglVertex2f ( rect.x + (rect.w - GUIED_CENTERSIZE) / 2, rect.y + (rect.h - GUIED_CENTERSIZE) / 2 ); qglVertex2f ( rect.x + (rect.w + GUIED_CENTERSIZE) / 2, rect.y + (rect.h - GUIED_CENTERSIZE) / 2 ); qglVertex2f ( rect.x + (rect.w + GUIED_CENTERSIZE) / 2, rect.y + (rect.h + GUIED_CENTERSIZE) / 2 ); qglVertex2f ( rect.x + (rect.w - GUIED_CENTERSIZE) / 2, rect.y + (rect.h + GUIED_CENTERSIZE) / 2 ); qglEnd ( ); } if ( mExpression ) { return; } qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE ); qglColor4f ( color[0],color[1],color[2], 1.0f ); qglBegin(GL_QUADS); // Top Left qglVertex2f ( mRect.x - GUIED_GRABSIZE, mRect.y - GUIED_GRABSIZE ); qglVertex2f ( mRect.x - 1, mRect.y - GUIED_GRABSIZE ); qglVertex2f ( mRect.x - 1, mRect.y - 1 ); qglVertex2f ( mRect.x - GUIED_GRABSIZE, mRect.y - 1 ); // Left qglVertex2f ( mRect.x - GUIED_GRABSIZE, mRect.y + mRect.h / 2 - GUIED_GRABSIZE / 2); qglVertex2f ( mRect.x - 1, mRect.y + mRect.h / 2 - GUIED_GRABSIZE / 2 ); qglVertex2f ( mRect.x - 1, mRect.y + mRect.h / 2 + GUIED_GRABSIZE / 2 ); qglVertex2f ( mRect.x - GUIED_GRABSIZE, mRect.y + mRect.h / 2 + GUIED_GRABSIZE / 2 ); // Bototm Left qglVertex2f ( mRect.x - GUIED_GRABSIZE, mRect.y + mRect.h + 1 ); qglVertex2f ( mRect.x - 1, mRect.y + mRect.h + 1 ); qglVertex2f ( mRect.x - 1, mRect.y + mRect.h + GUIED_GRABSIZE ); qglVertex2f ( mRect.x - GUIED_GRABSIZE, mRect.y + mRect.h + GUIED_GRABSIZE ); // Bottom qglVertex2f ( mRect.x - GUIED_GRABSIZE / 2 + mRect.w / 2, mRect.y + mRect.h + 1 ); qglVertex2f ( mRect.x + GUIED_GRABSIZE / 2 + mRect.w / 2, mRect.y + mRect.h + 1 ); qglVertex2f ( mRect.x + GUIED_GRABSIZE / 2 + mRect.w / 2, mRect.y + mRect.h + GUIED_GRABSIZE ); qglVertex2f ( mRect.x - GUIED_GRABSIZE / 2 + mRect.w / 2, mRect.y + mRect.h + GUIED_GRABSIZE ); // Bottom Right qglVertex2f ( mRect.x + mRect.w + 1, mRect.y + mRect.h + 1 ); qglVertex2f ( mRect.x + mRect.w + GUIED_GRABSIZE, mRect.y + mRect.h + 1 ); qglVertex2f ( mRect.x + mRect.w + GUIED_GRABSIZE, mRect.y + mRect.h + GUIED_GRABSIZE ); qglVertex2f ( mRect.x + mRect.w + 1, mRect.y + mRect.h + GUIED_GRABSIZE ); // Right qglVertex2f ( mRect.x + mRect.w + 1, mRect.y + mRect.h / 2 - GUIED_GRABSIZE / 2); qglVertex2f ( mRect.x + mRect.w + GUIED_GRABSIZE, mRect.y + mRect.h / 2 - GUIED_GRABSIZE / 2 ); qglVertex2f ( mRect.x + mRect.w + GUIED_GRABSIZE, mRect.y + mRect.h / 2 + GUIED_GRABSIZE / 2 ); qglVertex2f ( mRect.x + mRect.w + 1, mRect.y + mRect.h / 2 + GUIED_GRABSIZE / 2 ); // Top Right qglVertex2f ( mRect.x + mRect.w + 1, mRect.y - GUIED_GRABSIZE ); qglVertex2f ( mRect.x + mRect.w + GUIED_GRABSIZE, mRect.y - GUIED_GRABSIZE ); qglVertex2f ( mRect.x + mRect.w + GUIED_GRABSIZE, mRect.y - 1 ); qglVertex2f ( mRect.x + mRect.w + 1, mRect.y - 1 ); // Top qglVertex2f ( mRect.x - GUIED_GRABSIZE / 2 + mRect.w / 2, mRect.y - GUIED_GRABSIZE ); qglVertex2f ( mRect.x + GUIED_GRABSIZE / 2 + mRect.w / 2, mRect.y - GUIED_GRABSIZE ); qglVertex2f ( mRect.x + GUIED_GRABSIZE / 2 + mRect.w / 2, mRect.y - 1 ); qglVertex2f ( mRect.x - GUIED_GRABSIZE / 2 + mRect.w / 2, mRect.y - 1 ); qglEnd ( ); qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL ); } /* ================ rvGESelectionMgr::UpdateRectangle Update the selection rectangle from all the currently selected items. ================ */ void rvGESelectionMgr::UpdateRectangle ( void ) { int i; idVec2 point; assert ( mWorkspace ); if ( mSelections.Num ( ) <= 0 ) { return; } // Start with the first selections retangle mRect = rvGEWindowWrapper::GetWrapper( mSelections[0] )->GetScreenRect ( ); // Its easier to do the calculates with it being top left and bottom right // so temporarly convert width and height to right and bottom mRect.w += mRect.x; mRect.h += mRect.y; // Merge all the rest of the rectangles to make the actual selection rectangle for ( i = 1; i < mSelections.Num(); i ++ ) { idRectangle selRect; selRect = rvGEWindowWrapper::GetWrapper ( mSelections[i] )->GetScreenRect ( ); mRect.w = max(selRect.x+selRect.w,mRect.w); mRect.h = max(selRect.y+selRect.h,mRect.h); mRect.x = min(selRect.x,mRect.x); mRect.y = min(selRect.y,mRect.y); } mRect.w -= mRect.x; mRect.h -= mRect.y; mWorkspace->WorkspaceToWindow ( mRect ); } /* ================ rvGESelectionMgr::UpdateExpression Update whether or not the selection has an expression in it ================ */ void rvGESelectionMgr::UpdateExpression ( void ) { int i; mExpression = false; for ( i = 0; i < mSelections.Num(); i ++ ) { rvGEWindowWrapper* wrapper; wrapper = rvGEWindowWrapper::GetWrapper ( mSelections[i] ); if ( wrapper && !wrapper->CanMoveAndSize ( ) ) { mExpression = true; break; } } } /* ================ rvGESelectionMgr::HitTest Test to see if the given coordinate is within the selection rectangle and if it is see what its over. ================ */ rvGESelectionMgr::EHitTest rvGESelectionMgr::HitTest ( float x, float y ) { if ( !mSelections.Num ( ) ) { return HT_NONE; } UpdateRectangle ( ); // Inside the rectangle is moving if ( mRect.Contains ( x, y ) ) { return mExpression?HT_SELECT:HT_MOVE; } if ( mExpression ) { return HT_NONE; } // Check for top left sizing if ( idRectangle ( mRect.x - GUIED_GRABSIZE, mRect.y - GUIED_GRABSIZE, GUIED_GRABSIZE, GUIED_GRABSIZE ).Contains ( x, y ) ) { return HT_SIZE_TOPLEFT; } // Check for left sizing if ( idRectangle ( mRect.x - GUIED_GRABSIZE, mRect.y + mRect.h / 2 - GUIED_GRABSIZE / 2, GUIED_GRABSIZE, GUIED_GRABSIZE ).Contains ( x, y ) ) { return HT_SIZE_LEFT; } // Check for bottom left sizing if ( idRectangle ( mRect.x - GUIED_GRABSIZE, mRect.y + mRect.h, GUIED_GRABSIZE, GUIED_GRABSIZE ).Contains ( x, y ) ) { return HT_SIZE_BOTTOMLEFT; } // Check for bottom sizing if ( idRectangle ( mRect.x + mRect.w / 2 - GUIED_GRABSIZE / 2, mRect.y + mRect.h, GUIED_GRABSIZE, GUIED_GRABSIZE ).Contains ( x, y ) ) { return HT_SIZE_BOTTOM; } // Check for bottom right sizing if ( idRectangle ( mRect.x + mRect.w, mRect.y + mRect.h, GUIED_GRABSIZE, GUIED_GRABSIZE ).Contains ( x, y ) ) { return HT_SIZE_BOTTOMRIGHT; } // Check for right sizing if ( idRectangle ( mRect.x + mRect.w, mRect.y + mRect.h / 2 - GUIED_GRABSIZE / 2, GUIED_GRABSIZE, GUIED_GRABSIZE ).Contains ( x, y ) ) { return HT_SIZE_RIGHT; } // Check for top right sizing if ( idRectangle ( mRect.x + mRect.w, mRect.y - GUIED_GRABSIZE, GUIED_GRABSIZE, GUIED_GRABSIZE ).Contains ( x, y ) ) { return HT_SIZE_TOPRIGHT; } // Check for top sizing if ( idRectangle ( mRect.x + mRect.w / 2 - GUIED_GRABSIZE / 2, mRect.y - GUIED_GRABSIZE, GUIED_GRABSIZE, GUIED_GRABSIZE ).Contains ( x, y ) ) { return HT_SIZE_TOP; } return HT_NONE; } /* ================ rvGESelectionMgr::GetBottomMost Returns the bottom most selected window. ================ */ idWindow* rvGESelectionMgr::GetBottomMost ( void ) { idWindow* bottom; int depth; int i; depth = 9999; bottom = NULL; // Loop through all the selections and find the bottom most window for ( i = 0; i < mSelections.Num(); i ++ ) { idWindow* parent; int tempDepth; // Calculate the depth of the window by iterating back through the windows parents for ( tempDepth = 0, parent = mSelections[i]; parent; parent = parent->GetParent ( ), tempDepth++ ); // If the new depth is less than the current depth then this window is below if ( tempDepth < depth ) { depth = tempDepth; bottom = mSelections[i]; } } return bottom; }