1315 lines
37 KiB
C++
1315 lines
37 KiB
C++
![]() |
/*
|
||
|
** 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: HierarchyView.cpp ////////////////////////////////////////////////////
|
||
|
//-----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Westwood Studios Pacific.
|
||
|
//
|
||
|
// Confidential Information
|
||
|
// Copyright (C) 2001 - All Rights Reserved
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Project: GUIEdit
|
||
|
//
|
||
|
// File name: HierarchyView.cpp
|
||
|
//
|
||
|
// Created: Colin Day, July 2001
|
||
|
//
|
||
|
// Desc: Manipulation the widows heirarchy through the tree
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||
|
#include <windows.h>
|
||
|
#include <commctrl.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||
|
#include "Common/Debug.h"
|
||
|
#include "GameClient/Gadget.h"
|
||
|
#include "Resource.h"
|
||
|
#include "HierarchyView.h"
|
||
|
#include "WinMain.h"
|
||
|
#include "GUIEdit.h"
|
||
|
#include "EditWindow.h"
|
||
|
#include "GUIEditWindowManager.h"
|
||
|
#include "Properties.h"
|
||
|
|
||
|
// DEFINES ////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// PRIVATE TYPES //////////////////////////////////////////////////////////////
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// PRIVATE DATA ///////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
static ICoord2D dialogPos;
|
||
|
static ICoord2D dialogSize;
|
||
|
|
||
|
|
||
|
// PUBLIC DATA ////////////////////////////////////////////////////////////////
|
||
|
HierarchyView *TheHierarchyView = NULL; ///< the view singleton
|
||
|
|
||
|
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// HierarchyView::dialogProc ==================================================
|
||
|
/** Windows dialog procedure for the control palette */
|
||
|
//=============================================================================
|
||
|
LRESULT CALLBACK HierarchyView::dialogProc( HWND hWndDialog, UINT message,
|
||
|
WPARAM wParam, LPARAM lParam )
|
||
|
{
|
||
|
|
||
|
switch( message )
|
||
|
{
|
||
|
|
||
|
// ------------------------------------------------------------------------
|
||
|
case WM_MOVE:
|
||
|
{
|
||
|
// Int x = LOWORD( lParam );
|
||
|
// Int y = HIWORD( lParam );
|
||
|
|
||
|
// record our position
|
||
|
RECT rect;
|
||
|
POINT p;
|
||
|
GetWindowRect( hWndDialog, &rect );
|
||
|
p.x = rect.left;
|
||
|
p.y = rect.top;
|
||
|
ScreenToClient( TheEditor->getWindowHandle(), &p );
|
||
|
dialogPos.x = p.x;
|
||
|
dialogPos.y = p.y;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
} // end move
|
||
|
|
||
|
// ------------------------------------------------------------------------
|
||
|
case WM_SIZE:
|
||
|
{
|
||
|
// Int sizeType = wParam; // resizing flag
|
||
|
Int width = LOWORD( lParam ); // width of client
|
||
|
Int height = HIWORD( lParam ); // height of client
|
||
|
|
||
|
// record the new height
|
||
|
RECT rect;
|
||
|
GetWindowRect( hWndDialog, &rect );
|
||
|
dialogSize.x = rect.right - rect.left;
|
||
|
dialogSize.y = rect.bottom - rect.top;
|
||
|
|
||
|
// resizing the dialog will cause us to resize the tree view control
|
||
|
if( TheHierarchyView )
|
||
|
{
|
||
|
HWND tree = TheHierarchyView->getTreeHandle();
|
||
|
|
||
|
if( tree )
|
||
|
{
|
||
|
Int border = 10;
|
||
|
RECT treeRect;
|
||
|
POINT p;
|
||
|
|
||
|
GetWindowRect( tree, &treeRect );
|
||
|
p.x = treeRect.left;
|
||
|
p.y = treeRect.top;
|
||
|
ScreenToClient( hWndDialog, &p );
|
||
|
MoveWindow( tree, border, p.y,
|
||
|
width - (border * 2), (height - border) - p.y,
|
||
|
TRUE );
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
} // end size
|
||
|
|
||
|
// ------------------------------------------------------------------------
|
||
|
case WM_MOUSEMOVE:
|
||
|
{
|
||
|
Int x = LOWORD( lParam );
|
||
|
Int y = HIWORD( lParam );
|
||
|
GameWindow *dragWindow = TheHierarchyView->getDragWindow();
|
||
|
|
||
|
// dragging a window then hilite any tree item we're over
|
||
|
if( dragWindow )
|
||
|
{
|
||
|
POINT treePoint;
|
||
|
|
||
|
// translate the mouse coords to the coords of the tree
|
||
|
treePoint.x = x;
|
||
|
treePoint.y = y;
|
||
|
ClientToScreen( hWndDialog, &treePoint );
|
||
|
ScreenToClient( TheHierarchyView->getTreeHandle(), &treePoint );
|
||
|
|
||
|
// get the tree item if any that we're over and select it if present
|
||
|
HTREEITEM overItem = TheHierarchyView->treePointToItem( treePoint.x, treePoint.y );
|
||
|
if( overItem )
|
||
|
{
|
||
|
GameWindow *target = TheHierarchyView->getWindowFromItem( overItem );
|
||
|
|
||
|
//
|
||
|
// set this window as the drag target, we use it to draw visual
|
||
|
// feeback in the edit window
|
||
|
//
|
||
|
TheHierarchyView->setDragTarget( target );
|
||
|
|
||
|
// select the item in the tree
|
||
|
TreeView_SelectItem( TheHierarchyView->getTreeHandle(), overItem );
|
||
|
|
||
|
//
|
||
|
// if this operation is legal set the cross cursor, otherwise
|
||
|
// use the "no" cursor
|
||
|
//
|
||
|
if( TheHierarchyView->validateDragDropOperation( dragWindow, target ) )
|
||
|
SetCursor( LoadCursor( NULL, IDC_CROSS ) );
|
||
|
else
|
||
|
SetCursor( LoadCursor( NULL, IDC_NO ) );
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
} // end mouse move
|
||
|
|
||
|
// ------------------------------------------------------------------------
|
||
|
case WM_LBUTTONUP:
|
||
|
{
|
||
|
Int x = LOWORD( lParam );
|
||
|
Int y = HIWORD( lParam );
|
||
|
GameWindow *dragWindow = TheHierarchyView->getDragWindow();
|
||
|
Bool clearDragWindow = TRUE;
|
||
|
|
||
|
if( dragWindow )
|
||
|
{
|
||
|
POINT treePoint;
|
||
|
|
||
|
// translate the mouse coords to the coords of the tree
|
||
|
treePoint.x = x;
|
||
|
treePoint.y = y;
|
||
|
ClientToScreen( hWndDialog, &treePoint );
|
||
|
ScreenToClient( TheHierarchyView->getTreeHandle(), &treePoint );
|
||
|
|
||
|
// get the tree item if any that we're over
|
||
|
HTREEITEM overItem = TheHierarchyView->treePointToItem( treePoint.x, treePoint.y );
|
||
|
if( overItem )
|
||
|
{
|
||
|
GameWindow *overWindow;
|
||
|
TVITEM overItemInfo;
|
||
|
|
||
|
// get the node info from the tree item we're over
|
||
|
overItemInfo.hItem = overItem;
|
||
|
overItemInfo.lParam = NULL;
|
||
|
overItemInfo.mask = TVIF_HANDLE | TVIF_PARAM;
|
||
|
TreeView_GetItem( TheHierarchyView->getTreeHandle(), &overItemInfo );
|
||
|
overWindow = (GameWindow *)overItemInfo.lParam;
|
||
|
|
||
|
// this should always be true!
|
||
|
assert( overWindow );
|
||
|
|
||
|
// do the drag drop if allowed
|
||
|
if( TheHierarchyView->validateDragDropOperation( dragWindow,
|
||
|
overWindow ) )
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// if our target window is NOT a gadget we have the option
|
||
|
// of moving the drag window to this position OR making the
|
||
|
// drag window a child of the target overWindow. If that is
|
||
|
// the case we need a little popup menu to decide
|
||
|
//
|
||
|
if( TheEditor->windowIsGadget( overWindow ) == FALSE )
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// bring up the popup menu, note that we must translate the
|
||
|
// local mouse pos to the screen
|
||
|
//
|
||
|
HMENU menu, subMenu;
|
||
|
POINT screen;
|
||
|
|
||
|
menu = LoadMenu( TheEditor->getInstance(), (LPCTSTR)HIERARCHY_DRAG_DROP_MENU );
|
||
|
subMenu = GetSubMenu( menu, 0 );
|
||
|
screen.x = x;
|
||
|
screen.y = y;
|
||
|
ClientToScreen( hWndDialog, &screen );
|
||
|
TrackPopupMenuEx( subMenu, 0, screen.x, screen.y, hWndDialog, NULL );
|
||
|
|
||
|
//
|
||
|
// do not reset the drag window, and set the target window as
|
||
|
// the popup target know which window to target after they
|
||
|
// select from the popup menu
|
||
|
//
|
||
|
clearDragWindow = FALSE;
|
||
|
TheHierarchyView->setPopupTarget( overWindow );
|
||
|
|
||
|
} // end if
|
||
|
else
|
||
|
{
|
||
|
|
||
|
// our only option is to move the window here
|
||
|
TheGUIEditWindowManager->moveAheadOf( dragWindow, overWindow );
|
||
|
|
||
|
} // end else
|
||
|
|
||
|
// we've made a change now
|
||
|
TheEditor->setUnsaved( TRUE );
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
// window has been dragged and operation complete
|
||
|
if( clearDragWindow )
|
||
|
{
|
||
|
|
||
|
TheHierarchyView->setDragWindow( NULL );
|
||
|
TheHierarchyView->setDragTarget( NULL );
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
// release window capture
|
||
|
ReleaseCapture();
|
||
|
|
||
|
// set the cursor back to normal
|
||
|
SetCursor( LoadCursor( NULL, IDC_ARROW ) );
|
||
|
|
||
|
} // end if, drag in progress
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
} // end left button up
|
||
|
|
||
|
// ------------------------------------------------------------------------
|
||
|
case WM_RBUTTONUP:
|
||
|
{
|
||
|
Int x = LOWORD( lParam );
|
||
|
Int y = HIWORD( lParam );
|
||
|
POINT treePoint;
|
||
|
|
||
|
// translate the mouse coords to the coords of the tree
|
||
|
treePoint.x = x;
|
||
|
treePoint.y = y;
|
||
|
ClientToScreen( hWndDialog, &treePoint );
|
||
|
ScreenToClient( TheHierarchyView->getTreeHandle(), &treePoint );
|
||
|
|
||
|
// get the tree item if any that we're over
|
||
|
HTREEITEM overItem = TheHierarchyView->treePointToItem( treePoint.x, treePoint.y );
|
||
|
if( overItem )
|
||
|
{
|
||
|
GameWindow *overWindow;
|
||
|
|
||
|
// get the game window from the tree item
|
||
|
overWindow = TheHierarchyView->getWindowFromItem( overItem );
|
||
|
|
||
|
// unselect all windows in the editor
|
||
|
TheEditor->clearSelections();
|
||
|
|
||
|
// select this one window
|
||
|
TheEditor->selectWindow( overWindow );
|
||
|
|
||
|
// set this window as the popup window target
|
||
|
TheHierarchyView->setPopupTarget( overWindow );
|
||
|
|
||
|
//
|
||
|
// bring up the popup menu, note that we must translate the
|
||
|
// local mouse pos to the screen
|
||
|
//
|
||
|
HMENU menu, subMenu;
|
||
|
POINT screen;
|
||
|
|
||
|
menu = LoadMenu( TheEditor->getInstance(), (LPCTSTR)HIERARCHY_POPUP_MENU );
|
||
|
subMenu = GetSubMenu( menu, 0 );
|
||
|
screen.x = x;
|
||
|
screen.y = y;
|
||
|
ClientToScreen( hWndDialog, &screen );
|
||
|
TrackPopupMenuEx( subMenu, 0, screen.x, screen.y, hWndDialog, NULL );
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
} // end right button up
|
||
|
|
||
|
// ------------------------------------------------------------------------
|
||
|
case WM_NOTIFY:
|
||
|
{
|
||
|
UnsignedInt controlID = (Int)wParam;
|
||
|
LPNMHDR notifyMessageHandler = (LPNMHDR)lParam;
|
||
|
|
||
|
// switch on control
|
||
|
switch( controlID )
|
||
|
{
|
||
|
|
||
|
// --------------------------------------------------------------------
|
||
|
case TREE_HIERARCHY:
|
||
|
{
|
||
|
|
||
|
// switch on notify code for the tree
|
||
|
switch( notifyMessageHandler->code )
|
||
|
{
|
||
|
|
||
|
// ----------------------------------------------------------------
|
||
|
case TVN_SELCHANGED:
|
||
|
{
|
||
|
LPNMTREEVIEW treeNotify = (LPNMTREEVIEW)lParam;
|
||
|
|
||
|
if( treeNotify->action != TVC_UNKNOWN )
|
||
|
{
|
||
|
TVITEM newItem;
|
||
|
|
||
|
// get the new item selected
|
||
|
newItem = treeNotify->itemNew;
|
||
|
|
||
|
// get the window data pointers
|
||
|
GameWindow *window = (GameWindow *)newItem.lParam;
|
||
|
|
||
|
// unselect everything else and select the new window
|
||
|
TheEditor->clearSelections();
|
||
|
if( window )
|
||
|
TheEditor->selectWindow( window );
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
break;
|
||
|
|
||
|
} // end selection changed
|
||
|
|
||
|
// ----------------------------------------------------------------
|
||
|
case NM_DBLCLK:
|
||
|
{
|
||
|
|
||
|
// get the selected tree item
|
||
|
HTREEITEM selected = TreeView_GetSelection( TheHierarchyView->getTreeHandle() );
|
||
|
if( selected )
|
||
|
{
|
||
|
GameWindow *overWindow;
|
||
|
|
||
|
// get the game window from the tree item
|
||
|
overWindow = TheHierarchyView->getWindowFromItem( selected );
|
||
|
|
||
|
// unselect all windows in the editor
|
||
|
TheEditor->clearSelections();
|
||
|
|
||
|
// select this one window
|
||
|
TheEditor->selectWindow( overWindow );
|
||
|
|
||
|
// set this window as the popup window target
|
||
|
TheHierarchyView->setPopupTarget( overWindow );
|
||
|
|
||
|
//
|
||
|
// bring up the popup menu, note that we must translate the
|
||
|
// local mouse pos to the screen
|
||
|
//
|
||
|
HMENU menu, subMenu;
|
||
|
POINT screen;
|
||
|
|
||
|
menu = LoadMenu( TheEditor->getInstance(), (LPCTSTR)HIERARCHY_POPUP_MENU );
|
||
|
subMenu = GetSubMenu( menu, 0 );
|
||
|
GetCursorPos( &screen );
|
||
|
TrackPopupMenuEx( subMenu, 0, screen.x, screen.y, hWndDialog, NULL );
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
break;
|
||
|
|
||
|
} // end double click
|
||
|
|
||
|
// ----------------------------------------------------------------
|
||
|
case TVN_BEGINDRAG:
|
||
|
{
|
||
|
LPNMTREEVIEW treeNotify = (LPNMTREEVIEW)lParam;
|
||
|
TVITEM newItem;
|
||
|
|
||
|
// get the item being dragged
|
||
|
newItem = treeNotify->itemNew;
|
||
|
|
||
|
// save the window being dragged
|
||
|
TheHierarchyView->setDragWindow( (GameWindow *)newItem.lParam );
|
||
|
TheHierarchyView->setDragTarget( NULL );
|
||
|
|
||
|
// capture the mouse
|
||
|
SetCapture( TheHierarchyView->getHierarchyHandle() );
|
||
|
|
||
|
break;
|
||
|
|
||
|
} // end begin left mouse drag
|
||
|
|
||
|
} // end switch
|
||
|
|
||
|
} // end hierarchy
|
||
|
|
||
|
} // end switch
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
} // end notify
|
||
|
|
||
|
// ------------------------------------------------------------------------
|
||
|
case WM_COMMAND:
|
||
|
{
|
||
|
// Int notifyCode = HIWORD( wParam );
|
||
|
Int controlID = LOWORD( wParam );
|
||
|
// HWND hWndControl = (HWND)lParam;
|
||
|
|
||
|
switch( controlID )
|
||
|
{
|
||
|
|
||
|
// --------------------------------------------------------------------
|
||
|
case MENU_HIERARCHY_MOVE_HERE:
|
||
|
{
|
||
|
GameWindow *drag = TheHierarchyView->getDragWindow();
|
||
|
GameWindow *target = TheHierarchyView->getPopupTarget();
|
||
|
|
||
|
// do the logic if after a sanity check on the targets
|
||
|
if( TheHierarchyView->validateDragDropOperation( drag, target ) )
|
||
|
TheGUIEditWindowManager->moveAheadOf( drag, target );
|
||
|
|
||
|
// we're done with the drag and popup ops now
|
||
|
TheHierarchyView->setDragWindow( NULL );
|
||
|
TheHierarchyView->setDragTarget( NULL );
|
||
|
TheHierarchyView->setPopupTarget( NULL );
|
||
|
|
||
|
break;
|
||
|
|
||
|
} // end hierarchy move window in heirarchy
|
||
|
|
||
|
// --------------------------------------------------------------------
|
||
|
case HIERARCHY_MAKE_CHILD_HERE:
|
||
|
{
|
||
|
GameWindow *drag = TheHierarchyView->getDragWindow();
|
||
|
GameWindow *target = TheHierarchyView->getPopupTarget();
|
||
|
|
||
|
// do the logic if after a sanity check on the targets
|
||
|
if( TheHierarchyView->validateDragDropOperation( drag, target ) )
|
||
|
TheGUIEditWindowManager->makeChildOf( drag, target );
|
||
|
|
||
|
// we're done with the drag and popup ops now
|
||
|
TheHierarchyView->setDragWindow( NULL );
|
||
|
TheHierarchyView->setDragTarget( NULL );
|
||
|
TheHierarchyView->setPopupTarget( NULL );
|
||
|
|
||
|
break;
|
||
|
|
||
|
} // end hierarchy, make child of
|
||
|
|
||
|
// --------------------------------------------------------------------
|
||
|
case HIERARCHY_POPUP_MOVE:
|
||
|
{
|
||
|
GameWindow *target = TheHierarchyView->getPopupTarget();
|
||
|
|
||
|
// sanity
|
||
|
if( target == NULL )
|
||
|
break;
|
||
|
|
||
|
//
|
||
|
// just to be safe, unselect all other windows, select this
|
||
|
// one, and go into move mode
|
||
|
//
|
||
|
TheEditor->clearSelections();
|
||
|
TheEditor->selectWindow( target );
|
||
|
TheEditor->setMode( MODE_DRAG_MOVE );
|
||
|
|
||
|
// set the locatoin of the move to the window position for now
|
||
|
ICoord2D pos;
|
||
|
target->winGetScreenPosition( &pos.x, &pos.y );
|
||
|
TheEditWindow->setDragMoveDest( &pos );
|
||
|
TheEditWindow->setDragMoveOrigin( &pos );
|
||
|
|
||
|
break;
|
||
|
|
||
|
} // end move
|
||
|
|
||
|
// --------------------------------------------------------------------
|
||
|
case HIERARCHY_POPUP_DELETE:
|
||
|
{
|
||
|
GameWindow *target = TheHierarchyView->getPopupTarget();
|
||
|
|
||
|
if( target )
|
||
|
TheEditor->deleteWindow( target );
|
||
|
|
||
|
break;
|
||
|
|
||
|
} // end delete
|
||
|
|
||
|
// --------------------------------------------------------------------
|
||
|
case HIERARCHY_POPUP_PROPERTIES:
|
||
|
{
|
||
|
GameWindow *target = TheHierarchyView->getPopupTarget();
|
||
|
|
||
|
if( target )
|
||
|
{
|
||
|
POINT p;
|
||
|
|
||
|
GetCursorPos( &p );
|
||
|
ScreenToClient( TheEditWindow->getWindowHandle(), &p );
|
||
|
InitPropertiesDialog( target, p.x, p.y );
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
break;
|
||
|
|
||
|
} // end properties
|
||
|
|
||
|
// --------------------------------------------------------------------
|
||
|
case IDOK:
|
||
|
break;
|
||
|
|
||
|
// --------------------------------------------------------------------
|
||
|
case IDCANCEL:
|
||
|
break;
|
||
|
|
||
|
} // end switch( LOWORD( wParam ) )
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
} // end of WM_COMMAND
|
||
|
|
||
|
// ------------------------------------------------------------------------
|
||
|
default:
|
||
|
return 0;
|
||
|
|
||
|
} // end of switch
|
||
|
|
||
|
} // end dialogProc
|
||
|
|
||
|
// HierarchyView::findItemEntry ===============================================
|
||
|
/** Workhorse to find the tree item anywhere in the tree with the
|
||
|
* matching data pointer of this game window */
|
||
|
//=============================================================================
|
||
|
HTREEITEM HierarchyView::findItemEntry( HTREEITEM node, GameWindow *window )
|
||
|
{
|
||
|
|
||
|
// end of recursion
|
||
|
if( node == NULL || window == NULL )
|
||
|
return NULL;
|
||
|
|
||
|
|
||
|
#if USE_FAST_FIND_ITEM
|
||
|
return m_treeHash[window];
|
||
|
#else
|
||
|
|
||
|
// is it in this node
|
||
|
TVITEM item;
|
||
|
item.hItem = node;
|
||
|
item.lParam = NULL;
|
||
|
item.mask = TVIF_HANDLE | TVIF_PARAM;
|
||
|
TreeView_GetItem( m_tree, &item );
|
||
|
if( (GameWindow *)item.lParam == window )
|
||
|
return node;
|
||
|
|
||
|
// not there, check our children
|
||
|
HTREEITEM child;
|
||
|
HTREEITEM found = NULL;
|
||
|
for( child = TreeView_GetNextItem( m_tree, node, TVGN_CHILD );
|
||
|
child;
|
||
|
child = TreeView_GetNextItem( m_tree, child, TVGN_NEXT ) )
|
||
|
{
|
||
|
|
||
|
found = findItemEntry( child, window );
|
||
|
if( found )
|
||
|
return found;
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
// not there, check the siblings
|
||
|
return findItemEntry( TreeView_GetNextItem( m_tree, node, TVGN_NEXT ),
|
||
|
window );
|
||
|
#endif
|
||
|
|
||
|
} // end findItemEntry
|
||
|
|
||
|
// HierarchyView::findTreeEntry ===============================================
|
||
|
/** Find the game window entry in the hierarchy tree, if found the
|
||
|
* item in the tree will be returned containing the window */
|
||
|
//=============================================================================
|
||
|
HTREEITEM HierarchyView::findTreeEntry( GameWindow *window )
|
||
|
{
|
||
|
|
||
|
// no-op
|
||
|
if( window == NULL )
|
||
|
return NULL;
|
||
|
|
||
|
// get root and search from there
|
||
|
return findItemEntry( TreeView_GetRoot( m_tree ), window );
|
||
|
|
||
|
} // end findTreeEntry
|
||
|
|
||
|
// HierarchyView::addWindowToTree =============================================
|
||
|
/** Add a single window to the hierarchy tree */
|
||
|
//=============================================================================
|
||
|
void HierarchyView::addWindowToTree( GameWindow *window,
|
||
|
HTREEITEM treeParent,
|
||
|
HierarchyOption option,
|
||
|
Bool addChildren,
|
||
|
Bool addSiblings )
|
||
|
{
|
||
|
HTREEITEM newItem = NULL;
|
||
|
|
||
|
// end of recursion
|
||
|
if( window == NULL )
|
||
|
return;
|
||
|
|
||
|
// add only if not in tree already
|
||
|
newItem = findTreeEntry( window );
|
||
|
if( newItem == NULL )
|
||
|
{
|
||
|
|
||
|
// setup insert struct
|
||
|
TVINSERTSTRUCT insert;
|
||
|
insert.hParent = treeParent;
|
||
|
if( option == HIERARCHY_ADD_AT_TOP )
|
||
|
insert.hInsertAfter = TVI_FIRST;
|
||
|
else
|
||
|
insert.hInsertAfter = TVI_LAST;
|
||
|
insert.itemex.mask = TVIF_TEXT | TVIF_PARAM;
|
||
|
insert.itemex.lParam = (LPARAM)window; // attach window to this item in lParam
|
||
|
|
||
|
//
|
||
|
// if the window has a name use it in the tree view, otherwise use a
|
||
|
// name based on the type of the window
|
||
|
//
|
||
|
insert.itemex.pszText = getWindowTreeName( window );
|
||
|
|
||
|
// add the item
|
||
|
newItem = TreeView_InsertItem( m_tree, &insert );
|
||
|
|
||
|
// sanity
|
||
|
if( newItem == NULL )
|
||
|
{
|
||
|
|
||
|
DEBUG_LOG(( "Error adding window to tree\n" ));
|
||
|
assert( 0 );
|
||
|
return;
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
#if USE_FAST_FIND_ITEM
|
||
|
m_treeHash[window] = newItem;
|
||
|
#endif
|
||
|
|
||
|
} // end if, not in already
|
||
|
|
||
|
//
|
||
|
// add children if requested, but not on gadgets no matter what becuase
|
||
|
// they are "atomic units", except for tab controls.
|
||
|
//
|
||
|
if( addChildren && TheEditor->windowIsGadget( window ) == FALSE || (window->winGetStyle() & GWS_TAB_CONTROL) )
|
||
|
{
|
||
|
GameWindow *child;
|
||
|
|
||
|
for( child = window->winGetChild(); child; child = child->winGetNext() )
|
||
|
addWindowToTree( child, newItem, HIERARCHY_ADD_AT_BOTTOM, TRUE, TRUE );
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
// add siblings if requested
|
||
|
if( addSiblings )
|
||
|
addWindowToTree( window->winGetNext(), treeParent, option,
|
||
|
addChildren, addSiblings );
|
||
|
|
||
|
} // end addWindowToTree
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// HierarchyView::HierarchyView ===============================================
|
||
|
/** */
|
||
|
//=============================================================================
|
||
|
HierarchyView::HierarchyView( void )
|
||
|
{
|
||
|
|
||
|
m_dialog = NULL;
|
||
|
m_tree = NULL;
|
||
|
dialogPos.x = dialogPos.y = 0;
|
||
|
dialogSize.x = dialogSize.y = 0;
|
||
|
m_dragWindow = NULL;
|
||
|
m_dragTarget = NULL;
|
||
|
m_popupTarget = NULL;
|
||
|
|
||
|
} // end HierarchyView
|
||
|
|
||
|
// HierarchyView::~HierarchyView ==============================================
|
||
|
/** */
|
||
|
//=============================================================================
|
||
|
HierarchyView::~HierarchyView( void )
|
||
|
{
|
||
|
|
||
|
// call the shutdown
|
||
|
shutdown();
|
||
|
|
||
|
} // end ~HierarchyView
|
||
|
|
||
|
// HierarchyView::init =========================================================
|
||
|
/** Create the control palette */
|
||
|
//=============================================================================
|
||
|
void HierarchyView::init( void )
|
||
|
{
|
||
|
RECT dialogRect;
|
||
|
RECT appRect;
|
||
|
|
||
|
// create the modless dialog box
|
||
|
m_dialog = CreateDialog( TheEditor->getInstance(),
|
||
|
(LPCSTR)HIERARCHY_DIALOG,
|
||
|
TheEditor->getWindowHandle(),
|
||
|
(DLGPROC)dialogProc );
|
||
|
|
||
|
// display the dialog
|
||
|
ShowWindow( m_dialog, SW_SHOW );
|
||
|
|
||
|
// get the size of the control palette
|
||
|
GetWindowRect( m_dialog, &dialogRect );
|
||
|
dialogSize.x = dialogRect.right - dialogRect.left;
|
||
|
dialogSize.y = dialogRect.bottom - dialogRect.top;
|
||
|
|
||
|
POINT p;
|
||
|
p.x = dialogRect.left;
|
||
|
p.y = dialogRect.top;
|
||
|
ScreenToClient( TheEditor->getWindowHandle(), &p );
|
||
|
dialogPos.x = p.x;
|
||
|
dialogPos.y = p.y;
|
||
|
|
||
|
// get the rect of the app window
|
||
|
GetClientRect( TheEditor->getWindowHandle(), &appRect );
|
||
|
|
||
|
// place control palette at the top right of client area in edit window
|
||
|
MoveWindow( m_dialog,
|
||
|
appRect.right - dialogSize.x, 0,
|
||
|
dialogSize.x, dialogSize.y,
|
||
|
TRUE );
|
||
|
|
||
|
// keep a handle to the tree
|
||
|
m_tree = GetDlgItem( m_dialog, TREE_HIERARCHY );
|
||
|
|
||
|
} // end init
|
||
|
|
||
|
// HierarchyView::reset =======================================================
|
||
|
/** Reset everything about our hierarchy view */
|
||
|
//=============================================================================
|
||
|
void HierarchyView::reset( void )
|
||
|
{
|
||
|
|
||
|
// reset the tree control
|
||
|
HTREEITEM parentItem = TreeView_GetRoot( m_tree );
|
||
|
SendMessage( m_tree, TVM_EXPAND, TVE_COLLAPSERESET, (LPARAM)parentItem );
|
||
|
|
||
|
#if USE_FAST_FIND_ITEM
|
||
|
m_treeHash.clear();
|
||
|
#endif
|
||
|
|
||
|
} // end reset
|
||
|
|
||
|
// HierarchyView::shutdown ====================================================
|
||
|
/** Destroy the control palette and all data associated with it */
|
||
|
//=============================================================================
|
||
|
void HierarchyView::shutdown( void )
|
||
|
{
|
||
|
|
||
|
// destroy the control palette window
|
||
|
DestroyWindow( m_dialog );
|
||
|
m_dialog = NULL;
|
||
|
m_tree = NULL;
|
||
|
|
||
|
} // end shutdown
|
||
|
|
||
|
// HierarchyView::getWindowTreeName ===========================================
|
||
|
/** Given a window, return a string representation for that window in
|
||
|
* the hierarchy view */
|
||
|
//=============================================================================
|
||
|
char *HierarchyView::getWindowTreeName( GameWindow *window )
|
||
|
{
|
||
|
static char buffer[ 256 ];
|
||
|
|
||
|
// init buffer to return to nothing
|
||
|
strcpy( buffer, "" );
|
||
|
|
||
|
// sanity
|
||
|
if( window == NULL )
|
||
|
return buffer;
|
||
|
|
||
|
// no name available, construct one based on type
|
||
|
Int style = window->winGetStyle();
|
||
|
if( BitTest( style, GWS_PUSH_BUTTON ) )
|
||
|
strcpy( buffer, "Button" );
|
||
|
else if( BitTest( style, GWS_RADIO_BUTTON ) )
|
||
|
strcpy( buffer, "Radio Button" );
|
||
|
else if( BitTest( style, GWS_TAB_CONTROL ) )
|
||
|
strcpy( buffer, "Tab Control" );
|
||
|
else if( BitTest( style, GWS_CHECK_BOX ) )
|
||
|
strcpy( buffer, "Check Box" );
|
||
|
else if( BitTest( style, GWS_HORZ_SLIDER ) )
|
||
|
strcpy( buffer, "Horizontal Slider" );
|
||
|
else if( BitTest( style, GWS_VERT_SLIDER ) )
|
||
|
strcpy( buffer, "Vertical Slider" );
|
||
|
else if( BitTest( style, GWS_STATIC_TEXT ) )
|
||
|
strcpy( buffer, "Static Text" );
|
||
|
else if( BitTest( style, GWS_ENTRY_FIELD ) )
|
||
|
strcpy( buffer, "Text Entry" );
|
||
|
else if( BitTest( style, GWS_SCROLL_LISTBOX ) )
|
||
|
strcpy( buffer, "Listbox" );
|
||
|
else if( BitTest( style, GWS_PROGRESS_BAR ) )
|
||
|
strcpy( buffer, "Progress Bar" );
|
||
|
else if( BitTest( style, GWS_USER_WINDOW ) )
|
||
|
strcpy( buffer, "User Window" );
|
||
|
else if( BitTest( style, GWS_TAB_PANE ) )
|
||
|
strcpy( buffer, "Tab Pane" );
|
||
|
else if( BitTest( style, GWS_COMBO_BOX ) )
|
||
|
strcpy( buffer, "Combo Box" );
|
||
|
else
|
||
|
strcpy( buffer, "Undefined" );
|
||
|
|
||
|
// if window has a name, concatenate it on the end
|
||
|
WinInstanceData *instData = window->winGetInstanceData();
|
||
|
if( !instData->m_decoratedNameString.isEmpty() )
|
||
|
{
|
||
|
|
||
|
strcat( buffer, ": " );
|
||
|
strcat( buffer, instData->m_decoratedNameString.str() );
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
return buffer;
|
||
|
|
||
|
} // end getWindowTreeName
|
||
|
|
||
|
// HierarchyView::addWindow ===================================================
|
||
|
/** Add a window to the hierarchy view AND any of it's children */
|
||
|
//=============================================================================
|
||
|
void HierarchyView::addWindow( GameWindow *window, HierarchyOption option )
|
||
|
{
|
||
|
|
||
|
// sanity
|
||
|
if( window == NULL || m_dialog == NULL )
|
||
|
return;
|
||
|
|
||
|
// do not add again if already in the tree
|
||
|
if( findTreeEntry( window ) != NULL )
|
||
|
return;
|
||
|
|
||
|
// get the parent tree entry to this window, NULL if no parent
|
||
|
GameWindow *parent = window->winGetParent();
|
||
|
HTREEITEM parentItem = findTreeEntry( parent );
|
||
|
|
||
|
// add this window
|
||
|
addWindowToTree( window, parentItem, option, TRUE, FALSE );
|
||
|
|
||
|
//
|
||
|
// force the tree control to redraw, it seems to have problems updating
|
||
|
// the plus signs, lame ass Microsoft
|
||
|
//
|
||
|
InvalidateRect( m_tree, NULL, TRUE );
|
||
|
|
||
|
} // end addWindow
|
||
|
|
||
|
// HierarchyView::removeWindow ================================================
|
||
|
/** Remove the window from the hierarchy tree view */
|
||
|
//=============================================================================
|
||
|
void HierarchyView::removeWindow( GameWindow *window )
|
||
|
{
|
||
|
HTREEITEM item;
|
||
|
|
||
|
// sanity
|
||
|
if( window == NULL )
|
||
|
return;
|
||
|
|
||
|
// if this window is the drag window clean that mode up
|
||
|
if( window == m_dragWindow )
|
||
|
m_dragWindow = NULL;
|
||
|
|
||
|
// clean up drag target
|
||
|
if( window == m_dragTarget )
|
||
|
m_dragTarget = NULL;
|
||
|
|
||
|
// if this window is the popup target remove it
|
||
|
if( window == m_popupTarget )
|
||
|
m_popupTarget = NULL;
|
||
|
|
||
|
// find this entry in the tree
|
||
|
item = findTreeEntry( window );
|
||
|
|
||
|
// if not in tree nothing to do
|
||
|
if( item == NULL )
|
||
|
return;
|
||
|
|
||
|
// remove it from the tree
|
||
|
TreeView_DeleteItem( m_tree, item );
|
||
|
|
||
|
#if USE_FAST_FIND_ITEM
|
||
|
TreeHash::iterator find = m_treeHash.find(window);
|
||
|
if (find != m_treeHash.end())
|
||
|
m_treeHash.erase(find);
|
||
|
#endif
|
||
|
|
||
|
} // end removeWindow
|
||
|
|
||
|
// HierarchyView::bringWindowToTop ============================================
|
||
|
/** Bring the window to the top of its parent list in the hierarchy
|
||
|
* view, if no parent is present to the top of the hierarchy then */
|
||
|
//=============================================================================
|
||
|
void HierarchyView::bringWindowToTop( GameWindow *window )
|
||
|
{
|
||
|
|
||
|
// sanity
|
||
|
if( window == NULL )
|
||
|
return;
|
||
|
|
||
|
// find this window entry
|
||
|
HTREEITEM item = findTreeEntry( window );
|
||
|
if( item == NULL )
|
||
|
{
|
||
|
|
||
|
DEBUG_LOG(( "Cannot bring window to top, no entry in tree!\n" ));
|
||
|
assert( 0 );
|
||
|
return;
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
// remove the entry from the tree
|
||
|
removeWindow( window );
|
||
|
|
||
|
// find the parent tree entry
|
||
|
HTREEITEM itemParent = findTreeEntry( window->winGetParent() );
|
||
|
|
||
|
// add the window as a child of the parent entry at the top of it's list
|
||
|
addWindowToTree( window, itemParent, HIERARCHY_ADD_AT_TOP, TRUE, FALSE );
|
||
|
|
||
|
} // end bringWindowToTop
|
||
|
|
||
|
// HierarchyView::updateWindowName ============================================
|
||
|
/** A window name may have been updated, reconstruct its hierarchy
|
||
|
* tree entry cause we like to show names when we have them */
|
||
|
//=============================================================================
|
||
|
void HierarchyView::updateWindowName( GameWindow *window )
|
||
|
{
|
||
|
|
||
|
// sanity
|
||
|
if( window == NULL )
|
||
|
return;
|
||
|
|
||
|
// get the tree entry
|
||
|
HTREEITEM item = findTreeEntry( window );
|
||
|
if( item == NULL )
|
||
|
{
|
||
|
|
||
|
DEBUG_LOG(( "updateWindowName: No hierarchy entry for window!\n" ));
|
||
|
assert( 0 );
|
||
|
return;
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
// setup the item to modify in the tree
|
||
|
TVITEM modify;
|
||
|
modify.mask = TVIF_HANDLE | TVIF_TEXT;
|
||
|
modify.hItem = item;
|
||
|
modify.pszText = getWindowTreeName( window );
|
||
|
|
||
|
// modify the item
|
||
|
TreeView_SetItem( m_tree, &modify );
|
||
|
|
||
|
} // end updateWindowName
|
||
|
|
||
|
// HierarchyView::getDialogPos ================================================
|
||
|
/** Get the dialog position as recorded from the static */
|
||
|
//=============================================================================
|
||
|
void HierarchyView::getDialogPos( ICoord2D *pos )
|
||
|
{
|
||
|
|
||
|
// sanity
|
||
|
if( pos == NULL )
|
||
|
return;
|
||
|
|
||
|
*pos = dialogPos;
|
||
|
|
||
|
} // end getDialogPos
|
||
|
|
||
|
// HierarchyView::getDialogSize ===============================================
|
||
|
/** Get the dialog size as recorded from the static */
|
||
|
//=============================================================================
|
||
|
void HierarchyView::getDialogSize( ICoord2D *size )
|
||
|
{
|
||
|
|
||
|
// sanity
|
||
|
if( size == NULL )
|
||
|
return;
|
||
|
|
||
|
*size = dialogSize;
|
||
|
|
||
|
} // end getDialogSize
|
||
|
|
||
|
// HierarchyView::setDialogPos ================================================
|
||
|
/** */
|
||
|
//=============================================================================
|
||
|
void HierarchyView::setDialogPos( ICoord2D *pos )
|
||
|
{
|
||
|
|
||
|
// sanity
|
||
|
if( pos )
|
||
|
dialogPos = *pos;
|
||
|
|
||
|
MoveWindow( m_dialog, dialogPos.x, dialogPos.y,
|
||
|
dialogSize.x, dialogSize.y, TRUE );
|
||
|
|
||
|
} // end setDialogPos
|
||
|
|
||
|
// HierarchyView::setDialogSize ===============================================
|
||
|
/** */
|
||
|
//=============================================================================
|
||
|
void HierarchyView::setDialogSize( ICoord2D *size )
|
||
|
{
|
||
|
|
||
|
// sanity
|
||
|
if( size )
|
||
|
dialogSize = *size;
|
||
|
|
||
|
MoveWindow( m_dialog, dialogPos.x, dialogPos.y,
|
||
|
dialogSize.x, dialogSize.y, TRUE );
|
||
|
|
||
|
} // end setDialogSize
|
||
|
|
||
|
// HierarchyView::moveWindowAheadOf ===========================================
|
||
|
/** Move the window hierarchy representation to be just ahead of the
|
||
|
* hierarchy entry of 'aheadOf' */
|
||
|
//=============================================================================
|
||
|
void HierarchyView::moveWindowAheadOf( GameWindow *window,
|
||
|
GameWindow *aheadOf )
|
||
|
{
|
||
|
|
||
|
// sanity
|
||
|
if( window == NULL )
|
||
|
return;
|
||
|
|
||
|
// get the window hierarchy entry
|
||
|
removeWindow( window );
|
||
|
|
||
|
// we'll say and aheadOf of NULL means put at the top
|
||
|
if( aheadOf == NULL )
|
||
|
{
|
||
|
|
||
|
addWindow( window, HIERARCHY_ADD_AT_TOP );
|
||
|
return;
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
// get the hierarchy item of the aheadOf window
|
||
|
HTREEITEM aheadOfItem = findTreeEntry( aheadOf );
|
||
|
if( aheadOfItem == NULL )
|
||
|
{
|
||
|
|
||
|
DEBUG_LOG(( "moveWindowAheadOf: aheadOf has no hierarchy entry!\n" ));
|
||
|
assert( 0 );
|
||
|
return;
|
||
|
|
||
|
} // end iof
|
||
|
|
||
|
//
|
||
|
// get the parent item we will be inserting the new entry at, a parent
|
||
|
// of NULL is OK and will put it at the root of the tree
|
||
|
//
|
||
|
HTREEITEM parentItem = TreeView_GetNextItem( m_tree, aheadOfItem, TVGN_PARENT );
|
||
|
|
||
|
//
|
||
|
// get the item that we will be inserting after (just previous to
|
||
|
// 'aheadOfItem' ... this can also be NULL for putting at the head
|
||
|
//
|
||
|
HTREEITEM prevItem = TreeView_GetNextItem( m_tree, aheadOfItem, TVGN_PREVIOUS );
|
||
|
|
||
|
// setup insert struct
|
||
|
TVINSERTSTRUCT insert;
|
||
|
insert.itemex.mask = TVIF_TEXT | TVIF_PARAM;
|
||
|
insert.hParent = parentItem;
|
||
|
if( prevItem == NULL )
|
||
|
insert.hInsertAfter = TVI_FIRST;
|
||
|
else
|
||
|
insert.hInsertAfter = prevItem;
|
||
|
insert.itemex.lParam = (LPARAM)window; // attach window to this item in lParam
|
||
|
insert.itemex.pszText = getWindowTreeName( window );
|
||
|
|
||
|
// add the item
|
||
|
HTREEITEM newItem = TreeView_InsertItem( m_tree, &insert );
|
||
|
|
||
|
// sanity
|
||
|
if( newItem == NULL )
|
||
|
{
|
||
|
|
||
|
DEBUG_LOG(( "moveWindowAheadOf: Error adding window to tree\n" ));
|
||
|
assert( 0 );
|
||
|
return;
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
//
|
||
|
// add ALL the children of this window as well, do not worry about
|
||
|
// gadget children
|
||
|
//
|
||
|
if( TheEditor->windowIsGadget( window ) == FALSE )
|
||
|
{
|
||
|
GameWindow *child = window->winGetChild();
|
||
|
|
||
|
addWindowToTree( child, newItem, HIERARCHY_ADD_AT_BOTTOM, TRUE, TRUE );
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
} // end moveWindowAheadOf
|
||
|
|
||
|
// HierarchyView::moveWindowChildOf ===========================================
|
||
|
/** Move the hierarchy entry for window so that it is now the first
|
||
|
* child in the list under parent */
|
||
|
//=============================================================================
|
||
|
void HierarchyView::moveWindowChildOf( GameWindow *window, GameWindow *parent )
|
||
|
{
|
||
|
|
||
|
// sanity
|
||
|
if( window == NULL )
|
||
|
return;
|
||
|
|
||
|
// remvoe the window from the hierarchy
|
||
|
removeWindow( window );
|
||
|
|
||
|
// if parent is NULL we'll put at top of list
|
||
|
if( parent == NULL )
|
||
|
{
|
||
|
|
||
|
addWindow( window, HIERARCHY_ADD_AT_TOP );
|
||
|
return;
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
// find the entry of the parent
|
||
|
HTREEITEM parentItem = findTreeEntry( parent );
|
||
|
if( parentItem == NULL )
|
||
|
{
|
||
|
|
||
|
DEBUG_LOG(( "moveWindowChildOf: No parent entry\n" ));
|
||
|
assert( 0 );
|
||
|
return;
|
||
|
|
||
|
} // end if
|
||
|
|
||
|
// add the window as child of the parent at the top, dont forget to
|
||
|
// also add the children of the window too!
|
||
|
addWindowToTree( window, parentItem, HIERARCHY_ADD_AT_TOP, TRUE, FALSE );
|
||
|
|
||
|
} // end moveWindowChildOf
|
||
|
|
||
|
// HierarchyView::treePointToItem =============================================
|
||
|
/** Given the location (x,y) in TREE COORDINATES, correlate that to
|
||
|
* a tree item, if any */
|
||
|
//=============================================================================
|
||
|
HTREEITEM HierarchyView::treePointToItem( Int x, Int y )
|
||
|
{
|
||
|
|
||
|
// which tree item are we now over
|
||
|
TVHITTESTINFO hitTest;
|
||
|
hitTest.pt.x = x;
|
||
|
hitTest.pt.y = y;
|
||
|
hitTest.hItem = NULL;
|
||
|
hitTest.flags = TVHT_ONITEM;
|
||
|
return TreeView_HitTest( TheHierarchyView->getTreeHandle(), &hitTest );
|
||
|
|
||
|
} // end treePointToItem
|
||
|
|
||
|
// HierarchyView::getWindowFromItem ===========================================
|
||
|
/** Get the game window we stored as the user data lParam in the tree
|
||
|
* item */
|
||
|
//=============================================================================
|
||
|
GameWindow *HierarchyView::getWindowFromItem( HTREEITEM treeItem )
|
||
|
{
|
||
|
|
||
|
// sanity
|
||
|
if( treeItem == NULL )
|
||
|
return NULL;
|
||
|
|
||
|
// get the node info from the tree item we're over
|
||
|
TVITEM itemInfo;
|
||
|
GameWindow *window;
|
||
|
|
||
|
itemInfo.hItem = treeItem;
|
||
|
itemInfo.lParam = NULL;
|
||
|
itemInfo.mask = TVIF_HANDLE | TVIF_PARAM;
|
||
|
TreeView_GetItem( m_tree, &itemInfo );
|
||
|
window = (GameWindow *)itemInfo.lParam;
|
||
|
assert( window );
|
||
|
|
||
|
return window;
|
||
|
|
||
|
} // end getWindowFromItem
|
||
|
|
||
|
// HierarchyView::selectWindow ================================================
|
||
|
/** Select the tree item */
|
||
|
//=============================================================================
|
||
|
void HierarchyView::selectWindow( GameWindow *window )
|
||
|
{
|
||
|
HTREEITEM item = NULL;
|
||
|
|
||
|
// get the item associated with the window
|
||
|
if( window )
|
||
|
item = findTreeEntry( window );
|
||
|
|
||
|
// select the item, or no item NULL will select nothing
|
||
|
TreeView_SelectItem( m_tree, item );
|
||
|
TreeView_Expand( m_tree, item, 0 );
|
||
|
|
||
|
} // end selectWindow
|
||
|
|
||
|
// HierarchyView::validateDragDropOperation ===================================
|
||
|
/** Return TRUE if the drag drop operation of source onto target
|
||
|
* is logically OK. It's not OK if target is a child of source because
|
||
|
* you cannot move a parent window into it's own child list. */
|
||
|
//=============================================================================
|
||
|
Bool HierarchyView::validateDragDropOperation( GameWindow *source,
|
||
|
GameWindow *target )
|
||
|
{
|
||
|
|
||
|
// sanity
|
||
|
if( source == NULL || target == NULL )
|
||
|
return FALSE;
|
||
|
|
||
|
// if target is the source or is a child of source in any way this is illegal
|
||
|
GameWindow *other = target;
|
||
|
while( other )
|
||
|
{
|
||
|
|
||
|
if( source == other )
|
||
|
return FALSE;
|
||
|
other = other->winGetParent();
|
||
|
|
||
|
} // end while
|
||
|
|
||
|
// everything is ok
|
||
|
return TRUE;
|
||
|
|
||
|
} // end validateDragDropOperation
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|