/*
**	Command & Conquer Generals Zero Hour(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program 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.
**
**	This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
*/

////////////////////////////////////////////////////////////////////////////////
//																																						//
//  (c) 2001-2003 Electronic Arts Inc.																				//
//																																						//
////////////////////////////////////////////////////////////////////////////////

// FILE: EditWindow.cpp ///////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//                                                                          
//                       Westwood Studios Pacific.                          
//                                                                          
//                       Confidential Information                           
//                Copyright (C) 2001 - All Rights Reserved                  
//                                                                          
//-----------------------------------------------------------------------------
//
// Project:    RTS3
//
// File name:  EditWindow.cpp
//
// Created:    Colin Day, July 2001
//
// Desc:       Main edit window for the GUI editing tool
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////

// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <stdio.h>

// USER INCLUDES //////////////////////////////////////////////////////////////
#include "Common/Debug.h"
#include "GameClient/Display.h"
#include "GameClient/GameWindowManager.h"
#include "W3DDevice/GameClient/W3DFileSystem.h"
#include "Resource.h"
#include "EditWindow.h"
#include "GUIEdit.h"
#include "WinMain.h"
#include "HierarchyView.h"
#include "Properties.h"
#include "WW3D2/WW3D.h"
#include "WW3D2/Render2D.h"

// DEFINES ////////////////////////////////////////////////////////////////////

// PRIVATE TYPES //////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
Bool EditWindow::m_classRegistered = FALSE;  ///< class registered flag
char *EditWindow::m_className = "EditWindowClass";  ///< edit window class name

///////////////////////////////////////////////////////////////////////////////
// PUBLIC DATA ////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
EditWindow *TheEditWindow = NULL;  ///< edit window singleton

///////////////////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

// editProc ===================================================================
/** Window procedure for the edit window */
//=============================================================================
LRESULT CALLBACK EditWindow::editProc( HWND hWnd, UINT message, 
																			 WPARAM wParam, LPARAM lParam )
{
	
	switch( message )
	{

		// ------------------------------------------------------------------------
		case WM_TIMER:
		{
			Int timerID = wParam;

			if( TheEditWindow )
			{
			
				if( timerID == TIMER_EDIT_WINDOW_PULSE )
					TheEditWindow->updatePulse();

			}  // end if

			return 0;

		}  // end timer

		//-------------------------------------------------------------------------
		case WM_MOUSEMOVE:
		case WM_LBUTTONDOWN:
		case WM_LBUTTONUP:
		case WM_MBUTTONDOWN:
		case WM_MBUTTONUP:
		case WM_RBUTTONDOWN:
		case WM_RBUTTONUP:
		{

			TheEditWindow->mouseEvent( message, wParam, lParam );
			return 0;

		}  // end mouse events

		// ------------------------------------------------------------------------
		case WM_COMMAND:
		{
			Int controlID = LOWORD( wParam );
//			Int nofifyCode = HIWORD( wParam );
//			HWND hWndControl = (HWND)lParam;

			switch( controlID )
			{

				// --------------------------------------------------------------------
				case POPUP_MENU_NEW_WINDOW:
				case POPUP_MENU_NEW_PUSH_BUTTON:
				case POPUP_MENU_NEW_RADIO_BUTTON:
				case POPUP_MENU_NEW_TAB_CONTROL:
				case POPUP_MENU_NEW_CHECK_BOX:
				case POPUP_MENU_NEW_LISTBOX:
				case POPUP_MENU_NEW_COMBO_BOX:
				case POPUP_MENU_NEW_HORIZONTAL_SLIDER:
				case POPUP_MENU_NEW_VERTICAL_SLIDER:
				case POPUP_MENU_NEW_PROGRESS_BAR:
				case POPUP_MENU_NEW_TEXT_ENTRY:
				case POPUP_MENU_NEW_STATIC_TEXT:
				case POPUP_MENU_PROPERTIES:
				case POPUP_MENU_DELETE:
				case POPUP_MENU_BRING_TO_TOP:
				{
					ICoord2D pos;
					GameWindow *window;

					// get position the menu was initiated at
					TheEditWindow->getPopupMenuClickPos( &pos );

					//
					// if the position the user clicked at was on another window,
					// that window will become the parent of the new one
					//
					window = TheEditor->getWindowAtPos( pos.x, pos.y );

					// create new window at that location
					switch( controlID )
					{
						
						// ----------------------------------------------------------------
						case POPUP_MENU_NEW_WINDOW:
							TheEditor->newWindow( GWS_USER_WINDOW, 
																		window, pos.x, pos.y, 
																		15 * TheEditor->getGridResolution(),
																		15 * TheEditor->getGridResolution() );
							break;

						// ----------------------------------------------------------------
						case POPUP_MENU_NEW_PUSH_BUTTON:
							TheEditor->newWindow( GWS_PUSH_BUTTON,
																		window, pos.x, pos.y, 
																		15 * TheEditor->getGridResolution(), 
																		3 * TheEditor->getGridResolution() );
							break;

						// ----------------------------------------------------------------
						case POPUP_MENU_NEW_CHECK_BOX:
							TheEditor->newWindow( GWS_CHECK_BOX,
																		window, pos.x, pos.y, 
																		15 * TheEditor->getGridResolution(),
																		3 * TheEditor->getGridResolution() );
							break;

						// ----------------------------------------------------------------
						case POPUP_MENU_NEW_RADIO_BUTTON:
							TheEditor->newWindow( GWS_RADIO_BUTTON,
																		window, pos.x, pos.y, 
																		15 * TheEditor->getGridResolution(), 
																		3 * TheEditor->getGridResolution() );
							break;

						// ----------------------------------------------------------------
						case POPUP_MENU_NEW_TAB_CONTROL:
							TheEditor->newWindow( GWS_TAB_CONTROL,
																		window, pos.x, pos.y, 
																		45 * TheEditor->getGridResolution(), 
																		30 * TheEditor->getGridResolution() );
							break;

						// ----------------------------------------------------------------
						case POPUP_MENU_NEW_LISTBOX:
							TheEditor->newWindow( GWS_SCROLL_LISTBOX,
																		window, pos.x, pos.y, 
																		20 * TheEditor->getGridResolution(), 
																		20 * TheEditor->getGridResolution() );
							break;
						
						// ----------------------------------------------------------------
						case POPUP_MENU_NEW_COMBO_BOX:
							TheEditor->newWindow( GWS_COMBO_BOX,
																		window, pos.x, pos.y, 
																		15 * TheEditor->getGridResolution(), 
																		3 * TheEditor->getGridResolution() );
							break;

						// ----------------------------------------------------------------
						case POPUP_MENU_NEW_HORIZONTAL_SLIDER:
							TheEditor->newWindow( GWS_HORZ_SLIDER,
																		window, pos.x, pos.y, 
																		20 * TheEditor->getGridResolution(), 
																		GADGET_SIZE );
							break;

						// ----------------------------------------------------------------
						case POPUP_MENU_NEW_VERTICAL_SLIDER:
							TheEditor->newWindow( GWS_VERT_SLIDER,
																		window, pos.x, pos.y, 
																		GADGET_SIZE, 
																		20 * TheEditor->getGridResolution() );
							break;

						// ----------------------------------------------------------------
						case POPUP_MENU_NEW_PROGRESS_BAR:
							TheEditor->newWindow( GWS_PROGRESS_BAR,
																		window, pos.x, pos.y, 
																		40 * TheEditor->getGridResolution(), 
																		GADGET_SIZE );
							break;

						// ----------------------------------------------------------------
						case POPUP_MENU_NEW_TEXT_ENTRY:
							TheEditor->newWindow( GWS_ENTRY_FIELD,
																		window, pos.x, pos.y, 
																		20 * TheEditor->getGridResolution(), 
																		25 );
							break;

						// ----------------------------------------------------------------
						case POPUP_MENU_NEW_STATIC_TEXT:
							TheEditor->newWindow( GWS_STATIC_TEXT,
																		window, pos.x, pos.y, 
																		15 * TheEditor->getGridResolution(), 
																		15 * TheEditor->getGridResolution() );
							break;

						// ----------------------------------------------------------------
						case POPUP_MENU_DELETE:
							TheEditor->deleteSelected();
							break;

						// ----------------------------------------------------------------
						case POPUP_MENU_BRING_TO_TOP:
							TheEditor->bringSelectedToTop();
							break;

						// ----------------------------------------------------------------
						case POPUP_MENU_PROPERTIES:
							if( window )
								InitPropertiesDialog( window, pos.x, pos.y );
							break;

					}  // end switch

					break;

				}  // end new window

			}  // end switch on control id

			return 0;

		}  // end command

		// ------------------------------------------------------------------------
		default:
		{
			
			break;

		}  // end default

	}  // end switch( message )

	return DefWindowProc( hWnd, message, wParam, lParam );

}  // end editProc

// EditWindow::registerEditWindowClass ========================================
/** Register a class with the windows OS for an edit window */
//=============================================================================
void EditWindow::registerEditWindowClass( void )
{
	WNDCLASSEX wcex;
	ATOM atom;
	HINSTANCE hInst = TheEditor->getInstance();

	wcex.cbSize = sizeof( WNDCLASSEX ); 

	wcex.style					= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc		= (WNDPROC)editProc;
	wcex.cbClsExtra			= 0;
	wcex.cbWndExtra			= 0;
	wcex.hInstance			= hInst;
	wcex.hIcon					= LoadIcon( hInst, (LPCTSTR)IDI_GUIEDIT );
	wcex.hCursor				= NULL;  //LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)GetStockObject( BLACK_BRUSH );
	wcex.lpszMenuName		=	NULL;
	wcex.lpszClassName	= m_className;
	wcex.hIconSm				= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

	atom = RegisterClassEx( &wcex );
	
	// if successfully registered we don't ever need to do this again
	if( atom != 0 )
		m_classRegistered = TRUE;

}  // end registerEditWindowClass

///////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

// EditWindow::EditWindow =====================================================
/** */
//=============================================================================
EditWindow::EditWindow( void )
{

	m_pulse = 0;
	m_size.x = 0;
	m_size.y = 0;
	m_bitDepth = 32;
	m_editWindowHWnd = NULL;
	m_assetManager = NULL;
	m_2DRender = NULL;
	m_w3dInitialized = FALSE;

	m_popupMenuClickPos.x = 0;
	m_popupMenuClickPos.y = 0;

	m_pickedWindow = NULL;

	m_dragMoveOrigin.x = 0;
	m_dragMoveOrigin.y = 0;
	m_dragMoveDest.x = 0;
	m_dragMoveDest.y = 0;

	m_dragSelecting = FALSE;
	m_selectRegion.lo.x = 0;
	m_selectRegion.lo.y = 0;
	m_selectRegion.hi.x = 0;
	m_selectRegion.hi.y = 0;

	m_resizingWindow = FALSE;
	m_windowToResize = NULL;
	m_resizeOrigin.x = 0;
	m_resizeOrigin.y = 0;
	m_resizeDest.x = 0;
	m_resizeDest.y = 0;

	m_backgroundColor.red   = 0.0f;
	m_backgroundColor.green = 0.3f;
	m_backgroundColor.blue  = 0.3f;
	m_backgroundColor.alpha = 1.0f;

	m_clipRegion.lo.x = 0;
	m_clipRegion.lo.y = 0;
	m_clipRegion.hi.x = 0;
	m_clipRegion.hi.y = 0;
	m_isClippedEnabled = FALSE;

}  // end EditWindow

// EditWindow::~EditWindow ====================================================
/** */
//=============================================================================
EditWindow::~EditWindow( void )
{

	// call the shutdown
	shutdown();

}  // end ~EditWindow

// EditWindow::init ===========================================================
/** Initialize the edit window */
//=============================================================================
void EditWindow::init( UnsignedInt clientWidth, UnsignedInt clientHeight )
{
	UnsignedInt windowStyle = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER | WS_CAPTION;
	UnsignedInt extendedWindowStyle = 0;
	ICoord2D size;

	// register an edit window class with windows if not already done
	if( m_classRegistered == FALSE )
		registerEditWindowClass();

	// create 2D renderer
	m_2DRender = new Render2DClass;

	// save width and height
	size.x = clientWidth;
	size.y = clientHeight;
	setSize( &size );

	//
	// we want a client area the specified width and height, figure out how
	// big our window rectangle needs to be in order to have a client are
	// of that size
	//
	RECT clientRect;
	clientRect.left = 0;
	clientRect.top = 0;
	clientRect.right = m_size.x;
	clientRect.bottom = m_size.y;
	AdjustWindowRect( &clientRect, windowStyle, FALSE );

	// create the window
	m_editWindowHWnd = CreateWindowEx( extendedWindowStyle,  // extended window style
																		 m_className,  // class name
																		 "Edit Window",  // window name
																		 windowStyle,  // style bits
																		 0,  // x location
																		 0,  // y location
																		 clientRect.right - clientRect.left,  // width
																		 clientRect.bottom - clientRect.top,  // height,
																		 TheEditor->getWindowHandle(),  // parent
																		 NULL,  // menu
																		 TheEditor->getInstance(),  // instance
																		 NULL );  // creation parameters

	// display the window
	ShowWindow( m_editWindowHWnd, SW_SHOW );

	// create the file system for our asset file locations
	TheW3DFileSystem = new W3DFileSystem;  // our own file system for asset locations

	// initialize W3D
	WWMath::Init();
	WW3D::Init( m_editWindowHWnd );
	WW3D::Set_Screen_UV_Bias( TRUE );  ///< this makes text look good :)
	if( WW3D::Set_Render_Device( 0,
															 m_size.x,
															 m_size.y,
															 m_bitDepth,
															 TRUE ) != WW3D_ERROR_OK )
	{

		assert( 0 );
		shutdown();
		return;

	}  // end if

	// create asset manager
	m_assetManager = new WW3DAssetManager;
	assert( m_assetManager );
	m_assetManager->Set_WW3D_Load_On_Demand( true );

	// W3D is now initialized
	m_w3dInitialized = TRUE;

	// set a timer for updating visual pulse drawing
	SetTimer( m_editWindowHWnd, TIMER_EDIT_WINDOW_PULSE, 5, NULL );

}  // end init

// EditWindow::shutdown =======================================================
/** Shutdown edit window */
//=============================================================================
void EditWindow::shutdown( void )
{

	// delete 2d renderer
	delete m_2DRender;
	m_2DRender = NULL;

	// delete asset manager
	m_assetManager->Free_Assets();
	delete m_assetManager;

	// shutdown WW3D
	WW3D::Shutdown();
	WWMath::Shutdown();

	// delete the w3d file system
	delete TheW3DFileSystem;
	TheW3DFileSystem = NULL;

	// destroy the edit window
	if( m_editWindowHWnd )
		DestroyWindow( m_editWindowHWnd );
	m_editWindowHWnd = NULL;

	// unregister our edit window class
	UnregisterClass( m_className, TheEditor->getInstance() );
	m_classRegistered = FALSE;

}  // EditWindowShutdown

// EditWindow::updatePulse ====================================================
/** Update pulse from timer message */
//=============================================================================
void EditWindow::updatePulse( void )
{
	static Bool dir = 1;
	static Int stepSize = 4;
	static Int pulseMax = 175,
						 pulseMin = 75;

	// this is used for drawing pusling lines for moving stuff
	if( dir == 1 )
	{
		m_pulse += stepSize;
		if( m_pulse >= pulseMax )
			dir = 0;
	}  // end if
	else
	{
		m_pulse -= stepSize;
		if( m_pulse <= pulseMin )
			dir = 1;
	}  // end else

}  // end updatePulse

// EditWindow::mouseEvent =====================================================
/** A mouse event has occurred from our window procedure */
//=============================================================================
void EditWindow::mouseEvent( UnsignedInt windowsMessage,
														 WPARAM wParam, LPARAM lParam )
{
	Int x = LOWORD( lParam );
	Int y = HIWORD( lParam );
	Bool controlDown = BitTest( GetKeyState( VK_CONTROL ), 0x1000 );
	ICoord2D mouse;

	// setup mouse in nice struct
	mouse.x = x;
	mouse.y = y;

	// for mouse move messges always update the status bar
	if( windowsMessage == WM_MOUSEMOVE )
	{
		char buffer[ 64 ];
		ICoord2D mousePrint;

		// only print mouse positions in the edit window
		mousePrint.x = x;
		mousePrint.y = y;
		if( mousePrint.x < 0 )
			mousePrint.x = 0;
		if( mousePrint.x > m_size.x )
			mousePrint.x = m_size.x;
		if( mousePrint.y < 0 )
			mousePrint.y = 0;
		if( mousePrint.y > m_size.y )
			mousePrint.y = m_size.y;

		sprintf( buffer, "Mouse Location (X = %d, Y = %d)", 
						 mousePrint.x, mousePrint.y );
		TheEditor->statusMessage( STATUS_MOUSE_COORDS, buffer );

		// keep focus in our app
		if( GetFocus() != TheEditor->getWindowHandle() )
			SetFocus( TheEditor->getWindowHandle() );

	}  // end if

	//
	// if we're in test mode just pump all input through to the 
	// window system so we can see how everything acts
	//
	if( TheEditor->getMode() == MODE_TEST_RUN )
	{
		if( TheWin32Mouse )
			TheWin32Mouse->addWin32Event( windowsMessage, wParam, lParam, NO_TIME_FROM_WINDOWS);
		
		return;

	}  // end if

	//
	// If we're in the keyboard move, ignore the mouse
	//
	if (TheEditor->getMode() == MODE_KEYBOARD_MOVE)
		return;

	// do logic for each of the mouse messages
	switch( windowsMessage )
	{

		// ------------------------------------------------------------------------
		case WM_MOUSEMOVE:
		{

			//
			// this is really stupid, but the tree controls just don't
			// give enough hooks into all the events we need ... it's possible
			// to be in drag and drop mode due to menus opening up and the 
			// user clicking on blank area etc.  So if the mouse is in the
			// the edit window just make sure all our drag and drop stuff is
			// clear in the hierarchy
			//
			TheHierarchyView->setDragWindow( NULL );
			TheHierarchyView->setDragTarget( NULL );
			TheHierarchyView->setPopupTarget( NULL );

			if( TheEditor->getMode() == MODE_DRAG_MOVE )
			{

				// update destination for drag move
				m_dragMoveDest = mouse;

			}  // end if
			else if( m_dragSelecting )
			{

				// update drag selection region
				m_selectRegion.hi.x = x;
				m_selectRegion.hi.y = y;

			}  // end else if
			else if( m_resizingWindow )
			{

					// save the position of our mouse for resizing
					m_resizeDest = mouse;

			}  // end else if
			else
			{

				//
				// if we have ONE window selected and are close to an anchor corner
				// to resize it change the cursor to resize cursor
				//
				TheEditWindow->handleResizeAvailable( x, y );

			}  // end else

			break;

		}  // end mouse move

		// ------------------------------------------------------------------------
		case WM_LBUTTONDOWN:
		{

			//
			// if we're in drag move mode ignore this command ... usually this
			// doesn't happen cause you usually get into drag move mode by pressing
			// down, holding down, and dragging ... but it's possible to move
			// windows via the hierarchy view for those hard to reach windows
			//
			if( TheEditor->getMode() == MODE_DRAG_MOVE &&
					TheEditor->selectionCount() == 1 &&
					TheHierarchyView->getPopupTarget() != NULL )
				break;

			//
			// if we are in one of the resize modes then this click will
			// resize the window selected 
			//
			if( TheEditor->getMode() == MODE_RESIZE_TOP_LEFT ||
					TheEditor->getMode() == MODE_RESIZE_BOTTOM_RIGHT ||
					TheEditor->getMode() == MODE_RESIZE_TOP_RIGHT ||
					TheEditor->getMode() == MODE_RESIZE_BOTTOM_LEFT ||
					TheEditor->getMode() == MODE_RESIZE_TOP ||
					TheEditor->getMode() == MODE_RESIZE_BOTTOM ||
					TheEditor->getMode() == MODE_RESIZE_RIGHT ||
					TheEditor->getMode() == MODE_RESIZE_LEFT )
			{

				// mouse movements will now resize the window in the selection list
				m_windowToResize = TheEditor->getFirstSelected();
				if( m_windowToResize )
					m_resizingWindow = TRUE;

				// save our mouse position for the resizing process
				m_resizeOrigin = mouse;
				m_resizeDest = mouse;

			}  // end if
			else
			{
				GameWindow *window = TheEditor->getWindowAtPos( x, y );
				if( window )
				{

					//
					// if this window is not selected, then this window will become
					// the selected window instead of anything else that is selected.
					//
					if( TheEditor->isWindowSelected( window ) == FALSE )
					{

						//
						// if control key is not down we clear selections, otherwise
						// we will add this one to the select list
						//
						if( controlDown == FALSE )
							TheEditor->clearSelections();

						// select this window
						TheEditor->selectWindow( window );

					}  // end if
					else
					{

						//
						// this window is selected, if control is down we will
						// unselect this window
						//
						if( controlDown == TRUE )
						{
							TheEditor->unSelectWindow( window );
						}

						// only proceed into drag mode if we have something selected
						else if( TheEditor->isWindowSelected( window ) )
						{
							// set move locations
							m_dragMoveOrigin = mouse;
							m_dragMoveDest = mouse;

							// capture the mouse
							SetCapture( m_editWindowHWnd );

							// change to drag move mode and switch cursor
							TheEditor->setMode( MODE_DRAG_MOVE );

						}  // end if

					}  // end else


				}  // end if
				else
				{

					// start a drag selection box
					m_dragSelecting = TRUE;
					m_selectRegion.lo.x = x;
					m_selectRegion.lo.y = y;
					m_selectRegion.hi.x = x;
					m_selectRegion.hi.y = y;

				}  // end else

			}  // end if

			break;

		}  // end left button down 

		// ------------------------------------------------------------------------
		case WM_LBUTTONUP:
		{

			// exit drag move mode
			if( TheEditor->getMode() == MODE_DRAG_MOVE )
			{

				// move the windows
				if ((m_dragMoveOrigin.x != m_dragMoveDest.x) || (m_dragMoveOrigin.y != m_dragMoveDest.y)) {
					TheEditor->dragMoveSelectedWindows( &m_dragMoveOrigin, &m_dragMoveDest );
				}
				// release capture
				SetCapture( NULL );

				// go back to normal mode
				TheEditor->setMode( MODE_EDIT );

			}  // end if
			else if( m_dragSelecting )
			{

				// select the windows in the region
				TheEditor->selectWindowsInRegion( &m_selectRegion );

				// stop a drag selection if in progress
				m_dragSelecting = FALSE;

			}  // end else
			else if( m_resizingWindow )
			{
				GameWindow *window = TheEditor->getFirstSelected();
				DEBUG_ASSERTCRASH(window, ("No window selected for resize!"));

				if (window)
				{
					ICoord2D resultLoc, resultSize;
					ICoord2D dest = m_resizeDest;

					// adjust resize dest by the grid if it's on
					if( TheEditor->isGridSnapOn() )
						TheEditor->gridSnapLocation( &dest, &dest );

					// compute the location to resize it at
					TheEditor->computeResizeLocation( TheEditor->getMode(),
																						window,
																						&m_resizeOrigin, &dest,
																						&resultLoc, &resultSize );

					// move the window
					TheEditor->moveWindowTo( window, resultLoc.x, resultLoc.y );

					// resize the window
					window->winSetSize( resultSize.x, resultSize.y );
				}
							
				// go back to normal
				m_resizingWindow = FALSE;
				TheEditor->setMode( MODE_EDIT );

			}  // end resizing window

			break;

		}  // end left button up

		// ------------------------------------------------------------------------
		case WM_MBUTTONDOWN:
		{

			break;

		}  // end middle button down

		// ------------------------------------------------------------------------
		case WM_MBUTTONUP:
		{

			break;

		}  // end middle button up

		// ------------------------------------------------------------------------
		case WM_RBUTTONDOWN:
		{
			ICoord2D clickPos = mouse;
			GameWindow *window;

			// adjust the mouse pos if we're on a grid
			if( TheEditor->isGridSnapOn() )
				TheEditor->gridSnapLocation( &mouse, &clickPos );

			// get the window at the click pos
			window = TheEditor->getWindowAtPos( clickPos.x, clickPos.y );
					
			//
			// if there is a window here and it is not part of the selection
			// list, everything else is unselected
			//
			if( window )
			{

				if( TheEditor->isWindowSelected( window ) == FALSE )
					TheEditor->clearSelections();

				// select this window
				TheEditor->selectWindow( window );

			}  // end if
			else
			{

				// no window here, clear selections anyway
				TheEditor->clearSelections();

			}  // end else
												
			// open right click menu
			TheEditWindow->openPopupMenu( clickPos.x, clickPos.y );

			break;

		}  // end right button down

		// ------------------------------------------------------------------------
		case WM_RBUTTONUP:
		{

			break;

		}  // end right button up

		// ------------------------------------------------------------------------
		default:
		{

			break;

		}  // end default

	}  // end switch on widnows message

}  // end mouseEvent

// EditWindow::inCornerTolerance ==============================================
/** If the 'dest' point is within 'tolerance' distance to the 'source'
	* point this returns TRUE */
//=============================================================================
Bool EditWindow::inCornerTolerance( ICoord2D *dest, ICoord2D *source,
																		Int tolerance )
{
	IRegion2D region;

	// sanity
	if( dest == NULL || source == NULL )
		return FALSE;

	/// @todo we should write PointInRegion() stuff again like it was in Nox

	// build the region around the source point
	region.lo.x = source->x - tolerance;
	region.lo.y = source->y - tolerance;
	region.hi.x = source->x + tolerance;
	region.hi.y = source->y + tolerance;

	// check if in region
	if( dest->x >= region.lo.x &&
			dest->x <= region.hi.x &&
			dest->y >= region.lo.y &&
			dest->y <= region.hi.y )
		return TRUE;
		
	return FALSE;
		
}  // end inCornerTolerance

// EditWindow::inLineTolerance ================================================
/** If the 'dest' point is within the region defined around the
	* line with th specified tolerance return TRUE */
//=============================================================================
Bool EditWindow::inLineTolerance( ICoord2D *dest,
																	ICoord2D *lineStart, ICoord2D *lineEnd,
																	Int tolerance )
{
	IRegion2D region;

	// sanity
	if( dest == NULL || lineStart == NULL || lineEnd == NULL )	
		return FALSE;

	// setup region
	region.lo.x = lineStart->x - tolerance;
	region.lo.y = lineStart->y - tolerance;
	region.hi.x = lineEnd->x + tolerance;
	region.hi.y = lineEnd->y + tolerance;

	// check if in region
	if( dest->x >= region.lo.x &&
			dest->x <= region.hi.x &&
			dest->y >= region.lo.y &&
			dest->y <= region.hi.y )
		return TRUE;
		
	return FALSE;

}  // end inLineTolerance

// EditWindow::handleResizeAvailable ==========================================
/** Given the mouse position, if it is close enough to a corner of a
	* SINGLE selected window then we change the icon to the appropriate
	* resize icon.  If the mouse is not moved from this position then
	* the next left click will allow for a resize of the window */
//=============================================================================
void EditWindow::handleResizeAvailable( Int mouseX, Int mouseY )
{
	GameWindow *window;
	ICoord2D origin, size, mouse, point;
	const Int tol = 5;
		
	// if there is zero or more than 1 window selected we can't resize
	if( TheEditor->selectionCount() != 1 )
		return;

	// get mouse data in a nice coord 2d
	mouse.x = mouseX;
	mouse.y = mouseY;

	// get the selected window data
	window = TheEditor->getFirstSelected();
	window->winGetScreenPosition( &origin.x, &origin.y );
	window->winGetSize( &size.x, &size.y );
		
	// check for around top left corner
	point = origin;
	if( inCornerTolerance( &mouse, &point, tol ) == TRUE )
	{

		TheEditor->setMode( MODE_RESIZE_TOP_LEFT );
		return;

	}  // end if

	// check for around bottom right corner
	point.x = origin.x + size.x;
	point.y = origin.y + size.y;
	if( inCornerTolerance( &mouse, &point, tol ) == TRUE )
	{

		TheEditor->setMode( MODE_RESIZE_BOTTOM_RIGHT );
		return;

	}  // end if

	// check for around top right corner
	point.x = origin.x + size.x;
	point.y = origin.y;
	if( inCornerTolerance( &mouse, &point, tol ) == TRUE )
	{
		
		TheEditor->setMode( MODE_RESIZE_TOP_RIGHT );
		return;

	}  // end if

	// check for around bottom left corner
	point.x = origin.x;
	point.y = origin.y + size.y;
	if( inCornerTolerance( &mouse, &point, tol ) == TRUE )
	{

		TheEditor->setMode( MODE_RESIZE_BOTTOM_LEFT );
		return;

	}  // end if

	ICoord2D lineStart, lineEnd;

	// check for along top edge
	lineStart = origin;
	lineEnd.x = origin.x + size.x;
	lineEnd.y = origin.y;
	if( inLineTolerance( &mouse, &lineStart, &lineEnd, tol ) == TRUE )
	{

		TheEditor->setMode( MODE_RESIZE_TOP );
		return;

	}  // end if

	// check for along bottom edge
	lineStart.x = origin.x;
	lineStart.y = origin.y + size.y;
	lineEnd.x = origin.x + size.x;
	lineEnd.y = origin.y + size.y;
	if( inLineTolerance( &mouse, &lineStart, &lineEnd, tol ) == TRUE )
	{

		TheEditor->setMode( MODE_RESIZE_BOTTOM );
		return;

	}  // end if

	// check for along left edge
	lineStart = origin;
	lineEnd.x = origin.x;
	lineEnd.y = origin.y + size.y;
	if( inLineTolerance( &mouse, &lineStart, &lineEnd, tol ) == TRUE )
	{

		TheEditor->setMode( MODE_RESIZE_LEFT );
		return;

	}  // end if

	// check for along right edge
	lineStart.x = origin.x + size.x;
	lineStart.y = origin.y;
	lineEnd.x = origin.x + size.x;
	lineEnd.y = origin.y + size.y;
	if( inLineTolerance( &mouse, &lineStart, &lineEnd, tol ) == TRUE )
	{

		TheEditor->setMode( MODE_RESIZE_RIGHT );
		return;

	}  // end if

	// we are not resizing anything at all, set us to normal mode
	TheEditor->setMode( MODE_EDIT );

}  // end handleResizeAvailable

// EditWindow::drawSeeThruOutlines ============================================
/** Draw an outline for a window that is see thru so we can still work
	* with it in the editor */
//=============================================================================
void EditWindow::drawSeeThruOutlines( GameWindow *windowList, Color c )
{

	// end recursion
	if( windowList == NULL )
		return;

	// draw outline for this window
	if( BitTest( windowList->winGetStatus(), WIN_STATUS_SEE_THRU ) )
	{
		ICoord2D pos;
		ICoord2D size;

		// get position and size
		windowList->winGetScreenPosition( &pos.x, &pos.y );
		windowList->winGetSize( &size.x, &size.y );

		// draw a box on the window
		drawOpenRect( pos.x, pos.y, size.x, size.y, 1, c );

	}  // end if

	// check window children
	GameWindow *child;
	for( child = windowList->winGetChild(); child; child = child->winGetNext() )
		drawSeeThruOutlines( child, c );

	// go to siblings
	drawSeeThruOutlines( windowList->winGetNext(), c );

}  // end drawSeeThruOutlines

// EditWindow::drawHiddenOutlines =============================================
/** Draw an outline for a window that is hidden so we can still work
	* with it in the editor */
//=============================================================================
void EditWindow::drawHiddenOutlines( GameWindow *windowList, Color c )
{

	// end recursion
	if( windowList == NULL )
		return;

	//
	// draw outline for this window, we are hidden if we have the hidden
	// status or any of our parents are hidden
	//
	Bool hidden = FALSE;
	GameWindow *parent= windowList->winGetParent();
	while( parent )
	{

		if( BitTest( parent->winGetStatus(), WIN_STATUS_HIDDEN ) )
			hidden = TRUE;
		parent = parent->winGetParent();

	}  // end while
	if( BitTest( windowList->winGetStatus(), WIN_STATUS_HIDDEN ) )
		hidden = TRUE;
	if( hidden )
	{
		ICoord2D pos;
		ICoord2D size;

		// get position and size
		windowList->winGetScreenPosition( &pos.x, &pos.y );
		windowList->winGetSize( &size.x, &size.y );

		// draw a box on the window
		drawOpenRect( pos.x, pos.y, size.x, size.y, 2, c );

	}  // end if

	// check window children
	GameWindow *child;
	for( child = windowList->winGetChild(); child; child = child->winGetNext() )
		drawHiddenOutlines( child, c );

	// go to siblings
	drawHiddenOutlines( windowList->winGetNext(), c );

}  // end drawHiddenOutlines

// EditWindow::drawUIback =====================================================
/** Draw any visual feedback to the user about selection boxes or windows
	* that are selected, draggin windows etc */
//=============================================================================
void EditWindow::drawUIFeedback( void )
{
	WindowSelectionEntry *select;
	Int color = m_pulse * 2;

	if( color > 255 )
		color = 255;

	// draw hidden window outlines if requested
	if( TheEditor->getShowHiddenOutlines() )
		drawHiddenOutlines( TheWindowManager->winGetWindowList(),
												GameMakeColor( color, 64, 64, 255 ) );

	// draw see-thru window outlines if requested
	if( TheEditor->getShowSeeThruOutlines() )
		drawSeeThruOutlines( TheWindowManager->winGetWindowList(),
												 GameMakeColor( 64, 64, color, 255 ) );

	// if the grid is visible draw it on top of everything
	if( TheEditor->isGridVisible() == TRUE )
		drawGrid();

	// draw drag selection box
	if( m_dragSelecting )
	{
		Int width, height;
		Real selectBoxWidth = 2.0f;
		Color selectBoxColor = GameMakeColor( 0, 255, 0, 255 );

		width = m_selectRegion.hi.x - m_selectRegion.lo.x;
		height = m_selectRegion.hi.y - m_selectRegion.lo.y;
		drawOpenRect( m_selectRegion.lo.x, m_selectRegion.lo.y,
		              width, height, selectBoxWidth, selectBoxColor );

	}  // end if

	// draw select lines on selected windows
	select = TheEditor->getSelectList();
	while( select )
	{
		ICoord2D origin, size;
		GameWindow *window;
		Real windowSelectWidth = 2.0f;
		Color windowSelectColor;
		
		windowSelectColor = GameMakeColor( 0, color, 0, 255 );

		// get window properties
		window = select->window;
		window->winGetScreenPosition( &origin.x, &origin.y );
		window->winGetSize( &size.x, &size.y );

		// draw a box on the window
		drawOpenRect( origin.x, origin.y, size.x, size.y, 
									windowSelectWidth, windowSelectColor );		

		// go to next selection
		select = select->next;

	}  // end while

	//
	// if we're drag moving, draw outlines of all the windows in the
	// select list offset by the start to end of the drag move
	//
	if( TheEditor->getMode() == MODE_DRAG_MOVE || TheEditor->getMode() == MODE_KEYBOARD_MOVE )
	{
		ICoord2D origin, size;
		ICoord2D moveLoc, safeLoc;
		GameWindow *window, *parent;
		Real outlineWidth = 1.0f;
		Color outlineColor;

		// determine outline using pulse counter
		outlineColor = GameMakeColor( m_pulse, m_pulse, m_pulse + 25, 255 );

		// traverse selection list
		select = TheEditor->getSelectList();
		while( select )
		{

			// get window data
			window = select->window;
			window->winGetScreenPosition( &origin.x, &origin.y );
			window->winGetSize( &size.x, &size.y );

			// figure out the destination of the window from this move
 			ICoord2D change;
 			change.x = (m_dragMoveDest.x - m_dragMoveOrigin.x);
 			change.y = (m_dragMoveDest.y - m_dragMoveOrigin.y);
 
 		// [SKB: Jun 02 2003 @ 2:7pm] :
 		// Don't move the object unless we have moved the mouse,
 		// this is to avoid the irritating movement of a window when just
 		// clicking on a window.
 			if (change.x || change.y)
 			{
 				moveLoc.x = origin.x + change.x;
 				moveLoc.y = origin.y + change.y;

				// snap move location to grid if on
 				if( (TheEditor->getMode() == MODE_DRAG_MOVE) && TheEditor->isGridSnapOn() )
					TheEditor->gridSnapLocation( &moveLoc, &moveLoc );


				// keep location legal
 				TheEditor->computeSafeLocation( window, moveLoc.x, moveLoc.y, 
																				&safeLoc.x, &safeLoc.y );

				// adjust location by parent location if present
				parent = window->winGetParent();
				if( parent )
				{
					ICoord2D parentOrigin;

					parent->winGetScreenPosition( &parentOrigin.x, &parentOrigin.y );
					safeLoc.x += parentOrigin.x;
					safeLoc.y += parentOrigin.y;

				}  // end if

				// draw outline of window at what would be the drag move destination
				drawOpenRect( safeLoc.x, safeLoc.y, size.x, size.y, 
											outlineWidth, outlineColor );
			}

			// go to next selection
			select = select->next;

		}  // end while

	}  // end if

	// if resizing a window draw that resize representation
	if( m_resizingWindow )
	{
		GameWindow *window = m_windowToResize;
		ICoord2D loc, size;
		Color outlineColor;
		Real outlineWidth = 1.0f;
		GameWindow *parent;
		ICoord2D dest = m_resizeDest;

		// adjust resize dest by the grid if it's on
		if( TheEditor->isGridSnapOn() )
			TheEditor->gridSnapLocation( &dest, &dest );

		//
		// given the location that we started dragging at and the destination
		// drag location along with the mode of resizing compute what the
		// new location and the new size of the selected window to resize
		//
		TheEditor->computeResizeLocation( TheEditor->getMode(),
																		  window,
																		  &m_resizeOrigin, &dest,
																		  &loc, &size );

		// adjust location by parent location if present
		parent = window->winGetParent();
		if( parent )
		{
			ICoord2D parentOrigin;

			parent->winGetScreenPosition( &parentOrigin.x, &parentOrigin.y );
			loc.x += parentOrigin.x;
			loc.y += parentOrigin.y;

		}  // end if

		// draw a box for the window at its new location
		outlineColor = GameMakeColor( m_pulse, m_pulse, m_pulse, 255 );
		drawOpenRect( loc.x, loc.y, size.x, size.y, outlineWidth, outlineColor );

	}  // end if

	// draw lines around any drag source and drag targets in the hierarchy view
	GameWindow *dragSource = TheHierarchyView->getDragWindow();
	Color dragColor = GameMakeColor( color, 0, color, 255 );
	if( dragSource )
	{
		ICoord2D origin, size;

		// get size and position
		dragSource->winGetScreenPosition( &origin.x, &origin.y );
		dragSource->winGetSize( &size.x, &size.y );

		// draw box
		drawOpenRect( origin.x, origin.y, size.x, size.y, 2, dragColor );

	}  // end if

	// drag target
	GameWindow *dragTarget = TheHierarchyView->getDragTarget();
	if( dragTarget )
	{
		ICoord2D origin, size;
		
		// get size and position
		dragTarget->winGetScreenPosition( &origin.x, &origin.y );
		dragTarget->winGetSize( &size.x, &size.y );

		// draw box
		drawOpenRect( origin.x, origin.y, size.x, size.y, 2, dragColor );

	}  // end if

}  // end drawUIFeedback

// EditWindow::drawGrid =======================================================
/** Draw the grid */
//=============================================================================
void EditWindow::drawGrid( void )
{
//	HDC hdc = GetDC( getWindowHandle() );
	Int res = TheEditor->getGridResolution();
	Int x, y;
	RGBColorInt *gridColor = TheEditor->getGridColor();
	Color color = GameMakeColor( gridColor->red, gridColor->green,	
															 gridColor->blue, gridColor->alpha );

	// set us to invert where we draw
//	SetROP2( hdc, R2_NOT );
//	SelectObject( hdc, (HPEN)GetStockObject( WHITE_PEN ) );

	for( y = 0; y < m_size.y; y += res )
	{

		TheDisplay->drawLine( 0, y, m_size.x, y, 1, color );
//		MoveToEx( hdc, 0, y, NULL );
//		LineTo( hdc, m_size.x, y );

	} 

	for( x = 0; x < m_size.x; x += res )
	{

		TheDisplay->drawLine( x, 0, x, m_size.y, 1, color );
//		MoveToEx( hdc, x, 0, NULL );
//		LineTo( hdc, x, m_size.y );

	} 

/*
	for( y = 0; y < m_size.y; y += res )
	{

		for( x = 0; x < m_size.x; x += res )
		{

			MoveToEx( hdc, x, y, NULL );
			LineTo( hdc, x + 1, y + 1 );

//				TheDisplay->drawLine( x, y, x + 1, y + 1, 1, 0xFFFFFFFF );

		}  // end for x

	}  // end for y
*/

	// release the dc
//	ReleaseDC( getWindowHandle(), hdc );

}  // end drawGrid

// EditWindow::draw ===========================================================
/** Draw the edit window */
//=============================================================================
void EditWindow::draw( void )
{
	static UnsignedInt syncTime = 0;

	// allow W3D to update its internals
	WW3D::Sync( syncTime );

	// for now, use constant time steps to avoid animations running independent of framerate
	syncTime += 50;

	// start render block
	WW3D::Begin_Render( true, true, Vector3( m_backgroundColor.red, 
																					 m_backgroundColor.green, 
																					 m_backgroundColor.blue ) );

	// draw the windows
	TheWindowManager->winRepaint();

	// draw selected drag box and any window selection boxes
	if( TheEditor->getMode() != MODE_TEST_RUN )
		drawUIFeedback();

	// render is all done!
	WW3D::End_Render();

}  // end draw

// EditWindow::setSize ========================================================
/** The edit window should now be logically consider this size */
//=============================================================================
void EditWindow::setSize( ICoord2D *size )
{

	// save the size
	m_size = *size;

	// the display should reflect the new size as well
	if( TheDisplay )
	{

		TheDisplay->setWidth( m_size.x );
		TheDisplay->setHeight( m_size.y );

	}  // end if

	// set the extents for our 2D renderer
	if( m_2DRender )
		m_2DRender->Set_Coordinate_Range( RectClass( 0,
																								 0,
																								 m_size.x,
																								 m_size.y ) );

}  // end setSize

// EditWindow::openPopupMenu ==================================================
/** Open the new control menu that comes up when the user right clicks
	* in the workspace to create new controls */
//=============================================================================
void EditWindow::openPopupMenu( Int x, Int y )
{
	HMENU menu, subMenu;
	POINT screen;
	Int selectCount = TheEditor->selectionCount();

	// get the menu with the new control items
	menu = LoadMenu( TheEditor->getInstance(), (LPCTSTR)POPUP_MENU );
	subMenu = GetSubMenu( menu, 0 );

	// enable/disable menu items
	if( selectCount == 0 )
	{

		EnableMenuItem( subMenu, POPUP_MENU_DELETE, MF_GRAYED );
		EnableMenuItem( subMenu, POPUP_MENU_PROPERTIES, MF_GRAYED );
		EnableMenuItem( subMenu, POPUP_MENU_BRING_TO_TOP, MF_GRAYED );

	}  // end if
	else
	{

		EnableMenuItem( subMenu, POPUP_MENU_DELETE, MF_ENABLED );
		EnableMenuItem( subMenu, POPUP_MENU_PROPERTIES, MF_ENABLED );
		EnableMenuItem( subMenu, POPUP_MENU_BRING_TO_TOP, MF_ENABLED );

	}  // end else
	
	//
	// open up right mouse track menu, note that we have to translate the
	// x,y of this mouse click which is local to this window into
	// screen coordinates
	//
	screen.x = x;
	screen.y = y;
	ClientToScreen( m_editWindowHWnd, &screen );
	TrackPopupMenuEx( subMenu, 0, screen.x, screen.y, m_editWindowHWnd, NULL );

	// save the location click for the creation of the popup menu
	m_popupMenuClickPos.x = x;
	m_popupMenuClickPos.y = y;

}  // end openPopupMenu

// EditWindow::drawLine =======================================================
/** draw a line on the display in pixel coordinates with the specified color */
//=============================================================================
void EditWindow::drawLine( Int startX, Int startY, 
													 Int endX, Int endY, 
													 Real lineWidth, UnsignedInt lineColor )
{

	m_2DRender->Reset();
	m_2DRender->Enable_Texturing( FALSE );
	m_2DRender->Add_Line( Vector2( startX, startY ), Vector2( endX, endY ), 
												lineWidth, lineColor );
	m_2DRender->Render();
	
}  // end drawLIne

// EditWindow::drawOpenRect ===================================================
/** draw a rect border on the display in pixel coordinates with the 
	* specified color */
//=============================================================================
void EditWindow::drawOpenRect( Int startX, Int startY, 
															 Int width, Int height,
															 Real lineWidth, UnsignedInt lineColor )
{

	m_2DRender->Reset();		
	m_2DRender->Enable_Texturing( FALSE );
	m_2DRender->Add_Outline( RectClass( startX, startY, 
																			startX + width, startY + height ), 
													 lineWidth, lineColor );

	// render it now!
	m_2DRender->Render();

}  // end drawOpenRect

// EditWindow::drawFillRect ===================================================
/** draw a filled rect on the display in pixel coords with the 
	* specified color */
//=============================================================================
void EditWindow::drawFillRect( Int startX, Int startY, 
															 Int width, Int height,
															 UnsignedInt color )
{

	m_2DRender->Reset();		
	m_2DRender->Enable_Texturing( FALSE );
	m_2DRender->Add_Rect( RectClass( startX, startY, 
																	 startX + width, startY + height ), 
												0, 0, color );

	// render it now!
	m_2DRender->Render();

}  // end drawFillRect

// EditWindow::drawImage ======================================================
/** draw an image fit within the screen coordinates */
//=============================================================================
void EditWindow::drawImage( const Image *image, 
														Int startX, Int startY, 
														Int endX, Int endY,
														Color color )
{

	// sanity
	if( image == NULL )
		return;

	const Region2D *uv = image->getUV();

	m_2DRender->Reset();
	m_2DRender->Enable_Texturing( TRUE );
	m_2DRender->Set_Texture( image->getFilename().str() );

	RectClass screen_rect(startX,startY,endX,endY);
	RectClass uv_rect(uv->lo.x,uv->lo.y,uv->hi.x,uv->hi.y);

	if (m_isClippedEnabled)
	{	//need to clip this quad to clip rectangle

		//
		//	Check for completely clipped
		//
		if (	endX <= m_clipRegion.lo.x ||
				endY <= m_clipRegion.lo.y)
		{
			return;	//nothing to render
		} else {

			//
			//	Clip the polygons to the specified area
			//
			RectClass clipped_rect;
			clipped_rect.Left		= __max (screen_rect.Left, m_clipRegion.lo.x);
			clipped_rect.Right	= __min (screen_rect.Right, m_clipRegion.hi.x);
			clipped_rect.Top		= __max (screen_rect.Top, m_clipRegion.lo.y);
			clipped_rect.Bottom	= __min (screen_rect.Bottom, m_clipRegion.hi.y);

			//
			//	Clip the texture to the specified area
			//
			RectClass clipped_uv_rect;
			float percent				= ((clipped_rect.Left - screen_rect.Left) / screen_rect.Width ());
			clipped_uv_rect.Left		= uv_rect.Left + (uv_rect.Width () * percent);

			percent						= ((clipped_rect.Right - screen_rect.Left) / screen_rect.Width ());
			clipped_uv_rect.Right	= uv_rect.Left + (uv_rect.Width () * percent);

			percent						= ((clipped_rect.Top - screen_rect.Top) / screen_rect.Height ());
			clipped_uv_rect.Top		= uv_rect.Top + (uv_rect.Height () * percent);

			percent						= ((clipped_rect.Bottom - screen_rect.Top) / screen_rect.Height ());
			clipped_uv_rect.Bottom	= uv_rect.Top + (uv_rect.Height () * percent);

			//
			//	Use the clipped rectangles to render
			//
			screen_rect = clipped_rect;
			uv_rect		= clipped_uv_rect;
		}
	}

	// if rotated 90 degrees clockwise we have to adjust the uv coords
	if( BitTest( image->getStatus(), IMAGE_STATUS_ROTATED_90_CLOCKWISE ) )
	{

		m_2DRender->Add_Tri( Vector2( screen_rect.Left, screen_rect.Top ), 
												 Vector2( screen_rect.Left, screen_rect.Bottom ),
												 Vector2( screen_rect.Right, screen_rect.Top ),
												 Vector2( uv_rect.Right, uv_rect.Top),
												 Vector2( uv_rect.Left, uv_rect.Top),
												 Vector2( uv_rect.Right, uv_rect.Bottom ),
												 color );

		m_2DRender->Add_Tri( Vector2( screen_rect.Right, screen_rect.Bottom ),
												 Vector2( screen_rect.Right, screen_rect.Top ),
												 Vector2( screen_rect.Left, screen_rect.Bottom ),
												 Vector2( uv_rect.Left, uv_rect.Bottom ),
												 Vector2( uv_rect.Right, uv_rect.Bottom ),
												 Vector2( uv_rect.Left, uv_rect.Top ),
												 color );

	}  // end if
	else
	{

		// just draw as normal
		m_2DRender->Add_Quad( screen_rect, uv_rect, color );

	}  // end else

	m_2DRender->Render();

}  // end drawImage

// EditWindow::getBackgroundColor =============================================
/** Get the background color for the edit window */
//=============================================================================
RGBColorReal EditWindow::getBackgroundColor( void )
{
	
	return m_backgroundColor;

}  // end getBackgroundColor

// EditWindow::setBackgroundColor =============================================
/** Set the background color for the edit window */
//=============================================================================
void EditWindow::setBackgroundColor( RGBColorReal color )
{

	m_backgroundColor = color;

}  // end setBackgroundColor

// EditWindow::notifyWindowDeleted ============================================
/** A window has been deleted from the editor and the editor is now
	* notifying the edit window about it in case anything must be
	* cleaned up */
//=============================================================================
void EditWindow::notifyWindowDeleted( GameWindow *window )
{

	// sanity
	if( window == NULL )
		return;

	// check to see if the resizing window was deleted
	if( m_windowToResize == window )
	{

		// get back to normal mode and clean up
		m_windowToResize = NULL;
		m_resizingWindow = FALSE;
		TheEditor->setMode( MODE_EDIT );

	}  // end if

	// null out picked window if needed
	if( m_pickedWindow == window )
		m_pickedWindow = NULL;

	//
	// go back to edit mode, this keeps us from staying in a resize mode
	// after deleting the window under the cursor
	//
	TheEditor->setMode( MODE_EDIT );

}  // end notifyWindowDeleted
