/* ** 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 . */ //////////////////////////////////////////////////////////////////////////////// // // // (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 #include #include // 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