HierarchyView.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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. #if USE_FAST_FIND_ITEM
  468. return m_treeHash[window];
  469. #else
  470. // is it in this node
  471. TVITEM item;
  472. item.hItem = node;
  473. item.lParam = NULL;
  474. item.mask = TVIF_HANDLE | TVIF_PARAM;
  475. TreeView_GetItem( m_tree, &item );
  476. if( (GameWindow *)item.lParam == window )
  477. return node;
  478. // not there, check our children
  479. HTREEITEM child;
  480. HTREEITEM found = NULL;
  481. for( child = TreeView_GetNextItem( m_tree, node, TVGN_CHILD );
  482. child;
  483. child = TreeView_GetNextItem( m_tree, child, TVGN_NEXT ) )
  484. {
  485. found = findItemEntry( child, window );
  486. if( found )
  487. return found;
  488. } // end if
  489. // not there, check the siblings
  490. return findItemEntry( TreeView_GetNextItem( m_tree, node, TVGN_NEXT ),
  491. window );
  492. #endif
  493. } // end findItemEntry
  494. // HierarchyView::findTreeEntry ===============================================
  495. /** Find the game window entry in the hierarchy tree, if found the
  496. * item in the tree will be returned containing the window */
  497. //=============================================================================
  498. HTREEITEM HierarchyView::findTreeEntry( GameWindow *window )
  499. {
  500. // no-op
  501. if( window == NULL )
  502. return NULL;
  503. // get root and search from there
  504. return findItemEntry( TreeView_GetRoot( m_tree ), window );
  505. } // end findTreeEntry
  506. // HierarchyView::addWindowToTree =============================================
  507. /** Add a single window to the hierarchy tree */
  508. //=============================================================================
  509. void HierarchyView::addWindowToTree( GameWindow *window,
  510. HTREEITEM treeParent,
  511. HierarchyOption option,
  512. Bool addChildren,
  513. Bool addSiblings )
  514. {
  515. HTREEITEM newItem = NULL;
  516. // end of recursion
  517. if( window == NULL )
  518. return;
  519. // add only if not in tree already
  520. newItem = findTreeEntry( window );
  521. if( newItem == NULL )
  522. {
  523. // setup insert struct
  524. TVINSERTSTRUCT insert;
  525. insert.hParent = treeParent;
  526. if( option == HIERARCHY_ADD_AT_TOP )
  527. insert.hInsertAfter = TVI_FIRST;
  528. else
  529. insert.hInsertAfter = TVI_LAST;
  530. insert.itemex.mask = TVIF_TEXT | TVIF_PARAM;
  531. insert.itemex.lParam = (LPARAM)window; // attach window to this item in lParam
  532. //
  533. // if the window has a name use it in the tree view, otherwise use a
  534. // name based on the type of the window
  535. //
  536. insert.itemex.pszText = getWindowTreeName( window );
  537. // add the item
  538. newItem = TreeView_InsertItem( m_tree, &insert );
  539. // sanity
  540. if( newItem == NULL )
  541. {
  542. DEBUG_LOG(( "Error adding window to tree\n" ));
  543. assert( 0 );
  544. return;
  545. } // end if
  546. #if USE_FAST_FIND_ITEM
  547. m_treeHash[window] = newItem;
  548. #endif
  549. } // end if, not in already
  550. //
  551. // add children if requested, but not on gadgets no matter what becuase
  552. // they are "atomic units", except for tab controls.
  553. //
  554. if( addChildren && TheEditor->windowIsGadget( window ) == FALSE || (window->winGetStyle() & GWS_TAB_CONTROL) )
  555. {
  556. GameWindow *child;
  557. for( child = window->winGetChild(); child; child = child->winGetNext() )
  558. addWindowToTree( child, newItem, HIERARCHY_ADD_AT_BOTTOM, TRUE, TRUE );
  559. } // end if
  560. // add siblings if requested
  561. if( addSiblings )
  562. addWindowToTree( window->winGetNext(), treeParent, option,
  563. addChildren, addSiblings );
  564. } // end addWindowToTree
  565. ///////////////////////////////////////////////////////////////////////////////
  566. // PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
  567. ///////////////////////////////////////////////////////////////////////////////
  568. // HierarchyView::HierarchyView ===============================================
  569. /** */
  570. //=============================================================================
  571. HierarchyView::HierarchyView( void )
  572. {
  573. m_dialog = NULL;
  574. m_tree = NULL;
  575. dialogPos.x = dialogPos.y = 0;
  576. dialogSize.x = dialogSize.y = 0;
  577. m_dragWindow = NULL;
  578. m_dragTarget = NULL;
  579. m_popupTarget = NULL;
  580. } // end HierarchyView
  581. // HierarchyView::~HierarchyView ==============================================
  582. /** */
  583. //=============================================================================
  584. HierarchyView::~HierarchyView( void )
  585. {
  586. // call the shutdown
  587. shutdown();
  588. } // end ~HierarchyView
  589. // HierarchyView::init =========================================================
  590. /** Create the control palette */
  591. //=============================================================================
  592. void HierarchyView::init( void )
  593. {
  594. RECT dialogRect;
  595. RECT appRect;
  596. // create the modless dialog box
  597. m_dialog = CreateDialog( TheEditor->getInstance(),
  598. (LPCSTR)HIERARCHY_DIALOG,
  599. TheEditor->getWindowHandle(),
  600. (DLGPROC)dialogProc );
  601. // display the dialog
  602. ShowWindow( m_dialog, SW_SHOW );
  603. // get the size of the control palette
  604. GetWindowRect( m_dialog, &dialogRect );
  605. dialogSize.x = dialogRect.right - dialogRect.left;
  606. dialogSize.y = dialogRect.bottom - dialogRect.top;
  607. POINT p;
  608. p.x = dialogRect.left;
  609. p.y = dialogRect.top;
  610. ScreenToClient( TheEditor->getWindowHandle(), &p );
  611. dialogPos.x = p.x;
  612. dialogPos.y = p.y;
  613. // get the rect of the app window
  614. GetClientRect( TheEditor->getWindowHandle(), &appRect );
  615. // place control palette at the top right of client area in edit window
  616. MoveWindow( m_dialog,
  617. appRect.right - dialogSize.x, 0,
  618. dialogSize.x, dialogSize.y,
  619. TRUE );
  620. // keep a handle to the tree
  621. m_tree = GetDlgItem( m_dialog, TREE_HIERARCHY );
  622. } // end init
  623. // HierarchyView::reset =======================================================
  624. /** Reset everything about our hierarchy view */
  625. //=============================================================================
  626. void HierarchyView::reset( void )
  627. {
  628. // reset the tree control
  629. HTREEITEM parentItem = TreeView_GetRoot( m_tree );
  630. SendMessage( m_tree, TVM_EXPAND, TVE_COLLAPSERESET, (LPARAM)parentItem );
  631. #if USE_FAST_FIND_ITEM
  632. m_treeHash.clear();
  633. #endif
  634. } // end reset
  635. // HierarchyView::shutdown ====================================================
  636. /** Destroy the control palette and all data associated with it */
  637. //=============================================================================
  638. void HierarchyView::shutdown( void )
  639. {
  640. // destroy the control palette window
  641. DestroyWindow( m_dialog );
  642. m_dialog = NULL;
  643. m_tree = NULL;
  644. } // end shutdown
  645. // HierarchyView::getWindowTreeName ===========================================
  646. /** Given a window, return a string representation for that window in
  647. * the hierarchy view */
  648. //=============================================================================
  649. char *HierarchyView::getWindowTreeName( GameWindow *window )
  650. {
  651. static char buffer[ 256 ];
  652. // init buffer to return to nothing
  653. strcpy( buffer, "" );
  654. // sanity
  655. if( window == NULL )
  656. return buffer;
  657. // no name available, construct one based on type
  658. Int style = window->winGetStyle();
  659. if( BitTest( style, GWS_PUSH_BUTTON ) )
  660. strcpy( buffer, "Button" );
  661. else if( BitTest( style, GWS_RADIO_BUTTON ) )
  662. strcpy( buffer, "Radio Button" );
  663. else if( BitTest( style, GWS_TAB_CONTROL ) )
  664. strcpy( buffer, "Tab Control" );
  665. else if( BitTest( style, GWS_CHECK_BOX ) )
  666. strcpy( buffer, "Check Box" );
  667. else if( BitTest( style, GWS_HORZ_SLIDER ) )
  668. strcpy( buffer, "Horizontal Slider" );
  669. else if( BitTest( style, GWS_VERT_SLIDER ) )
  670. strcpy( buffer, "Vertical Slider" );
  671. else if( BitTest( style, GWS_STATIC_TEXT ) )
  672. strcpy( buffer, "Static Text" );
  673. else if( BitTest( style, GWS_ENTRY_FIELD ) )
  674. strcpy( buffer, "Text Entry" );
  675. else if( BitTest( style, GWS_SCROLL_LISTBOX ) )
  676. strcpy( buffer, "Listbox" );
  677. else if( BitTest( style, GWS_PROGRESS_BAR ) )
  678. strcpy( buffer, "Progress Bar" );
  679. else if( BitTest( style, GWS_USER_WINDOW ) )
  680. strcpy( buffer, "User Window" );
  681. else if( BitTest( style, GWS_TAB_PANE ) )
  682. strcpy( buffer, "Tab Pane" );
  683. else if( BitTest( style, GWS_COMBO_BOX ) )
  684. strcpy( buffer, "Combo Box" );
  685. else
  686. strcpy( buffer, "Undefined" );
  687. // if window has a name, concatenate it on the end
  688. WinInstanceData *instData = window->winGetInstanceData();
  689. if( !instData->m_decoratedNameString.isEmpty() )
  690. {
  691. strcat( buffer, ": " );
  692. strcat( buffer, instData->m_decoratedNameString.str() );
  693. } // end if
  694. return buffer;
  695. } // end getWindowTreeName
  696. // HierarchyView::addWindow ===================================================
  697. /** Add a window to the hierarchy view AND any of it's children */
  698. //=============================================================================
  699. void HierarchyView::addWindow( GameWindow *window, HierarchyOption option )
  700. {
  701. // sanity
  702. if( window == NULL || m_dialog == NULL )
  703. return;
  704. // do not add again if already in the tree
  705. if( findTreeEntry( window ) != NULL )
  706. return;
  707. // get the parent tree entry to this window, NULL if no parent
  708. GameWindow *parent = window->winGetParent();
  709. HTREEITEM parentItem = findTreeEntry( parent );
  710. // add this window
  711. addWindowToTree( window, parentItem, option, TRUE, FALSE );
  712. //
  713. // force the tree control to redraw, it seems to have problems updating
  714. // the plus signs, lame ass Microsoft
  715. //
  716. InvalidateRect( m_tree, NULL, TRUE );
  717. } // end addWindow
  718. // HierarchyView::removeWindow ================================================
  719. /** Remove the window from the hierarchy tree view */
  720. //=============================================================================
  721. void HierarchyView::removeWindow( GameWindow *window )
  722. {
  723. HTREEITEM item;
  724. // sanity
  725. if( window == NULL )
  726. return;
  727. // if this window is the drag window clean that mode up
  728. if( window == m_dragWindow )
  729. m_dragWindow = NULL;
  730. // clean up drag target
  731. if( window == m_dragTarget )
  732. m_dragTarget = NULL;
  733. // if this window is the popup target remove it
  734. if( window == m_popupTarget )
  735. m_popupTarget = NULL;
  736. // find this entry in the tree
  737. item = findTreeEntry( window );
  738. // if not in tree nothing to do
  739. if( item == NULL )
  740. return;
  741. // remove it from the tree
  742. TreeView_DeleteItem( m_tree, item );
  743. #if USE_FAST_FIND_ITEM
  744. TreeHash::iterator find = m_treeHash.find(window);
  745. if (find != m_treeHash.end())
  746. m_treeHash.erase(find);
  747. #endif
  748. } // end removeWindow
  749. // HierarchyView::bringWindowToTop ============================================
  750. /** Bring the window to the top of its parent list in the hierarchy
  751. * view, if no parent is present to the top of the hierarchy then */
  752. //=============================================================================
  753. void HierarchyView::bringWindowToTop( GameWindow *window )
  754. {
  755. // sanity
  756. if( window == NULL )
  757. return;
  758. // find this window entry
  759. HTREEITEM item = findTreeEntry( window );
  760. if( item == NULL )
  761. {
  762. DEBUG_LOG(( "Cannot bring window to top, no entry in tree!\n" ));
  763. assert( 0 );
  764. return;
  765. } // end if
  766. // remove the entry from the tree
  767. removeWindow( window );
  768. // find the parent tree entry
  769. HTREEITEM itemParent = findTreeEntry( window->winGetParent() );
  770. // add the window as a child of the parent entry at the top of it's list
  771. addWindowToTree( window, itemParent, HIERARCHY_ADD_AT_TOP, TRUE, FALSE );
  772. } // end bringWindowToTop
  773. // HierarchyView::updateWindowName ============================================
  774. /** A window name may have been updated, reconstruct its hierarchy
  775. * tree entry cause we like to show names when we have them */
  776. //=============================================================================
  777. void HierarchyView::updateWindowName( GameWindow *window )
  778. {
  779. // sanity
  780. if( window == NULL )
  781. return;
  782. // get the tree entry
  783. HTREEITEM item = findTreeEntry( window );
  784. if( item == NULL )
  785. {
  786. DEBUG_LOG(( "updateWindowName: No hierarchy entry for window!\n" ));
  787. assert( 0 );
  788. return;
  789. } // end if
  790. // setup the item to modify in the tree
  791. TVITEM modify;
  792. modify.mask = TVIF_HANDLE | TVIF_TEXT;
  793. modify.hItem = item;
  794. modify.pszText = getWindowTreeName( window );
  795. // modify the item
  796. TreeView_SetItem( m_tree, &modify );
  797. } // end updateWindowName
  798. // HierarchyView::getDialogPos ================================================
  799. /** Get the dialog position as recorded from the static */
  800. //=============================================================================
  801. void HierarchyView::getDialogPos( ICoord2D *pos )
  802. {
  803. // sanity
  804. if( pos == NULL )
  805. return;
  806. *pos = dialogPos;
  807. } // end getDialogPos
  808. // HierarchyView::getDialogSize ===============================================
  809. /** Get the dialog size as recorded from the static */
  810. //=============================================================================
  811. void HierarchyView::getDialogSize( ICoord2D *size )
  812. {
  813. // sanity
  814. if( size == NULL )
  815. return;
  816. *size = dialogSize;
  817. } // end getDialogSize
  818. // HierarchyView::setDialogPos ================================================
  819. /** */
  820. //=============================================================================
  821. void HierarchyView::setDialogPos( ICoord2D *pos )
  822. {
  823. // sanity
  824. if( pos )
  825. dialogPos = *pos;
  826. MoveWindow( m_dialog, dialogPos.x, dialogPos.y,
  827. dialogSize.x, dialogSize.y, TRUE );
  828. } // end setDialogPos
  829. // HierarchyView::setDialogSize ===============================================
  830. /** */
  831. //=============================================================================
  832. void HierarchyView::setDialogSize( ICoord2D *size )
  833. {
  834. // sanity
  835. if( size )
  836. dialogSize = *size;
  837. MoveWindow( m_dialog, dialogPos.x, dialogPos.y,
  838. dialogSize.x, dialogSize.y, TRUE );
  839. } // end setDialogSize
  840. // HierarchyView::moveWindowAheadOf ===========================================
  841. /** Move the window hierarchy representation to be just ahead of the
  842. * hierarchy entry of 'aheadOf' */
  843. //=============================================================================
  844. void HierarchyView::moveWindowAheadOf( GameWindow *window,
  845. GameWindow *aheadOf )
  846. {
  847. // sanity
  848. if( window == NULL )
  849. return;
  850. // get the window hierarchy entry
  851. removeWindow( window );
  852. // we'll say and aheadOf of NULL means put at the top
  853. if( aheadOf == NULL )
  854. {
  855. addWindow( window, HIERARCHY_ADD_AT_TOP );
  856. return;
  857. } // end if
  858. // get the hierarchy item of the aheadOf window
  859. HTREEITEM aheadOfItem = findTreeEntry( aheadOf );
  860. if( aheadOfItem == NULL )
  861. {
  862. DEBUG_LOG(( "moveWindowAheadOf: aheadOf has no hierarchy entry!\n" ));
  863. assert( 0 );
  864. return;
  865. } // end iof
  866. //
  867. // get the parent item we will be inserting the new entry at, a parent
  868. // of NULL is OK and will put it at the root of the tree
  869. //
  870. HTREEITEM parentItem = TreeView_GetNextItem( m_tree, aheadOfItem, TVGN_PARENT );
  871. //
  872. // get the item that we will be inserting after (just previous to
  873. // 'aheadOfItem' ... this can also be NULL for putting at the head
  874. //
  875. HTREEITEM prevItem = TreeView_GetNextItem( m_tree, aheadOfItem, TVGN_PREVIOUS );
  876. // setup insert struct
  877. TVINSERTSTRUCT insert;
  878. insert.itemex.mask = TVIF_TEXT | TVIF_PARAM;
  879. insert.hParent = parentItem;
  880. if( prevItem == NULL )
  881. insert.hInsertAfter = TVI_FIRST;
  882. else
  883. insert.hInsertAfter = prevItem;
  884. insert.itemex.lParam = (LPARAM)window; // attach window to this item in lParam
  885. insert.itemex.pszText = getWindowTreeName( window );
  886. // add the item
  887. HTREEITEM newItem = TreeView_InsertItem( m_tree, &insert );
  888. // sanity
  889. if( newItem == NULL )
  890. {
  891. DEBUG_LOG(( "moveWindowAheadOf: Error adding window to tree\n" ));
  892. assert( 0 );
  893. return;
  894. } // end if
  895. //
  896. // add ALL the children of this window as well, do not worry about
  897. // gadget children
  898. //
  899. if( TheEditor->windowIsGadget( window ) == FALSE )
  900. {
  901. GameWindow *child = window->winGetChild();
  902. addWindowToTree( child, newItem, HIERARCHY_ADD_AT_BOTTOM, TRUE, TRUE );
  903. } // end if
  904. } // end moveWindowAheadOf
  905. // HierarchyView::moveWindowChildOf ===========================================
  906. /** Move the hierarchy entry for window so that it is now the first
  907. * child in the list under parent */
  908. //=============================================================================
  909. void HierarchyView::moveWindowChildOf( GameWindow *window, GameWindow *parent )
  910. {
  911. // sanity
  912. if( window == NULL )
  913. return;
  914. // remvoe the window from the hierarchy
  915. removeWindow( window );
  916. // if parent is NULL we'll put at top of list
  917. if( parent == NULL )
  918. {
  919. addWindow( window, HIERARCHY_ADD_AT_TOP );
  920. return;
  921. } // end if
  922. // find the entry of the parent
  923. HTREEITEM parentItem = findTreeEntry( parent );
  924. if( parentItem == NULL )
  925. {
  926. DEBUG_LOG(( "moveWindowChildOf: No parent entry\n" ));
  927. assert( 0 );
  928. return;
  929. } // end if
  930. // add the window as child of the parent at the top, dont forget to
  931. // also add the children of the window too!
  932. addWindowToTree( window, parentItem, HIERARCHY_ADD_AT_TOP, TRUE, FALSE );
  933. } // end moveWindowChildOf
  934. // HierarchyView::treePointToItem =============================================
  935. /** Given the location (x,y) in TREE COORDINATES, correlate that to
  936. * a tree item, if any */
  937. //=============================================================================
  938. HTREEITEM HierarchyView::treePointToItem( Int x, Int y )
  939. {
  940. // which tree item are we now over
  941. TVHITTESTINFO hitTest;
  942. hitTest.pt.x = x;
  943. hitTest.pt.y = y;
  944. hitTest.hItem = NULL;
  945. hitTest.flags = TVHT_ONITEM;
  946. return TreeView_HitTest( TheHierarchyView->getTreeHandle(), &hitTest );
  947. } // end treePointToItem
  948. // HierarchyView::getWindowFromItem ===========================================
  949. /** Get the game window we stored as the user data lParam in the tree
  950. * item */
  951. //=============================================================================
  952. GameWindow *HierarchyView::getWindowFromItem( HTREEITEM treeItem )
  953. {
  954. // sanity
  955. if( treeItem == NULL )
  956. return NULL;
  957. // get the node info from the tree item we're over
  958. TVITEM itemInfo;
  959. GameWindow *window;
  960. itemInfo.hItem = treeItem;
  961. itemInfo.lParam = NULL;
  962. itemInfo.mask = TVIF_HANDLE | TVIF_PARAM;
  963. TreeView_GetItem( m_tree, &itemInfo );
  964. window = (GameWindow *)itemInfo.lParam;
  965. assert( window );
  966. return window;
  967. } // end getWindowFromItem
  968. // HierarchyView::selectWindow ================================================
  969. /** Select the tree item */
  970. //=============================================================================
  971. void HierarchyView::selectWindow( GameWindow *window )
  972. {
  973. HTREEITEM item = NULL;
  974. // get the item associated with the window
  975. if( window )
  976. item = findTreeEntry( window );
  977. // select the item, or no item NULL will select nothing
  978. TreeView_SelectItem( m_tree, item );
  979. TreeView_Expand( m_tree, item, 0 );
  980. } // end selectWindow
  981. // HierarchyView::validateDragDropOperation ===================================
  982. /** Return TRUE if the drag drop operation of source onto target
  983. * is logically OK. It's not OK if target is a child of source because
  984. * you cannot move a parent window into it's own child list. */
  985. //=============================================================================
  986. Bool HierarchyView::validateDragDropOperation( GameWindow *source,
  987. GameWindow *target )
  988. {
  989. // sanity
  990. if( source == NULL || target == NULL )
  991. return FALSE;
  992. // if target is the source or is a child of source in any way this is illegal
  993. GameWindow *other = target;
  994. while( other )
  995. {
  996. if( source == other )
  997. return FALSE;
  998. other = other->winGetParent();
  999. } // end while
  1000. // everything is ok
  1001. return TRUE;
  1002. } // end validateDragDropOperation