HierarchyView.cpp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: HierarchyView.cpp ////////////////////////////////////////////////////
  24. //-----------------------------------------------------------------------------
  25. //
  26. // Westwood Studios Pacific.
  27. //
  28. // Confidential Information
  29. // Copyright (C) 2001 - All Rights Reserved
  30. //
  31. //-----------------------------------------------------------------------------
  32. //
  33. // Project: GUIEdit
  34. //
  35. // File name: HierarchyView.cpp
  36. //
  37. // Created: Colin Day, July 2001
  38. //
  39. // Desc: Manipulation the widows heirarchy through the tree
  40. //
  41. //-----------------------------------------------------------------------------
  42. ///////////////////////////////////////////////////////////////////////////////
  43. // SYSTEM INCLUDES ////////////////////////////////////////////////////////////
  44. #include <windows.h>
  45. #include <commctrl.h>
  46. #include <string.h>
  47. // USER INCLUDES //////////////////////////////////////////////////////////////
  48. #include "Common/Debug.h"
  49. #include "GameClient/Gadget.h"
  50. #include "Resource.h"
  51. #include "HierarchyView.h"
  52. #include "WinMain.h"
  53. #include "GUIEdit.h"
  54. #include "EditWindow.h"
  55. #include "GUIEditWindowManager.h"
  56. #include "Properties.h"
  57. // DEFINES ////////////////////////////////////////////////////////////////////
  58. // PRIVATE TYPES //////////////////////////////////////////////////////////////
  59. ///////////////////////////////////////////////////////////////////////////////
  60. // PRIVATE DATA ///////////////////////////////////////////////////////////////
  61. ///////////////////////////////////////////////////////////////////////////////
  62. static ICoord2D dialogPos;
  63. static ICoord2D dialogSize;
  64. // PUBLIC DATA ////////////////////////////////////////////////////////////////
  65. HierarchyView *TheHierarchyView = NULL; ///< the view singleton
  66. // PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
  67. ///////////////////////////////////////////////////////////////////////////////
  68. // PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
  69. ///////////////////////////////////////////////////////////////////////////////
  70. // HierarchyView::dialogProc ==================================================
  71. /** Windows dialog procedure for the control palette */
  72. //=============================================================================
  73. LRESULT CALLBACK HierarchyView::dialogProc( HWND hWndDialog, UINT message,
  74. WPARAM wParam, LPARAM lParam )
  75. {
  76. switch( message )
  77. {
  78. // ------------------------------------------------------------------------
  79. case WM_MOVE:
  80. {
  81. // Int x = LOWORD( lParam );
  82. // Int y = HIWORD( lParam );
  83. // record our position
  84. RECT rect;
  85. POINT p;
  86. GetWindowRect( hWndDialog, &rect );
  87. p.x = rect.left;
  88. p.y = rect.top;
  89. ScreenToClient( TheEditor->getWindowHandle(), &p );
  90. dialogPos.x = p.x;
  91. dialogPos.y = p.y;
  92. return 0;
  93. } // end move
  94. // ------------------------------------------------------------------------
  95. case WM_SIZE:
  96. {
  97. // Int sizeType = wParam; // resizing flag
  98. Int width = LOWORD( lParam ); // width of client
  99. Int height = HIWORD( lParam ); // height of client
  100. // record the new height
  101. RECT rect;
  102. GetWindowRect( hWndDialog, &rect );
  103. dialogSize.x = rect.right - rect.left;
  104. dialogSize.y = rect.bottom - rect.top;
  105. // resizing the dialog will cause us to resize the tree view control
  106. if( TheHierarchyView )
  107. {
  108. HWND tree = TheHierarchyView->getTreeHandle();
  109. if( tree )
  110. {
  111. Int border = 10;
  112. RECT treeRect;
  113. POINT p;
  114. GetWindowRect( tree, &treeRect );
  115. p.x = treeRect.left;
  116. p.y = treeRect.top;
  117. ScreenToClient( hWndDialog, &p );
  118. MoveWindow( tree, border, p.y,
  119. width - (border * 2), (height - border) - p.y,
  120. TRUE );
  121. } // end if
  122. } // end if
  123. return 0;
  124. } // end size
  125. // ------------------------------------------------------------------------
  126. case WM_MOUSEMOVE:
  127. {
  128. Int x = LOWORD( lParam );
  129. Int y = HIWORD( lParam );
  130. GameWindow *dragWindow = TheHierarchyView->getDragWindow();
  131. // dragging a window then hilite any tree item we're over
  132. if( dragWindow )
  133. {
  134. POINT treePoint;
  135. // translate the mouse coords to the coords of the tree
  136. treePoint.x = x;
  137. treePoint.y = y;
  138. ClientToScreen( hWndDialog, &treePoint );
  139. ScreenToClient( TheHierarchyView->getTreeHandle(), &treePoint );
  140. // get the tree item if any that we're over and select it if present
  141. HTREEITEM overItem = TheHierarchyView->treePointToItem( treePoint.x, treePoint.y );
  142. if( overItem )
  143. {
  144. GameWindow *target = TheHierarchyView->getWindowFromItem( overItem );
  145. //
  146. // set this window as the drag target, we use it to draw visual
  147. // feeback in the edit window
  148. //
  149. TheHierarchyView->setDragTarget( target );
  150. // select the item in the tree
  151. TreeView_SelectItem( TheHierarchyView->getTreeHandle(), overItem );
  152. //
  153. // if this operation is legal set the cross cursor, otherwise
  154. // use the "no" cursor
  155. //
  156. if( TheHierarchyView->validateDragDropOperation( dragWindow, target ) )
  157. SetCursor( LoadCursor( NULL, IDC_CROSS ) );
  158. else
  159. SetCursor( LoadCursor( NULL, IDC_NO ) );
  160. } // end if
  161. } // end if
  162. return 0;
  163. } // end mouse move
  164. // ------------------------------------------------------------------------
  165. case WM_LBUTTONUP:
  166. {
  167. Int x = LOWORD( lParam );
  168. Int y = HIWORD( lParam );
  169. GameWindow *dragWindow = TheHierarchyView->getDragWindow();
  170. Bool clearDragWindow = TRUE;
  171. if( dragWindow )
  172. {
  173. POINT treePoint;
  174. // translate the mouse coords to the coords of the tree
  175. treePoint.x = x;
  176. treePoint.y = y;
  177. ClientToScreen( hWndDialog, &treePoint );
  178. ScreenToClient( TheHierarchyView->getTreeHandle(), &treePoint );
  179. // get the tree item if any that we're over
  180. HTREEITEM overItem = TheHierarchyView->treePointToItem( treePoint.x, treePoint.y );
  181. if( overItem )
  182. {
  183. GameWindow *overWindow;
  184. TVITEM overItemInfo;
  185. // get the node info from the tree item we're over
  186. overItemInfo.hItem = overItem;
  187. overItemInfo.lParam = NULL;
  188. overItemInfo.mask = TVIF_HANDLE | TVIF_PARAM;
  189. TreeView_GetItem( TheHierarchyView->getTreeHandle(), &overItemInfo );
  190. overWindow = (GameWindow *)overItemInfo.lParam;
  191. // this should always be true!
  192. assert( overWindow );
  193. // do the drag drop if allowed
  194. if( TheHierarchyView->validateDragDropOperation( dragWindow,
  195. overWindow ) )
  196. {
  197. //
  198. // if our target window is NOT a gadget we have the option
  199. // of moving the drag window to this position OR making the
  200. // drag window a child of the target overWindow. If that is
  201. // the case we need a little popup menu to decide
  202. //
  203. if( TheEditor->windowIsGadget( overWindow ) == FALSE )
  204. {
  205. //
  206. // bring up the popup menu, note that we must translate the
  207. // local mouse pos to the screen
  208. //
  209. HMENU menu, subMenu;
  210. POINT screen;
  211. menu = LoadMenu( TheEditor->getInstance(), (LPCTSTR)HIERARCHY_DRAG_DROP_MENU );
  212. subMenu = GetSubMenu( menu, 0 );
  213. screen.x = x;
  214. screen.y = y;
  215. ClientToScreen( hWndDialog, &screen );
  216. TrackPopupMenuEx( subMenu, 0, screen.x, screen.y, hWndDialog, NULL );
  217. //
  218. // do not reset the drag window, and set the target window as
  219. // the popup target know which window to target after they
  220. // select from the popup menu
  221. //
  222. clearDragWindow = FALSE;
  223. TheHierarchyView->setPopupTarget( overWindow );
  224. } // end if
  225. else
  226. {
  227. // our only option is to move the window here
  228. TheGUIEditWindowManager->moveAheadOf( dragWindow, overWindow );
  229. } // end else
  230. // we've made a change now
  231. TheEditor->setUnsaved( TRUE );
  232. } // end if
  233. } // end if
  234. // window has been dragged and operation complete
  235. if( clearDragWindow )
  236. {
  237. TheHierarchyView->setDragWindow( NULL );
  238. TheHierarchyView->setDragTarget( NULL );
  239. } // end if
  240. // release window capture
  241. ReleaseCapture();
  242. // set the cursor back to normal
  243. SetCursor( LoadCursor( NULL, IDC_ARROW ) );
  244. } // end if, drag in progress
  245. return 0;
  246. } // end left button up
  247. // ------------------------------------------------------------------------
  248. case WM_RBUTTONUP:
  249. {
  250. Int x = LOWORD( lParam );
  251. Int y = HIWORD( lParam );
  252. POINT treePoint;
  253. // translate the mouse coords to the coords of the tree
  254. treePoint.x = x;
  255. treePoint.y = y;
  256. ClientToScreen( hWndDialog, &treePoint );
  257. ScreenToClient( TheHierarchyView->getTreeHandle(), &treePoint );
  258. // get the tree item if any that we're over
  259. HTREEITEM overItem = TheHierarchyView->treePointToItem( treePoint.x, treePoint.y );
  260. if( overItem )
  261. {
  262. GameWindow *overWindow;
  263. // get the game window from the tree item
  264. overWindow = TheHierarchyView->getWindowFromItem( overItem );
  265. // unselect all windows in the editor
  266. TheEditor->clearSelections();
  267. // select this one window
  268. TheEditor->selectWindow( overWindow );
  269. // set this window as the popup window target
  270. TheHierarchyView->setPopupTarget( overWindow );
  271. //
  272. // bring up the popup menu, note that we must translate the
  273. // local mouse pos to the screen
  274. //
  275. HMENU menu, subMenu;
  276. POINT screen;
  277. menu = LoadMenu( TheEditor->getInstance(), (LPCTSTR)HIERARCHY_POPUP_MENU );
  278. subMenu = GetSubMenu( menu, 0 );
  279. screen.x = x;
  280. screen.y = y;
  281. ClientToScreen( hWndDialog, &screen );
  282. TrackPopupMenuEx( subMenu, 0, screen.x, screen.y, hWndDialog, NULL );
  283. } // end if
  284. return 0;
  285. } // end right button up
  286. // ------------------------------------------------------------------------
  287. case WM_NOTIFY:
  288. {
  289. UnsignedInt controlID = (Int)wParam;
  290. LPNMHDR notifyMessageHandler = (LPNMHDR)lParam;
  291. // switch on control
  292. switch( controlID )
  293. {
  294. // --------------------------------------------------------------------
  295. case TREE_HIERARCHY:
  296. {
  297. // switch on notify code for the tree
  298. switch( notifyMessageHandler->code )
  299. {
  300. // ----------------------------------------------------------------
  301. case TVN_SELCHANGED:
  302. {
  303. LPNMTREEVIEW treeNotify = (LPNMTREEVIEW)lParam;
  304. if( treeNotify->action != TVC_UNKNOWN )
  305. {
  306. TVITEM newItem;
  307. // get the new item selected
  308. newItem = treeNotify->itemNew;
  309. // get the window data pointers
  310. GameWindow *window = (GameWindow *)newItem.lParam;
  311. // unselect everything else and select the new window
  312. TheEditor->clearSelections();
  313. if( window )
  314. TheEditor->selectWindow( window );
  315. } // end if
  316. break;
  317. } // end selection changed
  318. // ----------------------------------------------------------------
  319. case NM_DBLCLK:
  320. {
  321. // get the selected tree item
  322. HTREEITEM selected = TreeView_GetSelection( TheHierarchyView->getTreeHandle() );
  323. if( selected )
  324. {
  325. GameWindow *overWindow;
  326. // get the game window from the tree item
  327. overWindow = TheHierarchyView->getWindowFromItem( selected );
  328. // unselect all windows in the editor
  329. TheEditor->clearSelections();
  330. // select this one window
  331. TheEditor->selectWindow( overWindow );
  332. // set this window as the popup window target
  333. TheHierarchyView->setPopupTarget( overWindow );
  334. //
  335. // bring up the popup menu, note that we must translate the
  336. // local mouse pos to the screen
  337. //
  338. HMENU menu, subMenu;
  339. POINT screen;
  340. menu = LoadMenu( TheEditor->getInstance(), (LPCTSTR)HIERARCHY_POPUP_MENU );
  341. subMenu = GetSubMenu( menu, 0 );
  342. GetCursorPos( &screen );
  343. TrackPopupMenuEx( subMenu, 0, screen.x, screen.y, hWndDialog, NULL );
  344. } // end if
  345. break;
  346. } // end double click
  347. // ----------------------------------------------------------------
  348. case TVN_BEGINDRAG:
  349. {
  350. LPNMTREEVIEW treeNotify = (LPNMTREEVIEW)lParam;
  351. TVITEM newItem;
  352. // get the item being dragged
  353. newItem = treeNotify->itemNew;
  354. // save the window being dragged
  355. TheHierarchyView->setDragWindow( (GameWindow *)newItem.lParam );
  356. TheHierarchyView->setDragTarget( NULL );
  357. // capture the mouse
  358. SetCapture( TheHierarchyView->getHierarchyHandle() );
  359. break;
  360. } // end begin left mouse drag
  361. } // end switch
  362. } // end hierarchy
  363. } // end switch
  364. return 0;
  365. } // end notify
  366. // ------------------------------------------------------------------------
  367. case WM_COMMAND:
  368. {
  369. // Int notifyCode = HIWORD( wParam );
  370. Int controlID = LOWORD( wParam );
  371. // HWND hWndControl = (HWND)lParam;
  372. switch( controlID )
  373. {
  374. // --------------------------------------------------------------------
  375. case MENU_HIERARCHY_MOVE_HERE:
  376. {
  377. GameWindow *drag = TheHierarchyView->getDragWindow();
  378. GameWindow *target = TheHierarchyView->getPopupTarget();
  379. // do the logic if after a sanity check on the targets
  380. if( TheHierarchyView->validateDragDropOperation( drag, target ) )
  381. TheGUIEditWindowManager->moveAheadOf( drag, target );
  382. // we're done with the drag and popup ops now
  383. TheHierarchyView->setDragWindow( NULL );
  384. TheHierarchyView->setDragTarget( NULL );
  385. TheHierarchyView->setPopupTarget( NULL );
  386. break;
  387. } // end hierarchy move window in heirarchy
  388. // --------------------------------------------------------------------
  389. case HIERARCHY_MAKE_CHILD_HERE:
  390. {
  391. GameWindow *drag = TheHierarchyView->getDragWindow();
  392. GameWindow *target = TheHierarchyView->getPopupTarget();
  393. // do the logic if after a sanity check on the targets
  394. if( TheHierarchyView->validateDragDropOperation( drag, target ) )
  395. TheGUIEditWindowManager->makeChildOf( drag, target );
  396. // we're done with the drag and popup ops now
  397. TheHierarchyView->setDragWindow( NULL );
  398. TheHierarchyView->setDragTarget( NULL );
  399. TheHierarchyView->setPopupTarget( NULL );
  400. break;
  401. } // end hierarchy, make child of
  402. // --------------------------------------------------------------------
  403. case HIERARCHY_POPUP_MOVE:
  404. {
  405. GameWindow *target = TheHierarchyView->getPopupTarget();
  406. // sanity
  407. if( target == NULL )
  408. break;
  409. //
  410. // just to be safe, unselect all other windows, select this
  411. // one, and go into move mode
  412. //
  413. TheEditor->clearSelections();
  414. TheEditor->selectWindow( target );
  415. TheEditor->setMode( MODE_DRAG_MOVE );
  416. // set the locatoin of the move to the window position for now
  417. ICoord2D pos;
  418. target->winGetScreenPosition( &pos.x, &pos.y );
  419. TheEditWindow->setDragMoveDest( &pos );
  420. TheEditWindow->setDragMoveOrigin( &pos );
  421. break;
  422. } // end move
  423. // --------------------------------------------------------------------
  424. case HIERARCHY_POPUP_DELETE:
  425. {
  426. GameWindow *target = TheHierarchyView->getPopupTarget();
  427. if( target )
  428. TheEditor->deleteWindow( target );
  429. break;
  430. } // end delete
  431. // --------------------------------------------------------------------
  432. case HIERARCHY_POPUP_PROPERTIES:
  433. {
  434. GameWindow *target = TheHierarchyView->getPopupTarget();
  435. if( target )
  436. {
  437. POINT p;
  438. GetCursorPos( &p );
  439. ScreenToClient( TheEditWindow->getWindowHandle(), &p );
  440. InitPropertiesDialog( target, p.x, p.y );
  441. } // end if
  442. break;
  443. } // end properties
  444. // --------------------------------------------------------------------
  445. case IDOK:
  446. break;
  447. // --------------------------------------------------------------------
  448. case IDCANCEL:
  449. break;
  450. } // end switch( LOWORD( wParam ) )
  451. return 0;
  452. } // end of WM_COMMAND
  453. // ------------------------------------------------------------------------
  454. default:
  455. return 0;
  456. } // end of switch
  457. } // end dialogProc
  458. // HierarchyView::findItemEntry ===============================================
  459. /** Workhorse to find the tree item anywhere in the tree with the
  460. * matching data pointer of this game window */
  461. //=============================================================================
  462. HTREEITEM HierarchyView::findItemEntry( HTREEITEM node, GameWindow *window )
  463. {
  464. // end of recursion
  465. if( node == NULL || window == NULL )
  466. return NULL;
  467. // is it in this node
  468. TVITEM item;
  469. item.hItem = node;
  470. item.lParam = NULL;
  471. item.mask = TVIF_HANDLE | TVIF_PARAM;
  472. TreeView_GetItem( m_tree, &item );
  473. if( (GameWindow *)item.lParam == window )
  474. return node;
  475. // not there, check our children
  476. HTREEITEM child;
  477. HTREEITEM found = NULL;
  478. for( child = TreeView_GetNextItem( m_tree, node, TVGN_CHILD );
  479. child;
  480. child = TreeView_GetNextItem( m_tree, child, TVGN_NEXT ) )
  481. {
  482. found = findItemEntry( child, window );
  483. if( found )
  484. return found;
  485. } // end if
  486. // not there, check the siblings
  487. return findItemEntry( TreeView_GetNextItem( m_tree, node, TVGN_NEXT ),
  488. window );
  489. } // end findItemEntry
  490. // HierarchyView::findTreeEntry ===============================================
  491. /** Find the game window entry in the hierarchy tree, if found the
  492. * item in the tree will be returned containing the window */
  493. //=============================================================================
  494. HTREEITEM HierarchyView::findTreeEntry( GameWindow *window )
  495. {
  496. // no-op
  497. if( window == NULL )
  498. return NULL;
  499. // get root and search from there
  500. return findItemEntry( TreeView_GetRoot( m_tree ), window );
  501. } // end findTreeEntry
  502. // HierarchyView::addWindowToTree =============================================
  503. /** Add a single window to the hierarchy tree */
  504. //=============================================================================
  505. void HierarchyView::addWindowToTree( GameWindow *window,
  506. HTREEITEM treeParent,
  507. HierarchyOption option,
  508. Bool addChildren,
  509. Bool addSiblings )
  510. {
  511. HTREEITEM newItem = NULL;
  512. // end of recursion
  513. if( window == NULL )
  514. return;
  515. // add only if not in tree already
  516. newItem = findTreeEntry( window );
  517. if( newItem == NULL )
  518. {
  519. // setup insert struct
  520. TVINSERTSTRUCT insert;
  521. insert.hParent = treeParent;
  522. if( option == HIERARCHY_ADD_AT_TOP )
  523. insert.hInsertAfter = TVI_FIRST;
  524. else
  525. insert.hInsertAfter = TVI_LAST;
  526. insert.itemex.mask = TVIF_TEXT | TVIF_PARAM;
  527. insert.itemex.lParam = (LPARAM)window; // attach window to this item in lParam
  528. //
  529. // if the window has a name use it in the tree view, otherwise use a
  530. // name based on the type of the window
  531. //
  532. insert.itemex.pszText = getWindowTreeName( window );
  533. // add the item
  534. newItem = TreeView_InsertItem( m_tree, &insert );
  535. // sanity
  536. if( newItem == NULL )
  537. {
  538. DEBUG_LOG(( "Error adding window to tree\n" ));
  539. assert( 0 );
  540. return;
  541. } // end if
  542. } // end if, not in already
  543. //
  544. // add children if requested, but not on gadgets no matter what becuase
  545. // they are "atomic units", except for tab controls.
  546. //
  547. if( addChildren && TheEditor->windowIsGadget( window ) == FALSE || (window->winGetStyle() & GWS_TAB_CONTROL) )
  548. {
  549. GameWindow *child;
  550. for( child = window->winGetChild(); child; child = child->winGetNext() )
  551. addWindowToTree( child, newItem, HIERARCHY_ADD_AT_BOTTOM, TRUE, TRUE );
  552. } // end if
  553. // add siblings if requested
  554. if( addSiblings )
  555. addWindowToTree( window->winGetNext(), treeParent, option,
  556. addChildren, addSiblings );
  557. } // end addWindowToTree
  558. ///////////////////////////////////////////////////////////////////////////////
  559. // PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
  560. ///////////////////////////////////////////////////////////////////////////////
  561. // HierarchyView::HierarchyView ===============================================
  562. /** */
  563. //=============================================================================
  564. HierarchyView::HierarchyView( void )
  565. {
  566. m_dialog = NULL;
  567. m_tree = NULL;
  568. dialogPos.x = dialogPos.y = 0;
  569. dialogSize.x = dialogSize.y = 0;
  570. m_dragWindow = NULL;
  571. m_dragTarget = NULL;
  572. m_popupTarget = NULL;
  573. } // end HierarchyView
  574. // HierarchyView::~HierarchyView ==============================================
  575. /** */
  576. //=============================================================================
  577. HierarchyView::~HierarchyView( void )
  578. {
  579. // call the shutdown
  580. shutdown();
  581. } // end ~HierarchyView
  582. // HierarchyView::init =========================================================
  583. /** Create the control palette */
  584. //=============================================================================
  585. void HierarchyView::init( void )
  586. {
  587. RECT dialogRect;
  588. RECT appRect;
  589. // create the modless dialog box
  590. m_dialog = CreateDialog( TheEditor->getInstance(),
  591. (LPCSTR)HIERARCHY_DIALOG,
  592. TheEditor->getWindowHandle(),
  593. (DLGPROC)dialogProc );
  594. // display the dialog
  595. ShowWindow( m_dialog, SW_SHOW );
  596. // get the size of the control palette
  597. GetWindowRect( m_dialog, &dialogRect );
  598. dialogSize.x = dialogRect.right - dialogRect.left;
  599. dialogSize.y = dialogRect.bottom - dialogRect.top;
  600. POINT p;
  601. p.x = dialogRect.left;
  602. p.y = dialogRect.top;
  603. ScreenToClient( TheEditor->getWindowHandle(), &p );
  604. dialogPos.x = p.x;
  605. dialogPos.y = p.y;
  606. // get the rect of the app window
  607. GetClientRect( TheEditor->getWindowHandle(), &appRect );
  608. // place control palette at the top right of client area in edit window
  609. MoveWindow( m_dialog,
  610. appRect.right - dialogSize.x, 0,
  611. dialogSize.x, dialogSize.y,
  612. TRUE );
  613. // keep a handle to the tree
  614. m_tree = GetDlgItem( m_dialog, TREE_HIERARCHY );
  615. } // end init
  616. // HierarchyView::reset =======================================================
  617. /** Reset everything about our hierarchy view */
  618. //=============================================================================
  619. void HierarchyView::reset( void )
  620. {
  621. // reset the tree control
  622. HTREEITEM parentItem = TreeView_GetRoot( m_tree );
  623. SendMessage( m_tree, TVM_EXPAND, TVE_COLLAPSERESET, (LPARAM)parentItem );
  624. } // end reset
  625. // HierarchyView::shutdown ====================================================
  626. /** Destroy the control palette and all data associated with it */
  627. //=============================================================================
  628. void HierarchyView::shutdown( void )
  629. {
  630. // destroy the control palette window
  631. DestroyWindow( m_dialog );
  632. m_dialog = NULL;
  633. m_tree = NULL;
  634. } // end shutdown
  635. // HierarchyView::getWindowTreeName ===========================================
  636. /** Given a window, return a string representation for that window in
  637. * the hierarchy view */
  638. //=============================================================================
  639. char *HierarchyView::getWindowTreeName( GameWindow *window )
  640. {
  641. static char buffer[ 256 ];
  642. // init buffer to return to nothing
  643. strcpy( buffer, "" );
  644. // sanity
  645. if( window == NULL )
  646. return buffer;
  647. // no name available, construct one based on type
  648. Int style = window->winGetStyle();
  649. if( BitTest( style, GWS_PUSH_BUTTON ) )
  650. strcpy( buffer, "Button" );
  651. else if( BitTest( style, GWS_RADIO_BUTTON ) )
  652. strcpy( buffer, "Radio Button" );
  653. else if( BitTest( style, GWS_TAB_CONTROL ) )
  654. strcpy( buffer, "Tab Control" );
  655. else if( BitTest( style, GWS_CHECK_BOX ) )
  656. strcpy( buffer, "Check Box" );
  657. else if( BitTest( style, GWS_HORZ_SLIDER ) )
  658. strcpy( buffer, "Horizontal Slider" );
  659. else if( BitTest( style, GWS_VERT_SLIDER ) )
  660. strcpy( buffer, "Vertical Slider" );
  661. else if( BitTest( style, GWS_STATIC_TEXT ) )
  662. strcpy( buffer, "Static Text" );
  663. else if( BitTest( style, GWS_ENTRY_FIELD ) )
  664. strcpy( buffer, "Text Entry" );
  665. else if( BitTest( style, GWS_SCROLL_LISTBOX ) )
  666. strcpy( buffer, "Listbox" );
  667. else if( BitTest( style, GWS_PROGRESS_BAR ) )
  668. strcpy( buffer, "Progress Bar" );
  669. else if( BitTest( style, GWS_USER_WINDOW ) )
  670. strcpy( buffer, "User Window" );
  671. else if( BitTest( style, GWS_TAB_PANE ) )
  672. strcpy( buffer, "Tab Pane" );
  673. else if( BitTest( style, GWS_COMBO_BOX ) )
  674. strcpy( buffer, "Combo Box" );
  675. else
  676. strcpy( buffer, "Undefined" );
  677. // if window has a name, concatenate it on the end
  678. WinInstanceData *instData = window->winGetInstanceData();
  679. if( !instData->m_decoratedNameString.isEmpty() )
  680. {
  681. strcat( buffer, ": " );
  682. strcat( buffer, instData->m_decoratedNameString.str() );
  683. } // end if
  684. return buffer;
  685. } // end getWindowTreeName
  686. // HierarchyView::addWindow ===================================================
  687. /** Add a window to the hierarchy view AND any of it's children */
  688. //=============================================================================
  689. void HierarchyView::addWindow( GameWindow *window, HierarchyOption option )
  690. {
  691. // sanity
  692. if( window == NULL || m_dialog == NULL )
  693. return;
  694. // do not add again if already in the tree
  695. if( findTreeEntry( window ) != NULL )
  696. return;
  697. // get the parent tree entry to this window, NULL if no parent
  698. GameWindow *parent = window->winGetParent();
  699. HTREEITEM parentItem = findTreeEntry( parent );
  700. // add this window
  701. addWindowToTree( window, parentItem, option, TRUE, FALSE );
  702. //
  703. // force the tree control to redraw, it seems to have problems updating
  704. // the plus signs, lame ass Microsoft
  705. //
  706. InvalidateRect( m_tree, NULL, TRUE );
  707. } // end addWindow
  708. // HierarchyView::removeWindow ================================================
  709. /** Remove the window from the hierarchy tree view */
  710. //=============================================================================
  711. void HierarchyView::removeWindow( GameWindow *window )
  712. {
  713. HTREEITEM item;
  714. // sanity
  715. if( window == NULL )
  716. return;
  717. // if this window is the drag window clean that mode up
  718. if( window == m_dragWindow )
  719. m_dragWindow = NULL;
  720. // clean up drag target
  721. if( window == m_dragTarget )
  722. m_dragTarget = NULL;
  723. // if this window is the popup target remove it
  724. if( window == m_popupTarget )
  725. m_popupTarget = NULL;
  726. // find this entry in the tree
  727. item = findTreeEntry( window );
  728. // if not in tree nothing to do
  729. if( item == NULL )
  730. return;
  731. // remove it from the tree
  732. TreeView_DeleteItem( m_tree, item );
  733. } // end removeWindow
  734. // HierarchyView::bringWindowToTop ============================================
  735. /** Bring the window to the top of its parent list in the hierarchy
  736. * view, if no parent is present to the top of the hierarchy then */
  737. //=============================================================================
  738. void HierarchyView::bringWindowToTop( GameWindow *window )
  739. {
  740. // sanity
  741. if( window == NULL )
  742. return;
  743. // find this window entry
  744. HTREEITEM item = findTreeEntry( window );
  745. if( item == NULL )
  746. {
  747. DEBUG_LOG(( "Cannot bring window to top, no entry in tree!\n" ));
  748. assert( 0 );
  749. return;
  750. } // end if
  751. // remove the entry from the tree
  752. removeWindow( window );
  753. // find the parent tree entry
  754. HTREEITEM itemParent = findTreeEntry( window->winGetParent() );
  755. // add the window as a child of the parent entry at the top of it's list
  756. addWindowToTree( window, itemParent, HIERARCHY_ADD_AT_TOP, TRUE, FALSE );
  757. } // end bringWindowToTop
  758. // HierarchyView::updateWindowName ============================================
  759. /** A window name may have been updated, reconstruct its hierarchy
  760. * tree entry cause we like to show names when we have them */
  761. //=============================================================================
  762. void HierarchyView::updateWindowName( GameWindow *window )
  763. {
  764. // sanity
  765. if( window == NULL )
  766. return;
  767. // get the tree entry
  768. HTREEITEM item = findTreeEntry( window );
  769. if( item == NULL )
  770. {
  771. DEBUG_LOG(( "updateWindowName: No hierarchy entry for window!\n" ));
  772. assert( 0 );
  773. return;
  774. } // end if
  775. // setup the item to modify in the tree
  776. TVITEM modify;
  777. modify.mask = TVIF_HANDLE | TVIF_TEXT;
  778. modify.hItem = item;
  779. modify.pszText = getWindowTreeName( window );
  780. // modify the item
  781. TreeView_SetItem( m_tree, &modify );
  782. } // end updateWindowName
  783. // HierarchyView::getDialogPos ================================================
  784. /** Get the dialog position as recorded from the static */
  785. //=============================================================================
  786. void HierarchyView::getDialogPos( ICoord2D *pos )
  787. {
  788. // sanity
  789. if( pos == NULL )
  790. return;
  791. *pos = dialogPos;
  792. } // end getDialogPos
  793. // HierarchyView::getDialogSize ===============================================
  794. /** Get the dialog size as recorded from the static */
  795. //=============================================================================
  796. void HierarchyView::getDialogSize( ICoord2D *size )
  797. {
  798. // sanity
  799. if( size == NULL )
  800. return;
  801. *size = dialogSize;
  802. } // end getDialogSize
  803. // HierarchyView::setDialogPos ================================================
  804. /** */
  805. //=============================================================================
  806. void HierarchyView::setDialogPos( ICoord2D *pos )
  807. {
  808. // sanity
  809. if( pos )
  810. dialogPos = *pos;
  811. MoveWindow( m_dialog, dialogPos.x, dialogPos.y,
  812. dialogSize.x, dialogSize.y, TRUE );
  813. } // end setDialogPos
  814. // HierarchyView::setDialogSize ===============================================
  815. /** */
  816. //=============================================================================
  817. void HierarchyView::setDialogSize( ICoord2D *size )
  818. {
  819. // sanity
  820. if( size )
  821. dialogSize = *size;
  822. MoveWindow( m_dialog, dialogPos.x, dialogPos.y,
  823. dialogSize.x, dialogSize.y, TRUE );
  824. } // end setDialogSize
  825. // HierarchyView::moveWindowAheadOf ===========================================
  826. /** Move the window hierarchy representation to be just ahead of the
  827. * hierarchy entry of 'aheadOf' */
  828. //=============================================================================
  829. void HierarchyView::moveWindowAheadOf( GameWindow *window,
  830. GameWindow *aheadOf )
  831. {
  832. // sanity
  833. if( window == NULL )
  834. return;
  835. // get the window hierarchy entry
  836. removeWindow( window );
  837. // we'll say and aheadOf of NULL means put at the top
  838. if( aheadOf == NULL )
  839. {
  840. addWindow( window, HIERARCHY_ADD_AT_TOP );
  841. return;
  842. } // end if
  843. // get the hierarchy item of the aheadOf window
  844. HTREEITEM aheadOfItem = findTreeEntry( aheadOf );
  845. if( aheadOfItem == NULL )
  846. {
  847. DEBUG_LOG(( "moveWindowAheadOf: aheadOf has no hierarchy entry!\n" ));
  848. assert( 0 );
  849. return;
  850. } // end iof
  851. //
  852. // get the parent item we will be inserting the new entry at, a parent
  853. // of NULL is OK and will put it at the root of the tree
  854. //
  855. HTREEITEM parentItem = TreeView_GetNextItem( m_tree, aheadOfItem, TVGN_PARENT );
  856. //
  857. // get the item that we will be inserting after (just previous to
  858. // 'aheadOfItem' ... this can also be NULL for putting at the head
  859. //
  860. HTREEITEM prevItem = TreeView_GetNextItem( m_tree, aheadOfItem, TVGN_PREVIOUS );
  861. // setup insert struct
  862. TVINSERTSTRUCT insert;
  863. insert.itemex.mask = TVIF_TEXT | TVIF_PARAM;
  864. insert.hParent = parentItem;
  865. if( prevItem == NULL )
  866. insert.hInsertAfter = TVI_FIRST;
  867. else
  868. insert.hInsertAfter = prevItem;
  869. insert.itemex.lParam = (LPARAM)window; // attach window to this item in lParam
  870. insert.itemex.pszText = getWindowTreeName( window );
  871. // add the item
  872. HTREEITEM newItem = TreeView_InsertItem( m_tree, &insert );
  873. // sanity
  874. if( newItem == NULL )
  875. {
  876. DEBUG_LOG(( "moveWindowAheadOf: Error adding window to tree\n" ));
  877. assert( 0 );
  878. return;
  879. } // end if
  880. //
  881. // add ALL the children of this window as well, do not worry about
  882. // gadget children
  883. //
  884. if( TheEditor->windowIsGadget( window ) == FALSE )
  885. {
  886. GameWindow *child = window->winGetChild();
  887. addWindowToTree( child, newItem, HIERARCHY_ADD_AT_BOTTOM, TRUE, TRUE );
  888. } // end if
  889. } // end moveWindowAheadOf
  890. // HierarchyView::moveWindowChildOf ===========================================
  891. /** Move the hierarchy entry for window so that it is now the first
  892. * child in the list under parent */
  893. //=============================================================================
  894. void HierarchyView::moveWindowChildOf( GameWindow *window, GameWindow *parent )
  895. {
  896. // sanity
  897. if( window == NULL )
  898. return;
  899. // remvoe the window from the hierarchy
  900. removeWindow( window );
  901. // if parent is NULL we'll put at top of list
  902. if( parent == NULL )
  903. {
  904. addWindow( window, HIERARCHY_ADD_AT_TOP );
  905. return;
  906. } // end if
  907. // find the entry of the parent
  908. HTREEITEM parentItem = findTreeEntry( parent );
  909. if( parentItem == NULL )
  910. {
  911. DEBUG_LOG(( "moveWindowChildOf: No parent entry\n" ));
  912. assert( 0 );
  913. return;
  914. } // end if
  915. // add the window as child of the parent at the top, dont forget to
  916. // also add the children of the window too!
  917. addWindowToTree( window, parentItem, HIERARCHY_ADD_AT_TOP, TRUE, FALSE );
  918. } // end moveWindowChildOf
  919. // HierarchyView::treePointToItem =============================================
  920. /** Given the location (x,y) in TREE COORDINATES, correlate that to
  921. * a tree item, if any */
  922. //=============================================================================
  923. HTREEITEM HierarchyView::treePointToItem( Int x, Int y )
  924. {
  925. // which tree item are we now over
  926. TVHITTESTINFO hitTest;
  927. hitTest.pt.x = x;
  928. hitTest.pt.y = y;
  929. hitTest.hItem = NULL;
  930. hitTest.flags = TVHT_ONITEM;
  931. return TreeView_HitTest( TheHierarchyView->getTreeHandle(), &hitTest );
  932. } // end treePointToItem
  933. // HierarchyView::getWindowFromItem ===========================================
  934. /** Get the game window we stored as the user data lParam in the tree
  935. * item */
  936. //=============================================================================
  937. GameWindow *HierarchyView::getWindowFromItem( HTREEITEM treeItem )
  938. {
  939. // sanity
  940. if( treeItem == NULL )
  941. return NULL;
  942. // get the node info from the tree item we're over
  943. TVITEM itemInfo;
  944. GameWindow *window;
  945. itemInfo.hItem = treeItem;
  946. itemInfo.lParam = NULL;
  947. itemInfo.mask = TVIF_HANDLE | TVIF_PARAM;
  948. TreeView_GetItem( m_tree, &itemInfo );
  949. window = (GameWindow *)itemInfo.lParam;
  950. assert( window );
  951. return window;
  952. } // end getWindowFromItem
  953. // HierarchyView::selectWindow ================================================
  954. /** Select the tree item */
  955. //=============================================================================
  956. void HierarchyView::selectWindow( GameWindow *window )
  957. {
  958. HTREEITEM item = NULL;
  959. // get the item associated with the window
  960. if( window )
  961. item = findTreeEntry( window );
  962. // select the item, or no item NULL will select nothing
  963. TreeView_SelectItem( m_tree, item );
  964. TreeView_Expand( m_tree, item, 0 );
  965. } // end selectWindow
  966. // HierarchyView::validateDragDropOperation ===================================
  967. /** Return TRUE if the drag drop operation of source onto target
  968. * is logically OK. It's not OK if target is a child of source because
  969. * you cannot move a parent window into it's own child list. */
  970. //=============================================================================
  971. Bool HierarchyView::validateDragDropOperation( GameWindow *source,
  972. GameWindow *target )
  973. {
  974. // sanity
  975. if( source == NULL || target == NULL )
  976. return FALSE;
  977. // if target is the source or is a child of source in any way this is illegal
  978. GameWindow *other = target;
  979. while( other )
  980. {
  981. if( source == other )
  982. return FALSE;
  983. other = other->winGetParent();
  984. } // end while
  985. // everything is ok
  986. return TRUE;
  987. } // end validateDragDropOperation