dhewm3/neo/tools/guied/GEWorkspace.cpp
Daniel Gibson b054261a0e Make MFC Tools work with MSAA enabled
The problem was that the editors called ChoosePixelFormat() instead of
wglChoosePixelFormatARB() - and the normal ChoosePixelFormat() has no
attribute for MSAA, so if MSAA is enabled (by SDL2 which calls the wgl
variant), ChoosePixelFormat() will return an incomaptible format and
the editors don't get a working OpenGL context.
So I wrote a wrapper around ChoosePixelFormat() that calls the wgl variant
if available, and all the necessary plumbing around that.

While at it, removed the unused qwgl*PixelFormat function pointers and
supressed the "inconsistent dll linkage" warnings for the gl stubs
2021-05-11 00:39:00 +02:00

2064 lines
47 KiB
C++

/*
===========================================================================
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 <http://www.gnu.org/licenses/>.
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 "../../sys/win32/rc/guied_resource.h"
#include "../../renderer/tr_local.h"
#include "../../sys/win32/win_local.h"
#include "../../ui/DeviceContext.h"
#include "../../ui/EditWindow.h"
#include "../../ui/ListWindow.h"
#include "../../ui/BindWindow.h"
#include "../../ui/RenderWindow.h"
#include "../../ui/ChoiceWindow.h"
#include "GEApp.h"
#include "GEItemPropsDlg.h"
#include "GEItemScriptsDlg.h"
// Modifiers
#include "GEModifierGroup.h"
#include "GEMoveModifier.h"
#include "GESizeModifier.h"
#include "GEStateModifier.h"
#include "GEZOrderModifier.h"
#include "GEInsertModifier.h"
#include "GEHideModifier.h"
#include "GEDeleteModifier.h"
static float g_ZoomScales[rvGEWorkspace::ZOOM_MAX] = { 0, 0.25f, 0.33f, 0.50f, 0.66f, 1.0f, 1.5f, 2.0f, 3.0f };
static const int ID_GUIED_SELECT_FIRST = 9800;
static const int ID_GUIED_SELECT_LAST = 9900;
idList<rvGEClipboardItem*> rvGEWorkspace::mClipboard;
rvGEWorkspace::rvGEWorkspace ( rvGEApp* app ) : mApplication ( app )
{
mWnd = 0;
mInterface = 0;
mZoom = ZOOM_100;
mScrollHorz = false;
mScrollVert = false;
mModified = false;
mNew = false;
mDragScroll = false;
mSourceControlState = SCS_CHECKEDOUT;
mFilename = "guis/Untitled.gui";
mDragType = rvGESelectionMgr::HT_NONE;
mHandCursor = LoadCursor ( app->GetInstance(), MAKEINTRESOURCE(IDC_GUIED_HAND) );
mDontAdd = false;
mSelections.SetWorkspace ( this );
}
rvGEWorkspace::~rvGEWorkspace ( )
{
// Make sure all the wrappers get cleaned up
rvGEWindowWrapper::GetWrapper ( mInterface->GetDesktop ( ) )->EnumChildren ( CleanupEnumProc, NULL );
DestroyCursor ( mHandCursor );
delete mInterface;
}
/*
================
rvGEWorkspace::CleanupEnumProc
Window enumeration procedure that deletes all the wrapper classes
================
*/
bool rvGEWorkspace::CleanupEnumProc ( rvGEWindowWrapper* wrapper, void* data )
{
bool result;
if ( !wrapper )
{
return true;
}
result = wrapper->EnumChildren ( CleanupEnumProc, data );
// Cleanup the window wrapper
delete wrapper;
return result;
}
/*
================
rvGEWorkspace::GetZoomScale
Returns the scale of the current zoom level
================
*/
float rvGEWorkspace::GetZoomScale ( void )
{
return g_ZoomScales [ mZoom ];
}
/*
================
rvGEWorkspace::Attach
Attaches the workspace to the given window. This is usually done after the
window is created and the file has been loaded.
================
*/
bool rvGEWorkspace::Attach ( HWND wnd )
{
assert ( wnd );
mWnd = wnd;
// Initialize the pixel format for this window
SetupPixelFormat ( );
// Jam the workspace pointer into the userdata window long so
// we can retrieve the workspace from the window later
SetWindowLongPtr( mWnd, GWLP_USERDATA, ( LONG_PTR ) this );
UpdateTitle ( );
return true;
}
/*
================
rvGEWorkspace::Detach
Detaches the workspace from the window it is currently attached to
================
*/
void rvGEWorkspace::Detach ( void )
{
assert ( mWnd );
SetWindowLongPtr ( mWnd, GWLP_USERDATA, 0 );
mWnd = NULL;
}
/*
================
rvGEWorkspace::SetupPixelFormat
Setup the pixel format for the opengl context
================
*/
bool rvGEWorkspace::SetupPixelFormat ( void )
{
HDC hDC = GetDC ( mWnd );
bool result = true;
int pixelFormat = Win_ChoosePixelFormat(hDC);
if (pixelFormat > 0)
{
if (SetPixelFormat(hDC, pixelFormat, &win32.pfd) == NULL)
{
result = false;
}
}
else
{
result = false;
}
ReleaseDC ( mWnd, hDC );
return result;
}
/*
================
rvGEWorkspace::RenderGrid
Renders the grid on top of the user interface
================
*/
void rvGEWorkspace::RenderGrid ( void )
{
float x;
float y;
float step;
idVec4& color = mApplication->GetOptions().GetGridColor ( );
// See if the grid is off before rendering it
if ( !mApplication->GetOptions().GetGridVisible ( ))
{
return;
}
qglEnable(GL_BLEND);
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
qglColor4f ( color[0], color[1], color[2], 0.5f );
qglBegin ( GL_LINES );
step = mApplication->GetOptions().GetGridWidth ( ) * g_ZoomScales[mZoom];
for ( x = mRect.x + mRect.w; x >= mRect.x ; x -= step )
{
qglVertex2f ( x, mRect.y );
qglVertex2f ( x, mRect.y + mRect.h );
}
step = mApplication->GetOptions().GetGridHeight ( ) * g_ZoomScales[mZoom];
for ( y = mRect.y + mRect.h; y >= mRect.y ; y -= step )
{
qglVertex2f ( mRect.x, y );
qglVertex2f ( mRect.x + mRect.w, y );
}
qglEnd ( );
qglDisable(GL_BLEND);
qglColor3f ( color[0], color[1], color[2] );
qglBegin ( GL_LINES );
step = mApplication->GetOptions().GetGridWidth ( ) * g_ZoomScales[mZoom];
for ( x = mRect.x + mRect.w; x >= mRect.x ; x -= step * 4 )
{
qglVertex2f ( x, mRect.y );
qglVertex2f ( x, mRect.y + mRect.h );
}
step = mApplication->GetOptions().GetGridHeight ( ) * g_ZoomScales[mZoom];
for ( y = mRect.y + mRect.h; y >= mRect.y ; y -= step * 4 )
{
qglVertex2f ( mRect.x, y );
qglVertex2f ( mRect.x + mRect.w, y );
}
qglEnd ( );
}
/*
================
rvGEWorkspace::Render
Renders the workspace to the given DC
================
*/
void rvGEWorkspace::Render ( HDC hdc )
{
int front;
int back;
float scale;
scale = g_ZoomScales[mZoom];
// Switch GL contexts to our dc
if (!qwglMakeCurrent( hdc, win32.hGLRC ))
{
common->Printf("ERROR: wglMakeCurrent failed.. Error:%i\n", qglGetError());
common->Printf("Please restart Q3Radiant if the Map view is not working\n");
return;
}
// Prepare the view and clear it
GL_State( GLS_DEFAULT );
qglViewport(0, 0, mWindowWidth, mWindowHeight );
qglScissor(0, 0, mWindowWidth, mWindowHeight );
qglClearColor ( 0.75f, 0.75f, 0.75f, 0 );
qglDisable(GL_DEPTH_TEST);
qglDisable(GL_CULL_FACE);
qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Render the workspace below
qglMatrixMode(GL_PROJECTION);
qglLoadIdentity();
qglOrtho(0,mWindowWidth, mWindowHeight, 0, -1, 1);
qglMatrixMode(GL_MODELVIEW);
qglLoadIdentity();
qglColor3f ( mApplication->GetOptions().GetWorkspaceColor()[0], mApplication->GetOptions().GetWorkspaceColor()[1], mApplication->GetOptions().GetWorkspaceColor()[2] );
qglBegin ( GL_QUADS );
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 ( );
// Prepare the renderSystem view to draw the GUI in
viewDef_t viewDef;
memset ( &viewDef, 0, sizeof(viewDef) );
tr.viewDef = &viewDef;
tr.viewDef->renderView.x = mRect.x;
tr.viewDef->renderView.y = mWindowHeight - mRect.y - mRect.h;
tr.viewDef->renderView.width = mRect.w;
tr.viewDef->renderView.height = mRect.h;
tr.viewDef->scissor.x1 = 0;
tr.viewDef->scissor.y1 = 0;
tr.viewDef->scissor.x2 = mRect.w;
tr.viewDef->scissor.y2 = mRect.h;
tr.viewDef->isEditor = true;
renderSystem->BeginFrame(mWindowWidth, mWindowHeight );
// Draw the gui
mInterface->Redraw ( 0 ); // eventLoop->Milliseconds() );
// We are done using the renderSystem now
renderSystem->EndFrame( &front, &back );
if ( mApplication->GetActiveWorkspace ( ) == this )
{
mApplication->GetStatusBar().SetTriangles ( backEnd.pc.c_drawIndexes/3 );
}
// Prepare the viewport for drawing selections, etc.
GL_State( GLS_DEFAULT );
qglDisable( GL_TEXTURE_CUBE_MAP_EXT );
// qglDisable(GL_BLEND);
qglDisable(GL_CULL_FACE);
qglViewport(0, 0, mWindowWidth, mWindowHeight );
qglScissor(0, 0, mWindowWidth, mWindowHeight );
qglMatrixMode(GL_PROJECTION);
qglLoadIdentity();
qglOrtho(0,mWindowWidth, mWindowHeight, 0, -1, 1);
qglMatrixMode(GL_MODELVIEW);
qglLoadIdentity();
RenderGrid ( );
mSelections.Render ( );
qglFinish ( );
qwglSwapBuffers(hdc);
qglEnable( GL_TEXTURE_CUBE_MAP_EXT );
qglEnable( GL_CULL_FACE);
}
/*
================
rvGEWorkspace::UpdateTitle
Updates the window title with the name of the file and the zoom level and weither its open or not
================
*/
void rvGEWorkspace::UpdateTitle ( void )
{
// Set the window title based on the current filename
SetWindowText ( mWnd, va("%s%s (%d%%)", idStr(mFilename).StripPath ( ).c_str( ), mModified?"*":"", (int) (g_ZoomScales[mZoom] * 100)) );
gApp.GetStatusBar().SetZoom ( (int)(g_ZoomScales[mZoom] * 100.0f) );
}
/*
================
rvGEWorkspace::UpdateRectangle
Updates the rectangle (not counting scrolling)
================
*/
void rvGEWorkspace::UpdateRectangle ( bool useScroll )
{
RECT rcClient;
float x;
float y;
float scale;
scale = g_ZoomScales[mZoom];
// Grab the current client rectangle of the window and cache off the width and height
GetClientRect ( mWnd, &rcClient );
mWindowWidth = rcClient.right - rcClient.left;
mWindowHeight = rcClient.bottom - rcClient.top;
// The workspace is always centered in the window
x = mRect.x = mWindowWidth / 2 - (SCREEN_WIDTH * scale) / 2;
y = mRect.y = mWindowHeight / 2 - (SCREEN_HEIGHT * scale) / 2;
mRect.w = (SCREEN_WIDTH * scale);
mRect.h = (SCREEN_HEIGHT * scale);
// When using the scroll position offset the rectangle based on the scrollbar positions
if ( useScroll )
{
// Adjust the start of the rectangle for the scroll positiond
mRect.y -= (float)GetScrollPos ( mWnd, SB_VERT ) / 1000.0f;
mRect.x -= (float)GetScrollPos ( mWnd, SB_HORZ ) / 1000.0f;
}
}
/*
================
rvGEWorkspace::Scroll
Adjusts the given scrollbar by the given offset
================
*/
void rvGEWorkspace::Scroll ( int scrollbar, int offset )
{
SCROLLINFO si;
if ( scrollbar == SB_HORZ && !mScrollHorz )
{
return;
}
else if ( scrollbar == SB_VERT && !mScrollVert )
{
return;
}
// Get all the vertial scroll bar information
si.cbSize = sizeof (si);
si.fMask = SIF_ALL;
// Save the position for comparison later on
GetScrollInfo ( mWnd, scrollbar, &si);
si.nPos += (1000 * offset);
if ( si.nPos < si.nMin ) si.nPos = si.nMin;
if ( si.nPos > si.nMax ) si.nPos = si.nMax;
si.fMask = SIF_POS;
SetScrollInfo (mWnd, scrollbar, &si, TRUE);
GetScrollInfo (mWnd, scrollbar, &si);
UpdateRectangle ( );
}
int rvGEWorkspace::HandleScroll ( int scrollbar, WPARAM wParam, LPARAM lParam )
{
SCROLLINFO si;
// Get all the vertial scroll bar information
si.cbSize = sizeof (si);
si.fMask = SIF_ALL;
// Save the position for comparison later on
GetScrollInfo ( mWnd, scrollbar, &si);
switch (LOWORD (wParam))
{
// user clicked left or up arrow
case SB_LINELEFT:
si.nPos -= 1000;
break;
// user clicked right or down arrow
case SB_LINERIGHT:
si.nPos += 1000;
break;
// user clicked shaft left of the scroll box
case SB_PAGELEFT:
si.nPos -= si.nPage;
break;
// user clicked shaft right of the scroll box
case SB_PAGERIGHT:
si.nPos += si.nPage;
break;
// user dragged the scroll box
case SB_THUMBTRACK:
si.nPos = si.nTrackPos;
break;
default :
break;
}
// Set the position and then retrieve it. Due to adjustments
// by Windows it may not be the same as the value set.
si.fMask = SIF_POS;
SetScrollInfo (mWnd, scrollbar, &si, TRUE);
GetScrollInfo (mWnd, scrollbar, &si);
UpdateRectangle ( );
return 0;
}
/*
================
rvGEWorkspace::UpdateScrollbars
Updates the states and the ranges of the scrollbars as well as the rectangle
================
*/
void rvGEWorkspace::UpdateScrollbars ( void )
{
SCROLLINFO info;
// First update the rectangle without applying scroll positions so
// we know the real sizes and coordinates
UpdateRectangle ( false );
// Setup the veritcal scrollbar
info.cbSize = sizeof(info);
info.fMask = SIF_RANGE|SIF_PAGE;
info.nMax = (mRect.h - mWindowHeight + 10) * 1000 / 2;
info.nMin = -info.nMax;
info.nPage = (int)((float)info.nMax * (float)((float)mWindowHeight / mRect.h));
info.nMax += info.nPage;
// If there is something to scroll then turn on the vertical scroll bar
// if its not on and update the scroll info.
if ( info.nMax > 0 )
{
if ( !mScrollVert )
{
mScrollVert = true;
ShowScrollBar ( mWnd, SB_VERT, mScrollVert );
}
SetScrollInfo ( mWnd, SB_VERT, &info, TRUE );
}
// Nothing to scroll, turn off the scrollbar if its on.
else if ( mScrollVert )
{
mScrollVert = false;
SetScrollPos ( mWnd, SB_VERT, 0, FALSE );
ShowScrollBar ( mWnd, SB_VERT, mScrollVert );
}
// Setup the horizontal scrollbar
info.nMax = (mRect.w - mWindowWidth + 10) * 1000 / 2;
info.nMin = -info.nMax;
info.nPage = (int)((float)info.nMax * (float)((float)mWindowWidth / mRect.w));
info.nMax += info.nPage;
// If there is something to scroll then turn on the vertical scroll bar
// if its not on and update the scroll info.
if ( info.nMax > 0 )
{
if ( !mScrollHorz )
{
mScrollHorz = true;
ShowScrollBar ( mWnd, SB_HORZ, mScrollHorz );
}
SetScrollInfo ( mWnd, SB_HORZ, &info, TRUE );
}
// Nothing to scroll, turn off the scrollbar if its on.
else if ( mScrollHorz )
{
mScrollHorz = false;
SetScrollPos ( mWnd, SB_HORZ, 0, FALSE );
ShowScrollBar ( mWnd, SB_HORZ, mScrollHorz );
}
// Need to update the rectangle again to take the scrollbar changes into account
UpdateRectangle ( true );
}
/*
================
rvGEWorkspace::UpdateCursor
Called to update the cursor when the mouse is within the workspace window
================
*/
void rvGEWorkspace::UpdateCursor ( rvGESelectionMgr::EHitTest type )
{
switch ( type )
{
case rvGESelectionMgr::HT_SELECT:
SetCursor ( LoadCursor ( NULL, IDC_ARROW ) );
break;
case rvGESelectionMgr::HT_MOVE:
SetCursor ( LoadCursor ( NULL, IDC_SIZEALL ) );
break;
case rvGESelectionMgr::HT_SIZE_LEFT:
case rvGESelectionMgr::HT_SIZE_RIGHT:
SetCursor ( LoadCursor ( NULL, IDC_SIZEWE ) );
break;
case rvGESelectionMgr::HT_SIZE_TOP:
case rvGESelectionMgr::HT_SIZE_BOTTOM:
SetCursor ( LoadCursor ( NULL, IDC_SIZENS ) );
break;
case rvGESelectionMgr::HT_SIZE_TOPRIGHT:
case rvGESelectionMgr::HT_SIZE_BOTTOMLEFT:
SetCursor ( LoadCursor ( NULL, IDC_SIZENESW ) );
break;
case rvGESelectionMgr::HT_SIZE_BOTTOMRIGHT:
case rvGESelectionMgr::HT_SIZE_TOPLEFT:
SetCursor ( LoadCursor ( NULL, IDC_SIZENWSE ) );
break;
}
}
void rvGEWorkspace::UpdateCursor ( float x, float y )
{
idVec2 point;
rvGESelectionMgr::EHitTest type;
// First convert the worspace coord to a window coord
point = WorkspaceToWindow ( idVec2( x, y ) );
// See if it hits anything
type = mSelections.HitTest ( point.x, point.y );
// If it hits something then use it to update the cursor
if ( rvGESelectionMgr::HT_NONE != type )
{
UpdateCursor ( type );
}
else
{
SetCursor ( LoadCursor ( NULL, IDC_ARROW ) );
}
}
void rvGEWorkspace::UpdateCursor ( void )
{
if ( mDragType == rvGESelectionMgr::HT_NONE )
{
POINT point;
idVec2 cursor;
GetCursorPos ( &point );
cursor.Set ( point.x, point.y );
WindowToWorkspace ( cursor );
UpdateCursor ( cursor.x, cursor.y );
}
else
{
UpdateCursor ( mDragType );
}
}
/*
================
rvGEWorkspace::HandleMessage
Handles window messages to the workspace
================
*/
void rvGEWorkspace::HandleMessage ( UINT msg, WPARAM wParam, LPARAM lParam )
{
switch ( msg )
{
case WM_CLOSE:
{
if ( IsModified ( ) )
{
if ( IDYES == gApp.MessageBox ( va("Save changes to the document \"%s\" before closing?", GetFilename() ), MB_YESNO|MB_ICONQUESTION ) )
{
SendMessage ( mApplication->GetMDIFrame(), WM_COMMAND, MAKELONG(ID_GUIED_FILE_SAVE,0), 0 );
}
}
GetApplication ( )->GetNavigator().SetWorkspace(NULL);
GetApplication ( )->GetTransformer().SetWorkspace(NULL);
GetApplication ( )->GetProperties().SetWorkspace(NULL);
break;
}
case WM_CAPTURECHANGED:
if ( (HWND)lParam != mWnd )
{
mDragScroll = false;
mDragType = rvGESelectionMgr::HT_NONE;
}
break;
case WM_SETCURSOR:
{
POINT point;
idVec2 cursor;
GetCursorPos ( &point );
cursor.Set ( point.x, point.y );
WindowToWorkspace ( cursor );
if ( mDragType == rvGESelectionMgr::HT_NONE )
{
UpdateCursor ( cursor.x, cursor.y );
}
else
{
UpdateCursor ( mDragType );
}
break;
}
case WM_MOUSEWHEEL:
if ( (short)HIWORD(wParam) > 0 )
{
ZoomIn ( );
}
else if ( (short)HIWORD(wParam) < 0 )
{
ZoomOut ( );
}
break;
case WM_MOUSEMOVE:
HandleMouseMove ( wParam, lParam );
break;
case WM_MBUTTONDOWN:
HandleMButtonDown ( wParam, lParam );
break;
case WM_MBUTTONUP:
HandleMButtonUp ( wParam, lParam );
break;
case WM_LBUTTONDOWN:
HandleLButtonDown ( wParam, lParam );
break;
case WM_LBUTTONUP:
HandleLButtonUp ( wParam, lParam );
break;
case WM_LBUTTONDBLCLK:
HandleLButtonDblClk ( wParam, lParam );
break;
case WM_INITMENUPOPUP:
SendMessage ( mApplication->GetMDIFrame(), msg, wParam, lParam );
break;
case WM_COMMAND:
HandleCommand ( wParam, lParam );
break;
case WM_RBUTTONDOWN:
HandleRButtonDown ( wParam, lParam );
break;
case WM_SIZE:
UpdateScrollbars();
break;
case WM_VSCROLL:
HandleScroll ( SB_VERT, wParam, lParam );
break;
case WM_HSCROLL:
HandleScroll ( SB_HORZ, wParam, lParam );
break;
case WM_KEYDOWN:
HandleKeyDown ( wParam, lParam );
break;
}
}
/*
================
rvGEWorkspace::HandleCommand
Handles command messages destined for the workspace window. This is for
special workspace commands, any unhandled commands are forwarded to the main window
================
*/
int rvGEWorkspace::HandleCommand ( WPARAM wParam, LPARAM lParam )
{
// Select command
if ( LOWORD(wParam) >= ID_GUIED_SELECT_FIRST && LOWORD(wParam) <= ID_GUIED_SELECT_LAST )
{
idWindow* window = mSelectMenu[LOWORD(wParam)-ID_GUIED_SELECT_FIRST];
rvGEWindowWrapper* wrapper = rvGEWindowWrapper::GetWrapper ( window );
// Handle multi select as well
if ( GetAsyncKeyState ( VK_SHIFT ) & 0x8000 )
{
if ( wrapper->IsSelected ( ) )
{
mSelections.Remove ( window );
}
else
{
mSelections.Add ( window );
}
}
else
{
mSelections.Set ( window );
}
}
return SendMessage ( mApplication->GetMDIFrame(), WM_COMMAND, wParam, lParam );
}
/*
================
rvGEWorkspace::HandleMButtonDown
Handles the middle mouse down message in the workspace
================
*/
int rvGEWorkspace::HandleMButtonDown ( WPARAM wParam, LPARAM lParam )
{
if ( mDragType != rvGESelectionMgr::HT_NONE )
{
return 0;
}
mDragPoint.Set ( LOWORD(lParam), HIWORD(lParam) );
mDragScroll = true;
SetCursor ( mHandCursor );
SetCapture ( mWnd );
WindowToWorkspace ( mDragPoint );
return 0;
}
/*
================
rvGEWorkspace::HandleMButtonUp
Handles the middle mouse up message in the workspace
================
*/
int rvGEWorkspace::HandleMButtonUp ( WPARAM wParam, LPARAM lParam )
{
if ( mDragScroll )
{
mDragScroll = false;
ReleaseCapture ( );
}
return 0;
}
/*
================
rvGEWorkspace::HandleRButtonDown
Handles the left mouse down message in the workspace
================
*/
int rvGEWorkspace::HandleRButtonDown ( WPARAM wParam, LPARAM lParam )
{
POINT point = { LOWORD(lParam), HIWORD(lParam) };
HMENU menu;
// Add the select menu
mSelectMenu.Clear ( );
// Cache where the menu is being brought up so we can
// figure out which windows are under the point
mSelectMenuPos[0] = point.x;
mSelectMenuPos[1] = point.y;
WindowToWorkspace ( mSelectMenuPos );
// Build a list of all the windows under the menu point
rvGEWindowWrapper::GetWrapper ( mInterface->GetDesktop() )->EnumChildren ( BuildSelectMenuEnumProc, this );
// Add the desktop window always
mSelectMenu.Append ( mInterface->GetDesktop() );
//
menu = GetSubMenu ( LoadMenu ( mApplication->GetInstance(), MAKEINTRESOURCE(IDR_GUIED_ITEM_POPUP) ), 0 );
HMENU popup = CreatePopupMenu ( );
int i;
for ( i = 0; i < mSelectMenu.Num(); i ++ )
{
rvGEWindowWrapper* wrapper = rvGEWindowWrapper::GetWrapper ( mSelectMenu[i] );
AppendMenu ( popup, MF_STRING|MF_ENABLED|(wrapper->IsSelected()?MF_CHECKED:0), ID_GUIED_SELECT_FIRST + i, mSelectMenu[i]->GetName() );
}
InsertMenu ( menu, 1, MF_POPUP|MF_BYPOSITION, (UINT_PTR) popup, "Select" );
// Bring up the popup menu
ClientToScreen ( mWnd, &point );
TrackPopupMenu ( menu, TPM_RIGHTBUTTON|TPM_LEFTALIGN, point.x, point.y, 0, mWnd, NULL );
DestroyMenu ( popup );
DestroyMenu ( menu );
return 0;
}
/*
================
rvGEWorkspace::HandleLButtonDown
Handles the left mouse down message in the workspace
================
*/
int rvGEWorkspace::HandleLButtonDown ( WPARAM wParam, LPARAM lParam )
{
if ( mDragScroll )
{
return 0;
}
idVec2 point ( LOWORD(lParam), HIWORD(lParam) );
WindowToWorkspace ( point );
// Make sure whatever modifications get generated cant be merged into whats already there
mModifiers.BlockNextMerge ( );
mDragPoint.Set ( LOWORD(lParam), HIWORD(lParam) );
mDragTime = Sys_Milliseconds ( );
mDragX = true;
mDragY = true;
// If we have selections then start a drag
if ( mSelections.Num ( ) )
{
mDragType = mSelections.HitTest ( mDragPoint.x, mDragPoint.y );
}
rvGEWindowWrapper* wrapper;
wrapper = rvGEWindowWrapper::GetWrapper ( mInterface->GetDesktop ( ) );
idWindow* window = wrapper->WindowFromPoint ( point.x, point.y );
// dissallow selection of the desktop.
if ( gApp.GetOptions().GetIgnoreDesktopSelect() && window == mInterface->GetDesktop ( ) )
{
window = NULL;
}
if ( mDragType == rvGESelectionMgr::HT_MOVE || mDragType == rvGESelectionMgr::HT_NONE )
{
if ( window )
{
bool selected;
selected = mSelections.IsSelected ( window );
if ( GetAsyncKeyState ( VK_SHIFT ) & 0x8000 )
{
if ( !selected )
{
mSelections.Add ( window );
mDragType = rvGESelectionMgr::HT_MOVE;
}
else
{
mSelections.Remove ( window );
}
}
else if ( !selected && mDragType == rvGESelectionMgr::HT_NONE )
{
mSelections.Set ( window );
mDragType = rvGESelectionMgr::HT_MOVE;
}
}
else
{
mSelections.Clear ( );
}
}
if ( mSelections.IsExpression ( ) )
{
mDragType = rvGESelectionMgr::HT_SELECT;
}
// Windows capture
else if ( mDragType != rvGESelectionMgr::HT_NONE )
{
SetCapture ( mWnd );
}
WindowToWorkspace ( mDragPoint );
return 0;
}
/*
================
rvGEWorkspace::HandleLButtonUp
Handles the left mouse up message in the workspace
================
*/
int rvGEWorkspace::HandleLButtonUp ( WPARAM wParam, LPARAM lParam )
{
if ( mDragType != rvGESelectionMgr::HT_NONE )
{
ReleaseCapture ( );
mModifiers.BlockNextMerge ( );
// Update the transformer
mApplication->GetTransformer().Update ( );
}
// No more dragging
mDragType = rvGESelectionMgr::HT_NONE;
return 0;
}
/*
================
rvGEWorkspace::HandleLButtonDblClk
Handle a double click by opening properties
================
*/
int rvGEWorkspace::HandleLButtonDblClk ( WPARAM wParam, LPARAM lParam )
{
EditSelectedProperties ( );
return 0;
}
/*
================
rvGEWorkspace::HandleMouseMove
Handles the moving of the mouse for dragging and cursor updating
================
*/
int rvGEWorkspace::HandleMouseMove ( WPARAM wParam, LPARAM lParam )
{
idVec2 cursor;
cursor.Set ( (short)LOWORD(lParam), (short)HIWORD(lParam) );
// Convert the window point to the workspace before updating the
// cursor with the position
WindowToWorkspace ( cursor );
// Scrolling the window around
if ( mDragScroll )
{
Scroll ( SB_HORZ, mDragPoint.x - cursor.x );
Scroll ( SB_VERT, mDragPoint.y - cursor.y );
SetCursor ( mHandCursor );
mDragPoint = cursor;
return 0;
}
// If not dragging then just update the cursor and return
if ( mDragType == rvGESelectionMgr::HT_NONE )
{
UpdateCursor ( cursor.x, cursor.y );
return 0;
}
// Dont allow a drag move start until the button has been down for 100 ms or so
if ( mDragType == rvGESelectionMgr::HT_MOVE && Sys_Milliseconds() - mDragTime <= 50 )
{
return 0;
}
// Handle grid snapping
if ( gApp.GetOptions().GetGridSnap ( ) )
{
cursor.x = (float)(((int)cursor.x + gApp.GetOptions().GetGridWidth()/2) / gApp.GetOptions().GetGridWidth() * gApp.GetOptions().GetGridWidth());
cursor.y = (float)(((int)cursor.y + gApp.GetOptions().GetGridWidth()/2) / gApp.GetOptions().GetGridWidth() * gApp.GetOptions().GetGridWidth());
}
// If the cursor hasnt moved then there is nothing to update with the drag
if ( (int) cursor.x == (int) mDragPoint.x && (int) cursor.y == (int) mDragPoint.y )
{
return 0;
}
switch ( mDragType )
{
case rvGESelectionMgr::HT_MOVE:
AddModifierMove ( "Move", cursor.x - mDragPoint.x, cursor.y - mDragPoint.y, mApplication->GetOptions().GetGridSnap ( ) );
break;
case rvGESelectionMgr::HT_SIZE_BOTTOM:
AddModifierSize ( "Size", 0, 0, 0, cursor.y - mDragPoint.y, mApplication->GetOptions().GetGridSnap ( ) );
break;
case rvGESelectionMgr::HT_SIZE_TOP:
AddModifierSize ( "Size", 0, cursor.y - mDragPoint.y, 0, 0, mApplication->GetOptions().GetGridSnap ( ) );
break;
case rvGESelectionMgr::HT_SIZE_RIGHT:
AddModifierSize ( "Size", 0, 0, cursor.x - mDragPoint.x, 0, mApplication->GetOptions().GetGridSnap ( ) );
break;
case rvGESelectionMgr::HT_SIZE_LEFT:
AddModifierSize ( "Size", cursor.x - mDragPoint.x, 0, 0, 0, mApplication->GetOptions().GetGridSnap ( ) );
break;
case rvGESelectionMgr::HT_SIZE_TOPLEFT:
AddModifierSize ( "Size", cursor.x - mDragPoint.x, cursor.y - mDragPoint.y, 0, 0, mApplication->GetOptions().GetGridSnap ( ) );
break;
case rvGESelectionMgr::HT_SIZE_TOPRIGHT:
AddModifierSize ( "Size", 0, cursor.y - mDragPoint.y, cursor.x - mDragPoint.x, 0, mApplication->GetOptions().GetGridSnap ( ) );
break;
case rvGESelectionMgr::HT_SIZE_BOTTOMLEFT:
AddModifierSize ( "Size", cursor.x - mDragPoint.x, 0, 0, cursor.y - mDragPoint.y, mApplication->GetOptions().GetGridSnap ( ) );
break;
case rvGESelectionMgr::HT_SIZE_BOTTOMRIGHT:
AddModifierSize ( "Size", 0, 0, cursor.x - mDragPoint.x, cursor.y - mDragPoint.y, mApplication->GetOptions().GetGridSnap ( ) );
break;
}
UpdateCursor ( mDragType );
// If the x coordinate has changed then update it
if ( (int)cursor.x != (int)mDragPoint.x && mDragX )
{
mDragPoint.x = cursor.x;
}
// If the y coordinate has changed then update it
if ( (int)cursor.y != (int)mDragPoint.y && mDragY )
{
mDragPoint.y = cursor.y;
}
return 0;
}
/*
================
rvGEWorkspace::HandleKeyDown
Handles the the pressing of a key
================
*/
int rvGEWorkspace::HandleKeyDown ( WPARAM wParam, LPARAM lParam )
{
bool shift = (GetAsyncKeyState ( VK_SHIFT ) & 0x8000) ? true : false;
switch ( wParam )
{
case VK_LEFT:
if ( shift )
{
AddModifierSizeNudge ( -1, 0, false );
}
else
{
AddModifierMoveNudge ( -1, 0, false );
}
break;
case VK_RIGHT:
if ( shift )
{
AddModifierSizeNudge ( 1, 0, false );
}
else
{
AddModifierMoveNudge ( 1, 0, false );
}
break;
case VK_DOWN:
if ( shift )
{
AddModifierSizeNudge ( 0, 1, false );
}
else
{
AddModifierMoveNudge ( 0, 1, false );
}
break;
case VK_UP:
if ( shift )
{
AddModifierSizeNudge ( 0, -1, false );
}
else
{
AddModifierMoveNudge ( 0, -1, false );
}
break;
case VK_ESCAPE:
mSelections.Clear ( );
mApplication->GetNavigator().Update ( );
break;
}
return 0;
}
/*
================
rvGEWorkspace::WindowToWorkspace
Converts the given coordinates in windows space to the workspace's coordinates.
================
*/
idVec2& rvGEWorkspace::WindowToWorkspace ( idVec2& point )
{
point.x = (point.x - mRect.x) / mRect.w * SCREEN_WIDTH;
point.y = (point.y - mRect.y) / mRect.h * SCREEN_HEIGHT;
return point;
}
idRectangle& rvGEWorkspace::WindowToWorkspace ( idRectangle& rect )
{
rect.x = (rect.x - mRect.x) / mRect.w * SCREEN_WIDTH;
rect.y = (rect.y - mRect.y) / mRect.h * SCREEN_HEIGHT;
rect.w = rect.w / mRect.w * SCREEN_WIDTH;
rect.h = rect.h / mRect.h * SCREEN_HEIGHT;
return rect;
}
/*
================
rvGEWorkspace::WindowToWorkspace
Converts the given workspace coordinates to the windows coordinates.
================
*/
idVec2& rvGEWorkspace::WorkspaceToWindow ( idVec2& point )
{
point.x = mRect.x + (point.x / SCREEN_WIDTH * mRect.w);
point.y = mRect.y + (point.y / SCREEN_HEIGHT * mRect.h);
return point;
}
idRectangle& rvGEWorkspace::WorkspaceToWindow ( idRectangle& rect )
{
rect.x = mRect.x + (rect.x / SCREEN_WIDTH * mRect.w);
rect.y = mRect.y + (rect.y / SCREEN_HEIGHT * mRect.h);
rect.w = rect.w / SCREEN_WIDTH * mRect.w;
rect.h = rect.h / SCREEN_HEIGHT * mRect.h;
return rect;
}
/*
================
rvGEWorkspace::ZoomIn
Zooms the workspace in by one zoom level
================
*/
rvGEWorkspace::EZoomLevel rvGEWorkspace::ZoomIn ( void )
{
mZoom = mZoom + 1;
if ( mZoom >= ZOOM_MAX )
{
mZoom = ZOOM_MAX - 1;
}
UpdateScrollbars ( );
UpdateTitle ( );
InvalidateRect ( mWnd, NULL, FALSE );
return (EZoomLevel)mZoom;
}
/*
================
rvGEWorkspace::ZoomOut
Zooms the workspace out by one level
================
*/
rvGEWorkspace::EZoomLevel rvGEWorkspace::ZoomOut ( void )
{
mZoom--;
if ( mZoom <= ZOOM_MIN )
{
mZoom = ZOOM_MIN + 1;
}
UpdateScrollbars ( );
UpdateTitle ( );
InvalidateRect ( mWnd, NULL, FALSE );
return (EZoomLevel)mZoom;
}
/*
================
rvGEWorkspace::CreateModifier
Creates a new modifier of the given type for the given window. This function is called
specifically from the add modifiers function with the variable args list forwarded.
================
*/
rvGEModifier* rvGEWorkspace::CreateModifier ( EModifierType type, idWindow* window, va_list args )
{
rvGEModifier* mod;
switch ( type )
{
case MOD_DELETE:
mod = new rvGEDeleteModifier ( "Delete", window );
break;
case MOD_HIDE:
mod = new rvGEHideModifier ( "Hide", window, true );
break;
case MOD_UNHIDE:
mod = new rvGEHideModifier ( "Hide", window, false );
break;
case MOD_SEND_BACKWARD:
mod = new rvGEZOrderModifier ( "Send Backward", window, rvGEZOrderModifier::ZO_BACKWARD );
break;
case MOD_SEND_BACK:
mod = new rvGEZOrderModifier ( "Send to Back", window, rvGEZOrderModifier::ZO_BACK );
break;
case MOD_BRING_FORWARD:
mod = new rvGEZOrderModifier ( "Bring Forward", window, rvGEZOrderModifier::ZO_FORWARD );
break;
case MOD_BRING_FRONT:
mod = new rvGEZOrderModifier ( "Bring to Front", window, rvGEZOrderModifier::ZO_FRONT );
break;
default:
mod = NULL;
break;
}
return mod;
}
/*
================
rvGEWorkspace::AddModifiers
Add the specific modifier for the given window
================
*/
void rvGEWorkspace::AddModifiers ( idWindow* window, EModifierType type, ... )
{
va_list args;
va_start(args,type) ;
mModifiers.Append ( CreateModifier ( type, window, args ) );
va_end (args) ;
SetModified ( true );
}
void rvGEWorkspace::AddModifiers ( EModifierType type, ... )
{
va_list args;
// Nothing to move if there is no selection
if ( !mSelections.Num ( ) )
{
return;
}
// More than one selection requires a modifier group
else if ( mSelections.Num ( ) > 1 )
{
rvGEModifierGroup* group = new rvGEModifierGroup;
int i;
for ( i = 0; i < mSelections.Num(); i ++ )
{
va_start(args,type);
group->Append ( CreateModifier ( type, mSelections[i], args ) );
va_end (args);
}
mModifiers.Append ( group );
}
// Single modifier
else
{
va_start(args,type) ;
mModifiers.Append ( CreateModifier ( type, mSelections[0], args ) );
va_end (args) ;
}
SetModified ( true );
}
bool rvGEWorkspace::BuildSelectMenuEnumProc ( rvGEWindowWrapper* wrapper, void* data )
{
rvGEWorkspace* workspace;
workspace = (rvGEWorkspace*) data;
assert ( workspace );
if ( !wrapper )
{
return true;
}
wrapper->EnumChildren ( BuildSelectMenuEnumProc, data );
if ( wrapper->IsDeleted ( ) || wrapper->IsHidden ( ) )
{
return true;
}
if ( wrapper->GetScreenRect ( ).Contains ( workspace->mSelectMenuPos[0], workspace->mSelectMenuPos[1] ) )
{
workspace->mSelectMenu.Append ( wrapper->GetWindow ( ));
}
return true;
}
bool rvGEWorkspace::ShowAllEnumProc ( rvGEWindowWrapper* wrapper, void* data )
{
rvGEModifierGroup* group = (rvGEModifierGroup*) data;
wrapper->EnumChildren ( ShowAllEnumProc, data );
if ( wrapper->IsHidden ( ) )
{
group->Append ( new rvGEHideModifier ( "Show Hidden", wrapper->GetWindow ( ), false ) );
}
return true;
}
void rvGEWorkspace::AddModifierShowAll ( void )
{
rvGEModifierGroup* group = new rvGEModifierGroup;
rvGEWindowWrapper::GetWrapper( mInterface->GetDesktop ( ) )->EnumChildren ( ShowAllEnumProc, group );
if ( !group->GetCount ( ) )
{
delete group;
}
else
{
mModifiers.Append ( group );
}
mApplication->GetNavigator().Refresh ( );
}
void rvGEWorkspace::DeleteSelected ( void )
{
AddModifiers ( MOD_DELETE );
mSelections.Clear ( );
mApplication->GetNavigator().Update ( );
}
/*
================
rvGEWorkspace::NewWindow
Create a new window
================
*/
idWindow* rvGEWorkspace::NewWindow ( idDict* state, rvGEWindowWrapper::EWindowType type )
{
idWindow* window = new idWindow ( mInterface->GetDesktop()->GetDC(), mInterface );
rvGEWindowWrapper* wrapper;
int count;
idStr baseName;
switch ( type )
{
case rvGEWindowWrapper::WT_NORMAL:
window = new idWindow ( mInterface->GetDesktop()->GetDC(), mInterface );
break;
case rvGEWindowWrapper::WT_BIND:
window = new idBindWindow ( mInterface->GetDesktop()->GetDC(), mInterface );
break;
case rvGEWindowWrapper::WT_RENDER:
window = new idRenderWindow ( mInterface->GetDesktop()->GetDC(), mInterface );
break;
case rvGEWindowWrapper::WT_CHOICE:
window = new idChoiceWindow ( mInterface->GetDesktop()->GetDC(), mInterface );
break;
case rvGEWindowWrapper::WT_EDIT:
window = new idEditWindow ( mInterface->GetDesktop()->GetDC(), mInterface );
break;
default:
assert ( false );
return NULL;
}
baseName = state ? state->GetString("name","unnamed") : "unnamed";
baseName.StripQuotes ( );
count = 0;
if ( mInterface->GetDesktop()->FindChildByName ( baseName ) )
{
count = 1;
while ( 1 )
{
drawWin_t* dw = mInterface->GetDesktop()->FindChildByName ( va("%s%d",baseName.c_str(),count) );
if ( !dw )
{
break;
}
assert ( dw->win );
wrapper = rvGEWindowWrapper::GetWrapper ( dw->win );
if ( wrapper && wrapper->IsDeleted ( ) )
{
break;
}
count++;
}
}
idStr winName;
idStr winTemplate;
if ( count )
{
winName = va("%s%d", baseName.c_str(), count );
}
else
{
winName = baseName;
}
winTemplate = winName + " { }";
idParser src( winTemplate, winTemplate.Length(), "", LEXFL_ALLOWMULTICHARLITERALS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
window->Parse ( &src );
wrapper = rvGEWindowWrapper::GetWrapper ( window );
if ( state )
{
wrapper->SetState ( *state );
}
wrapper->SetStateKey ( "name", winName );
wrapper->Finish ( );
SetModified ( true );
return window;
}
idWindow* rvGEWorkspace::AddWindow ( rvGEWindowWrapper::EWindowType type )
{
idWindow* window;
idDict state;
state.Set ( "rect", "0,0,100,100" );
state.Set ( "visible", "1" );
window = NewWindow ( &state, type );
assert ( window );
mModifiers.Append ( new rvGEInsertModifier ( "New", window, mInterface->GetDesktop(), NULL ) );
mSelections.Set ( window );
mApplication->GetNavigator().Update ( );
mApplication->GetTransformer().Update ( );
mApplication->GetProperties().Update ( );
return window;
}
bool rvGEWorkspace::EditSelectedProperties ( void )
{
if ( !mSelections.Num ( ) || mSelections.Num() > 1 )
{
return false;
}
idDict dict;
if ( GEItemPropsDlg_DoModal ( mWnd, mSelections[0], dict ) )
{
mModifiers.Append ( new rvGEStateModifier ( "Item Properties", mSelections[0], dict ) );
SetModified ( true );
}
mApplication->GetNavigator().Update ( );
mApplication->GetTransformer().Update ( );
mApplication->GetProperties().Update ( );
return true;
}
bool rvGEWorkspace::EditSelectedScripts ( void )
{
if ( GEItemScriptsDlg_DoModal ( mWnd, mSelections[0] ) )
{
gApp.GetNavigator().Refresh ( );
SetModified ( true );
}
return true;
}
void rvGEWorkspace::BringSelectedForward ( void )
{
AddModifiers ( MOD_BRING_FORWARD );
mApplication->GetNavigator().Update ( );
}
void rvGEWorkspace::BringSelectedToFront ( void )
{
AddModifiers ( MOD_BRING_FRONT );
mApplication->GetNavigator().Update ( );
}
void rvGEWorkspace::SendSelectedToBack ( void )
{
AddModifiers ( MOD_SEND_BACK );
mApplication->GetNavigator().Update ( );
}
void rvGEWorkspace::SendSelectedBackward ( void )
{
AddModifiers ( MOD_SEND_BACKWARD );
mApplication->GetNavigator().Update ( );
}
/*
================
rvGEWorkspace::MakeSelectedSameSize
Align the selected items to the first one using the given align type
================
*/
void rvGEWorkspace::MakeSelectedSameSize ( bool changeWidth, bool changeHeight )
{
rvGEModifierGroup* group;
idRectangle rectTo;
int i;
group = new rvGEModifierGroup ( );
rectTo = rvGEWindowWrapper::GetWrapper ( mSelections[0] )->GetClientRect ( );
for ( i = 1; i < mSelections.Num(); i ++ )
{
idRectangle rectFrom;
float width = 0;
float height = 0;
rectFrom = rvGEWindowWrapper::GetWrapper(mSelections[i])->GetClientRect ();
if ( changeWidth )
{
width = rectTo.w - rectFrom.w;
}
if ( changeHeight )
{
height = rectTo.h - rectFrom.h;
}
group->Append ( new rvGESizeModifier ( "Make Same Size", mSelections[i], 0, 0, width, height ) );
}
mModifiers.Append ( group );
// Cant merge alignments
mModifiers.BlockNextMerge ( );
SetModified ( true );
}
/*
================
rvGEWorkspace::AlignSelected
Align the selected items to the first one using the given align type
================
*/
void rvGEWorkspace::AlignSelected ( EItemAlign align )
{
static const char* alignNames[]={"Lefts","Centers","Rights","Tops","Middles","Bottoms" };
int i;
idStr modName;
rvGEModifierGroup* group;
assert ( mSelections.Num() > 1 );
modName = "Align " + idStr(alignNames[align]);
group = new rvGEModifierGroup ( );
idRectangle rectTo;
rectTo = rvGEWindowWrapper::GetWrapper ( mSelections[0] )->GetScreenRect ( );
// Everything gets aligned to the first selection so run
// through all other selections and move them.
for ( i = 1; i < mSelections.Num(); i ++ )
{
float x;
float y;
idRectangle rectFrom;
rectFrom = rvGEWindowWrapper::GetWrapper ( mSelections[i] )->GetScreenRect ( );
switch ( align )
{
case ALIGN_LEFTS:
x = rectTo[0] - rectFrom[0];
y = 0;
break;
case ALIGN_RIGHTS:
x = (rectTo[0]+rectTo[2]) - (rectFrom[0]+rectFrom[2]);
y = 0;
break;
case ALIGN_CENTERS:
x = (rectTo[0]+rectTo[2]/2) - (rectFrom[0]+rectFrom[2]/2);
y = 0;
break;
case ALIGN_TOPS:
y = rectTo[1] - rectFrom[1];
x = 0;
break;
case ALIGN_BOTTOMS:
x = 0;
y = (rectTo[1]+rectTo[3]) - (rectFrom[1]+rectFrom[3]);
break;
case ALIGN_MIDDLES:
x = 0;
y = (rectTo[1]+rectTo[3]/2) - (rectFrom[1]+rectFrom[3]/2);
break;
default:
assert ( false );
break;
}
group->Append ( new rvGEMoveModifier ( modName, mSelections[i], x, y ) );
}
mModifiers.Append ( group );
// Cant merge alignments
mModifiers.BlockNextMerge ( );
SetModified ( true );
}
/*
================
rvGEWorkspace::AddModifierMove
Adds a move modifier with the given offsets
================
*/
void rvGEWorkspace::AddModifierMove ( const char* modName, float x, float y, bool snap )
{
idRectangle scaleRect;
idRectangle newRect;
scaleRect = mSelections.GetRect ( );
WindowToWorkspace ( scaleRect );
newRect = scaleRect;
newRect.x += x;
newRect.y += y;
if ( snap )
{
gApp.GetOptions ().SnapRectToGrid ( newRect, true, true, false, false );
}
rvGEModifierGroup* group = new rvGEModifierGroup;
for ( int i = 0; i < mSelections.Num(); i ++ )
{
if ( !mSelections[i]->GetParent ( ) )
{
continue;
}
// IF the parent window is being moved around as well then dont move this one.
if ( rvGEWindowWrapper::GetWrapper ( mSelections[i]->GetParent ( ) )->IsSelected ( ) )
{
// We still need the modifier there so the selection can be restored and
// so the rectangle gets updated
group->Append ( new rvGEMoveModifier ( modName, mSelections[i], 0, 0 ) );
continue;
}
group->Append ( new rvGEMoveModifier ( modName, mSelections[i], newRect.x-scaleRect.x, newRect.y-scaleRect.y ) );
}
mModifiers.Append ( group );
SetModified ( true );
}
/*
================
rvGEWorkspace::AddModifierSize
Adds a size modifier with the given offsets
================
*/
void rvGEWorkspace::AddModifierSize ( const char* modName, float l, float t, float r, float b, bool snap )
{
idRectangle scaleRect;
idRectangle sizeRect;
idRectangle newRect;
scaleRect = mSelections.GetRect ( );
WindowToWorkspace ( scaleRect );
newRect = scaleRect;
newRect.x += l;
newRect.y += t;
newRect.w += (r - l);
newRect.h += (b - t);
// Restrict sizing below 1 width
if ( newRect.w <= 1 )
{
newRect.x = newRect.x - (l ? (1 - newRect.w) : 0);
mDragPoint.x = newRect.x;
newRect.w = 1;
mDragX = false;
}
else
{
mDragX = true;
}
// Restrict sizing below 1 height
if ( newRect.h <= 1 )
{
newRect.y = newRect.y - (t ? (1 - newRect.h) : 0);
mDragPoint.y = newRect.y;
newRect.h = 1;
mDragY = false;
}
else
{
mDragY = true;
}
if ( snap )
{
gApp.GetOptions ().SnapRectToGrid ( newRect, l != 0.0f, t != 0.0f, r != 0.0f, b != 0.0f );
}
rvGEModifierGroup* group = new rvGEModifierGroup;
for ( int i = 0; i < mSelections.Num(); i ++ )
{
sizeRect = rvGEWindowWrapper::GetWrapper ( mSelections[i] )->GetScreenRect ( );
l = (newRect.x + ((sizeRect.x - scaleRect.x) / scaleRect.w) * newRect.w) - sizeRect.x;
t = (newRect.y + ((sizeRect.y - scaleRect.y) / scaleRect.h) * newRect.h) - sizeRect.y;
r = (sizeRect.w / scaleRect.w * newRect.w) - sizeRect.w + l;
b = (sizeRect.h / scaleRect.h * newRect.h) - sizeRect.h + t;
// This is sorta crufty but needs to be done. When a parent is being sized at the same
// time as a child you will get double movement because the child is relative to the parent. Therefore
// we need to subtract out the closest parents sizing.
idWindow* parent = mSelections[i];
while ( NULL != (parent = parent->GetParent ( ) ) )
{
rvGEWindowWrapper* pwrapper = rvGEWindowWrapper::GetWrapper ( parent );
float offset;
if ( !pwrapper->IsSelected ( ) )
{
continue;
}
sizeRect = pwrapper->GetScreenRect ( );
// Subtract out the left and right modifications
offset = ((newRect.x + ((sizeRect.x - scaleRect.x) / scaleRect.w) * newRect.w) - sizeRect.x);
l -= offset;
r -= offset;
// Subtract out the top and bottom modifications
offset = ((newRect.y + ((sizeRect.y - scaleRect.y) / scaleRect.h) * newRect.h) - sizeRect.y);
t -= offset;
b -= offset;
break;
}
group->Append ( new rvGESizeModifier ( modName, mSelections[i], l, t, r, b ) );
}
mModifiers.Append ( group );
SetModified ( true );
}
/*
================
rvGEWorkspace::MakeSelectedAChild
Makes the selected windows a child of the first selected window
================
*/
void rvGEWorkspace::MakeSelectedAChild ( void )
{
rvGEModifierGroup* group;
int i;
if ( !rvGEWindowWrapper::GetWrapper ( mSelections[0] )->CanHaveChildren ( ) )
{
gApp.MessageBox ( "Cannot add children to an htmlDef item", MB_OK|MB_ICONERROR );
return;
}
group = new rvGEModifierGroup;
for ( i = 1; i < mSelections.Num(); i ++ )
{
if ( mSelections[i]->GetParent ( ) == mSelections[0] )
{
continue;
}
if ( !mSelections[i]->GetParent ( ) )
{
continue;
}
group->Append ( new rvGEInsertModifier ( "Make Child", mSelections[i], mSelections[0], NULL ) );
}
mModifiers.Append ( group );
// Navigator needs an update since the ordering has changed
gApp.GetNavigator().Update ( );
SetModified ( true );
}
void rvGEWorkspace::Copy ( void )
{
int i;
// Clear the current clipboard
for ( i = 0; i < mClipboard.Num(); i ++ )
{
delete mClipboard[i];
}
mClipboard.Clear ( );
for ( i = 0; i < mSelections.Num(); i ++ )
{
rvGEWindowWrapper* wrapper = rvGEWindowWrapper::GetWrapper ( mSelections[i] );
assert ( wrapper );
rvGEClipboardItem* item = new rvGEClipboardItem;
item->mStateDict = wrapper->GetStateDict ( );
item->mScriptDict = wrapper->GetScriptDict ( );
item->mVarDict = wrapper->GetVariableDict ( );
item->mStateDict.Set ( "windowType", rvGEWindowWrapper::WindowTypeToString ( wrapper->GetWindowType ( ) ) );
mClipboard.Append ( item );
}
}
void rvGEWorkspace::Paste ( void )
{
int i;
rvGEModifierGroup* group = new rvGEModifierGroup;
mSelections.Clear ( );
for ( i = 0; i < mClipboard.Num(); i ++ )
{
idDict state;
rvGEWindowWrapper::EWindowType type;
state.Copy ( mClipboard[i]->mStateDict );
type = rvGEWindowWrapper::StringToWindowType ( state.GetString ( "windowType", "windowDef" ) );
state.Delete ( "windowType" );
idWindow* window = NewWindow ( &state, type );
group->Append ( new rvGEInsertModifier ( "Paste", window, mInterface->GetDesktop(), NULL ) );
mSelections.Add ( window );
rvGEWindowWrapper::GetWrapper ( window )->GetScriptDict ( ) = mClipboard[i]->mScriptDict;
rvGEWindowWrapper::GetWrapper ( window )->GetVariableDict ( ) = mClipboard[i]->mVarDict;
}
mModifiers.Append ( group );
mApplication->GetNavigator().Update ( );
SetModified ( true );
}
void rvGEWorkspace::HideSelected ( void )
{
AddModifiers ( MOD_HIDE );
mSelections.Clear ( );
mApplication->GetNavigator().Refresh ( );
}
void rvGEWorkspace::UnhideSelected ( void )
{
AddModifiers ( MOD_UNHIDE );
mApplication->GetNavigator().Refresh ( );
}
void rvGEWorkspace::HideWindow ( idWindow* window )
{
AddModifiers ( window, MOD_HIDE );
mApplication->GetNavigator().Refresh ( );
}
void rvGEWorkspace::UnhideWindow ( idWindow* window )
{
AddModifiers ( window, MOD_UNHIDE );
mApplication->GetNavigator().Refresh ( );
}
/*
================
rvGEWorkspace::SetModified
Sets the modified state of the window and if source control is enabled it
will attempt to check out the file
================
*/
void rvGEWorkspace::SetModified ( bool mod )
{
if ( mModified != mod )
{
mModified = mod;
UpdateTitle ( );
}
}