GUIEditWindowManager.cpp 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617
  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: GUIEditWindowManager.cpp /////////////////////////////////////////////////////////////////
  24. // Created: Colin Day, July 2001
  25. // Desc: Window manager for the GUI edit tool, we want this up
  26. // fast and to look like what we use in the game so we're going
  27. // to use the WW3D window manager, and just override the
  28. // drawing functions to draw lines and images to the
  29. // display. We will also be adding our own functionality
  30. // here for editing and interacting with the GUI windows.
  31. ///////////////////////////////////////////////////////////////////////////////////////////////////
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include "Common/Debug.h"
  35. #include "GameClient/GadgetSlider.h"
  36. #include "GUIEditWindowManager.h"
  37. #include "EditWindow.h"
  38. #include "GUIEdit.h"
  39. #include "HierarchyView.h"
  40. // PUBLIC DATA ////////////////////////////////////////////////////////////////////////////////////
  41. GUIEditWindowManager *TheGUIEditWindowManager = NULL; ///< editor use only
  42. ///////////////////////////////////////////////////////////////////////////////////////////////////
  43. // PRIVATE FUNCTIONS //////////////////////////////////////////////////////////////////////////////
  44. ///////////////////////////////////////////////////////////////////////////////////////////////////
  45. //-------------------------------------------------------------------------------------------------
  46. /** Is the given widnow in the clipboard at the top level. NOTE that
  47. * children are NOT included in this search */
  48. //-------------------------------------------------------------------------------------------------
  49. Bool GUIEditWindowManager::isWindowInClipboard( GameWindow *window,
  50. GameWindow **list )
  51. {
  52. GameWindow *other;
  53. // sanity
  54. if( list == NULL || window == NULL )
  55. return FALSE;
  56. // just run through the window list in the clipboard to check
  57. for( other = *list; other; other = other->winGetNext() )
  58. {
  59. if( window == other )
  60. return TRUE; // found
  61. } // end for window
  62. return FALSE; // not found
  63. } // end isWindowInClipboard
  64. //-------------------------------------------------------------------------------------------------
  65. /** Add the window to clipboard list */
  66. //-------------------------------------------------------------------------------------------------
  67. void GUIEditWindowManager::linkToClipboard( GameWindow *window,
  68. GameWindow **list )
  69. {
  70. // sanity
  71. if( window == NULL || list == NULL )
  72. return;
  73. // debug sanity checking, can't add if already in it
  74. if( isWindowInClipboard( window, list ) )
  75. return;
  76. window->winSetPrev( NULL );
  77. window->winSetNext( *list );
  78. if( *list )
  79. (*list)->winSetPrev( window );
  80. *list = window;
  81. } // end linkToClipboard
  82. //-------------------------------------------------------------------------------------------------
  83. /** Unlink window from the clipboard list */
  84. //-------------------------------------------------------------------------------------------------
  85. void GUIEditWindowManager::unlinkFromClipboard( GameWindow *window,
  86. GameWindow **list )
  87. {
  88. GameWindow *next, *prev;
  89. // sanity
  90. if( window == NULL || list == NULL )
  91. return;
  92. // debug sanity checking, can't remove if not in
  93. if( isWindowInClipboard( window, list ) == FALSE )
  94. return;
  95. prev = window->winGetPrev();
  96. next = window->winGetNext();
  97. if( next )
  98. next->winSetPrev( prev );
  99. if( prev )
  100. prev->winSetNext( next );
  101. else
  102. *list = next;
  103. } // end unlinkFromClipboard
  104. //-------------------------------------------------------------------------------------------------
  105. /** Remove selection entries for child windows that also have ANY of
  106. * their parents in the selection list. */
  107. //-------------------------------------------------------------------------------------------------
  108. void GUIEditWindowManager::removeSupervisedChildSelections( void )
  109. {
  110. WindowSelectionEntry *select, *next;
  111. GameWindow *window, *parent;
  112. // iterate selections
  113. for( select = TheEditor->getSelectList(); select; select = next )
  114. {
  115. Bool parentSelected;
  116. // get next entry
  117. next = select->next;
  118. // get window data
  119. window = select->window;
  120. parent = window->winGetParent();
  121. // check to see if any parent is selected
  122. parentSelected = FALSE;
  123. while( parent )
  124. {
  125. if( TheEditor->isWindowSelected( parent ) )
  126. parentSelected = TRUE;
  127. parent = parent->winGetParent();
  128. } // end while
  129. //
  130. // if there is a parent selected then we can remove this
  131. // selection
  132. //
  133. if( parentSelected == TRUE )
  134. TheEditor->unSelectWindow( window );
  135. } // end for select
  136. } // end removeSupervisedChildSelections
  137. //-------------------------------------------------------------------------------------------------
  138. /** Traverse the selected window list, any child windows we encounter
  139. * are removed from their parent and placed in the window list at
  140. * the top level. Window position adjustments are made to compensate
  141. * for the transition from "parent space" to "screen space" */
  142. //-------------------------------------------------------------------------------------------------
  143. /*
  144. void GUIEditWindowManager::orphanSelectedChildren( void )
  145. {
  146. WindowSelectionEntry *select;
  147. GameWindow *window, *parent;
  148. for( select = TheEditor->getSelectList(); select; select = select->next )
  149. {
  150. // get window information
  151. window = select->window;
  152. parent = window->winGetParent();
  153. // we have a parent we're a candidate
  154. if( parent )
  155. {
  156. ICoord2D pos;
  157. // get the screen position of the window BEFORE we remove the parent
  158. window->winGetScreenPosition( &pos.x, &pos.y );
  159. // remove the child from the parent and add to top level of window system
  160. window->winSetParent( NULL );
  161. //
  162. // adjust the position, which previously was relative to the parent
  163. // but now is relative to the screen
  164. //
  165. window->winSetPosition( pos.x, pos.y );
  166. } // end if, we had a parent
  167. } // end for select
  168. } // end orphanSelectedChildren
  169. */
  170. ///////////////////////////////////////////////////////////////////////////////////////////////////
  171. // PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
  172. ///////////////////////////////////////////////////////////////////////////////////////////////////
  173. //-------------------------------------------------------------------------------------------------
  174. //-------------------------------------------------------------------------------------------------
  175. GUIEditWindowManager::GUIEditWindowManager( void )
  176. {
  177. m_clipboard = NULL;
  178. m_clipboardDup = NULL;
  179. m_copySpacing = 8;
  180. m_numCopiesPasted = 0;
  181. } // end GUIEditWindowManager
  182. //-------------------------------------------------------------------------------------------------
  183. //-------------------------------------------------------------------------------------------------
  184. GUIEditWindowManager::~GUIEditWindowManager( void )
  185. {
  186. // the duplicate list is only used in the actual act of pasting
  187. assert( m_clipboardDup == NULL );
  188. // free all data on the clipboard
  189. resetClipboard();
  190. } // end ~GUIEditWindowManager
  191. //-------------------------------------------------------------------------------------------------
  192. /** initialize the system */
  193. //-------------------------------------------------------------------------------------------------
  194. void GUIEditWindowManager::init( void )
  195. {
  196. // extending functionality
  197. W3DGameWindowManager::init();
  198. } // end init
  199. //-------------------------------------------------------------------------------------------------
  200. /** Destroy a game window */
  201. //-------------------------------------------------------------------------------------------------
  202. Int GUIEditWindowManager::winDestroy( GameWindow *window )
  203. {
  204. //
  205. // delete the edit data from window if present, the editor is the
  206. // ONLY place where this edit data is allocated anyway, it is
  207. // NOT present in the game
  208. //
  209. GameWindowEditData *editData = window->winGetEditData();
  210. if( editData )
  211. {
  212. // delete it
  213. delete editData;
  214. // set the edit data to NULL in the window
  215. window->winSetEditData( NULL );
  216. } // end if
  217. // call our base class functionality
  218. return W3DGameWindowManager::winDestroy( window );
  219. } // end winDestroy
  220. //-------------------------------------------------------------------------------------------------
  221. /** Create a new window by setting up its parameters and callbacks. */
  222. //-------------------------------------------------------------------------------------------------
  223. GameWindow *GUIEditWindowManager::winCreate( GameWindow *parent,
  224. UnsignedInt status,
  225. Int x, Int y,
  226. Int width, Int height,
  227. GameWinSystemFunc system,
  228. WinInstanceData *instData )
  229. {
  230. GameWindow *window;
  231. // call base class create
  232. window = W3DGameWindowManager::winCreate( parent, status, x, y,
  233. width, height, system,
  234. instData );
  235. // allocate edit data for the window
  236. if( window )
  237. {
  238. GameWindowEditData *editData = new GameWindowEditData;
  239. // set edit data to nothing
  240. memset( editData, 0, sizeof( GameWindowEditData ) );
  241. // attach edit data to window
  242. window->winSetEditData( editData );
  243. } // end if
  244. return window;
  245. } // end winCreate
  246. //-------------------------------------------------------------------------------------------------
  247. /** Destroy all windows in the clipboard */
  248. //-------------------------------------------------------------------------------------------------
  249. void GUIEditWindowManager::resetClipboard( void )
  250. {
  251. GameWindow *window, *next;
  252. // iterate through all windows
  253. for( window = m_clipboard; window; window = next )
  254. {
  255. // get next window
  256. next = window->winGetNext();
  257. //
  258. // in order for the destroy to really work correctly, the system
  259. // assumes that the window is actually part of the system, so take it
  260. // away from the clipboard and add it back to the regular system
  261. //
  262. unlinkFromClipboard( window, &m_clipboard );
  263. linkWindow( window );
  264. //
  265. // delete the window, note that these aren't part of the active editor,
  266. // the live only in the clipboard land so we don't need to notify
  267. // the edit window or the editor that this is going away ... they can't
  268. // possible be selected or anything
  269. //
  270. winDestroy( window );
  271. } // end for window
  272. // immediately process the destroyed windows just to be clean here
  273. processDestroyList();
  274. // nothing in the buffer now
  275. m_clipboard = NULL;
  276. m_numCopiesPasted = 0;
  277. } // end resetClipboard
  278. //-------------------------------------------------------------------------------------------------
  279. /** Is the clipboard empty */
  280. //-------------------------------------------------------------------------------------------------
  281. Bool GUIEditWindowManager::isClipboardEmpty( void )
  282. {
  283. if( m_clipboard )
  284. return TRUE;
  285. return FALSE;
  286. } // end isClipboardEmtpy
  287. //-------------------------------------------------------------------------------------------------
  288. /** Remove the selected windows from the current layout and put them into
  289. * the clipboard. If the parent of a window is not being cut with the
  290. * child the child will have no parent and will be adjusted to absolute
  291. * screen coordinates with no parent */
  292. //-------------------------------------------------------------------------------------------------
  293. void GUIEditWindowManager::cutSelectedToClipboard( void )
  294. {
  295. //
  296. // reset the clipboard just to be safe, this is done in the copy but
  297. // it's nice cause we depend on it here for deleting
  298. //
  299. resetClipboard();
  300. // first copy the selected windows to the clipboard
  301. copySelectedToClipboard();
  302. //
  303. // now delete the selected windows from the scene if we actually
  304. // copied them to the clipboard
  305. //
  306. if( m_clipboard )
  307. TheEditor->deleteSelected();
  308. } // end cutSelectedToClipboard
  309. //-------------------------------------------------------------------------------------------------
  310. /** Given the current window in a list pointed to by 'root', if that
  311. * window is selected, duplicate it and place it on the clipboard. If
  312. * it's not selected check it's children to see if any of them are
  313. * selected and should be duplicated. Then just move on down the list
  314. * and check the other sibling windows as well */
  315. //-------------------------------------------------------------------------------------------------
  316. void GUIEditWindowManager::duplicateSelected( GameWindow *root )
  317. {
  318. // end of recursion
  319. if( root == NULL )
  320. return;
  321. // if widow is selected duplicate and continue on
  322. if( TheEditor->isWindowSelected( root ) )
  323. {
  324. GameWindow *duplicate;
  325. // perform the duplication of window and all children
  326. duplicate = duplicateWindow( root, NULL );
  327. if( duplicate )
  328. {
  329. //
  330. // if our source window had a parent, that means that the child
  331. // was selected, but the parent wasn't. Therefore the new
  332. // duplicate has no parent, but needs to have its position
  333. // adjusted to be relative to the screen instead of the now
  334. // missing parent
  335. //
  336. GameWindow *parent = root->winGetParent();
  337. if( parent )
  338. {
  339. ICoord2D parentPos;
  340. ICoord2D pos;
  341. parent->winGetScreenPosition( &parentPos.x, &parentPos.y );
  342. duplicate->winGetScreenPosition( &pos.x, &pos.y );
  343. pos.x += parentPos.x;
  344. pos.y += parentPos.y;
  345. duplicate->winSetPosition( pos.x, pos.y );
  346. } // end if
  347. // add window to the clipboard
  348. linkToClipboard( duplicate, &m_clipboard );
  349. } // end if
  350. } // end if
  351. else
  352. {
  353. //
  354. // the window itself is not selected, but some of it's children
  355. // may be so check them
  356. //
  357. duplicateSelected( root->winGetChild() );
  358. } // end else
  359. // move on to the next window
  360. duplicateSelected( root->winGetNext() );
  361. } // end duplicateSelected
  362. //-------------------------------------------------------------------------------------------------
  363. /** Copy the selected windows to the clipboard */
  364. //-------------------------------------------------------------------------------------------------
  365. void GUIEditWindowManager::copySelectedToClipboard( void )
  366. {
  367. // reset the contents of the clipboard
  368. resetClipboard();
  369. //
  370. // to simplify things, child windows that ALSO have their
  371. // parent window selected will become unselected, anything that
  372. // happens to the parent will automatically include the child
  373. //
  374. removeSupervisedChildSelections();
  375. //
  376. // go through the window list and duplicate anything selected, note
  377. // that the clipboard will contain the list of windows in reverse
  378. // order from the original order in the layout
  379. //
  380. duplicateSelected( m_windowList );
  381. } // end copySelectedToClipboard
  382. //-------------------------------------------------------------------------------------------------
  383. /** Take the string representation of the name of the window passed in,
  384. * and add a number to it at the end. If there is already a number
  385. * on it at the end, that number will be incremented */
  386. //-------------------------------------------------------------------------------------------------
  387. void GUIEditWindowManager::incrementName( GameWindow *window )
  388. {
  389. WinInstanceData *instData = window->winGetInstanceData();
  390. // bleah, this is ugly and hokey, but if I rewrite
  391. // this I will botch it (cuz I'm currently not sure
  392. // how to test it)
  393. char name[MAX_WINDOW_NAME_LEN];
  394. strcpy(name, instData->m_decoratedNameString.str());
  395. Int len = strlen( name );
  396. char numberBuffer[ MAX_WINDOW_NAME_LEN ];
  397. Int i, j;
  398. char c;
  399. Bool hasNumberSuffix = FALSE;
  400. Int numberStartIndex = 0;
  401. // trivial case, just append a number to the end and get outta here
  402. if( len == 0 )
  403. {
  404. strcat( name, "1" );
  405. goto cleanup;
  406. } // end if
  407. //
  408. // start from the end of the string and back up to the start picking
  409. // off each character, checking if it's a number, and adding that number
  410. // to a string buffer. After all numbers are read from the name
  411. // the string is turned real number, incremented, and replaces the
  412. // existing number string
  413. //
  414. for( i = 0; i < MAX_WINDOW_NAME_LEN; i++ )
  415. numberBuffer[ i ] = ' ';
  416. numberBuffer[ MAX_WINDOW_NAME_LEN - 1 ] = '\0';
  417. for( i = len - 1, j = MAX_WINDOW_NAME_LEN - 2; i >= 0; i-- )
  418. {
  419. c = name[ i ];
  420. if( isdigit( c ) )
  421. {
  422. hasNumberSuffix = TRUE;
  423. numberBuffer[ j-- ] = c;
  424. } // end if
  425. else
  426. {
  427. numberStartIndex = i + 1;
  428. break; // exit for i
  429. } // end else
  430. } // end for i
  431. //
  432. // if we have a number suffix change it to a number, increment it, and
  433. // paste it over the old number
  434. //
  435. if( hasNumberSuffix == TRUE )
  436. {
  437. Int number = atoi( numberBuffer );
  438. Int charsAdded;
  439. // increment the number
  440. number++;
  441. // turn number back into string
  442. itoa( number, numberBuffer, 10 );
  443. // put number string OVER the original number string in the name
  444. len = strlen( numberBuffer );
  445. charsAdded = 0;
  446. for( i = 0; i < len; i++ )
  447. {
  448. if( i + numberStartIndex <= MAX_WINDOW_NAME_LEN - 2 )
  449. {
  450. name[ i + numberStartIndex ] = numberBuffer[ i ];
  451. charsAdded++;
  452. } // end if
  453. }
  454. name[ numberStartIndex + charsAdded ] = 0; // terminate at end of new string
  455. } // end if
  456. else
  457. {
  458. // no number at end, easy ... just append a number '1'
  459. strcat( name, "1" );
  460. } // end else
  461. cleanup:
  462. instData->m_decoratedNameString = name;
  463. } // end incrementName
  464. //-------------------------------------------------------------------------------------------------
  465. /** Validate the names for all the windows and child windows in the copy
  466. * buffer that they are unique and don't collide with any windows in
  467. * the real system. This is in preparation for a paste of the copy
  468. * buffer into the real working layout */
  469. //-------------------------------------------------------------------------------------------------
  470. void GUIEditWindowManager::validateClipboardNames( GameWindow *root )
  471. {
  472. Bool nameOK = FALSE;
  473. WinInstanceData *instData;
  474. Int sanityLoop = 0;
  475. // end of recursion
  476. if( root == NULL )
  477. return;
  478. // get our inst data
  479. instData = root->winGetInstanceData();
  480. //
  481. // we will check our name against all names in the active layout AND
  482. // in the clipboard, if it's a dupe we will pick a new name and
  483. // try it over and over until it's OK
  484. //
  485. while( nameOK == FALSE )
  486. {
  487. // if we're not a dupe with anything anywhere we're ok
  488. if( !TheEditor->isNameDuplicate( m_windowList, root, instData->m_decoratedNameString ) &&
  489. !TheEditor->isNameDuplicate( m_clipboardDup, root, instData->m_decoratedNameString ) )
  490. nameOK = TRUE;
  491. else
  492. incrementName( root ); // have to change our name, so sorry :(
  493. //
  494. // and just because I don't want the possibility of a infinite loop
  495. // EVER to occur here this is just a sanity check that will probably
  496. // never get run
  497. //
  498. if( ++sanityLoop > 99999999 )
  499. {
  500. char buffer[ 1024 ];
  501. sprintf( buffer, "Unable to make unique name for '%s', please manually edit the name before saving.",
  502. instData->m_decoratedNameString.str() );
  503. MessageBox( TheEditor->getWindowHandle(), buffer, "Error Mapping Names", MB_OK );
  504. nameOK = TRUE;
  505. } // end if
  506. } // end if
  507. // validate our children names
  508. GameWindow *child;
  509. for( child = root->winGetChild(); child; child = child->winGetNext() )
  510. validateClipboardNames( child );
  511. // validate the next window in the list
  512. validateClipboardNames( root->winGetNext() );
  513. } // end validateClipboardNames
  514. //-------------------------------------------------------------------------------------------------
  515. /** Paste the contents of the clipboard into the window world */
  516. //-------------------------------------------------------------------------------------------------
  517. void GUIEditWindowManager::pasteClipboard( void )
  518. {
  519. GameWindow *window, *next;
  520. GameWindow *firstWindow = NULL;
  521. // check for empty clipboard
  522. if( m_clipboard == NULL )
  523. {
  524. MessageBox( TheEditor->getWindowHandle(),
  525. "Cannot perform paste, the clipboard is empty.",
  526. "Clipboard Empty",
  527. MB_OK );
  528. return;
  529. } // end if
  530. // create a duplicate of everything in the clipboard
  531. assert( m_clipboardDup == NULL );
  532. createClipboardDuplicate();
  533. //
  534. // we are about to paste the contents of the clipboard dupe into the world,
  535. // scan through the clipboard dupe and adjust any names that will cause
  536. // collisions in the current layout
  537. //
  538. validateClipboardNames( m_clipboardDup );
  539. // keep a pointer to the first window we will add
  540. firstWindow = m_clipboardDup;
  541. // move everything from the duplicate list into the real world
  542. for( window = m_clipboardDup; window; window = next )
  543. {
  544. // get next window
  545. next = window->winGetNext();
  546. // remove from clipboard
  547. unlinkFromClipboard( window, &m_clipboardDup );
  548. // place in real layout
  549. linkWindow( window );
  550. //
  551. // since we just pasted in a new window, offset it a little bit
  552. // from the original location based on how many times we're pasted
  553. // this set of copies. This way they won't all stack on top of
  554. // each other
  555. //
  556. ICoord2D pos, safePos;
  557. window->winGetPosition( &pos.x, &pos.y );
  558. pos.x += m_copySpacing * (m_numCopiesPasted + 1);
  559. pos.y += m_copySpacing * (m_numCopiesPasted + 1);
  560. // kee the location legal
  561. TheEditor->computeSafeLocation( window, pos.x, pos.y,
  562. &safePos.x, &safePos.y );
  563. // set the new location
  564. TheEditor->moveWindowTo( window, safePos.x, safePos.y );
  565. // notify the hierarchy of the new window added
  566. TheHierarchyView->addWindow( window, HIERARCHY_ADD_AT_TOP );
  567. } // end for window
  568. // the clipboard duplicate list is only for the act of pasting
  569. assert( m_clipboardDup == NULL );
  570. // we've now completed another successful copy pasted in
  571. m_numCopiesPasted++;
  572. //
  573. // now that all windows were added to the layout, and we have
  574. // the first window that we added ... since we know they were added
  575. // at the head of the window list we can traverse from the first
  576. // window added to the head of the window list to access each new
  577. // window we just pasted. As a convenience we will unselct anything
  578. // selected and select all the windows we added
  579. //
  580. TheEditor->clearSelections();
  581. window = firstWindow;
  582. while( window )
  583. {
  584. TheEditor->selectWindow( window );
  585. window = window->winGetPrev();
  586. // notify the editor that each of the windows was created
  587. TheEditor->notifyNewWindow( window );
  588. } // end while
  589. // if we did in fact paste a window then our file contents have changed
  590. if( firstWindow )
  591. TheEditor->setUnsaved( TRUE );
  592. } // end pasteClipboard
  593. //-------------------------------------------------------------------------------------------------
  594. /** Convinience funtion to copy the Draw state info for a given instance */
  595. //-------------------------------------------------------------------------------------------------
  596. void InstDrawCopy ( WinInstanceData *instData, WinInstanceData *sourceInstData)
  597. {
  598. // do the copy of the colors for each state
  599. memcpy( &instData->m_enabledDrawData,
  600. &sourceInstData->m_enabledDrawData,
  601. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  602. memcpy( &instData->m_disabledDrawData,
  603. &sourceInstData->m_disabledDrawData,
  604. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  605. memcpy( &instData->m_hiliteDrawData,
  606. &sourceInstData->m_hiliteDrawData,
  607. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  608. }
  609. //-------------------------------------------------------------------------------------------------
  610. /** Duplciate a window and all its children */
  611. //-------------------------------------------------------------------------------------------------
  612. GameWindow *GUIEditWindowManager::duplicateWindow( GameWindow *source,
  613. GameWindow *parent )
  614. {
  615. GameWindow *duplicate = NULL;
  616. UnsignedInt style, status;
  617. WinInstanceData *instData;
  618. WinInstanceData instDataCopy;
  619. ICoord2D pos, size;
  620. // sanity
  621. if( source == NULL )
  622. return NULL;
  623. // get the window instance data and make a copy of it for creating new stuff
  624. instData = source->winGetInstanceData();
  625. instDataCopy = *instData;
  626. // memcpy( &instDataCopy, instData, sizeof( instDataCopy ) );
  627. //
  628. // do NOT copy the display string instances, these MUST be allocated when
  629. // needed in real windows
  630. //
  631. instDataCopy.m_text = NULL;
  632. instDataCopy.m_tooltip = NULL;
  633. // get a few properties we're going to need
  634. style = source->winGetStyle();
  635. status = source->winGetStatus();
  636. source->winGetPosition( &pos.x, &pos.y );
  637. source->winGetSize( &size.x, &size.y );
  638. // create a new window or gadget of the appropriate type
  639. if( BitTest( style, GWS_PUSH_BUTTON ) )
  640. {
  641. duplicate =
  642. TheWindowManager->gogoGadgetPushButton( parent,
  643. status,
  644. pos.x,
  645. pos.y,
  646. size.x,
  647. size.y,
  648. &instDataCopy,
  649. source->winGetFont(),
  650. FALSE );
  651. } // end if
  652. else if( BitTest( style, GWS_RADIO_BUTTON ) )
  653. {
  654. RadioButtonData *radioData = (RadioButtonData *)source->winGetUserData();
  655. RadioButtonData radioDataCopy;
  656. radioDataCopy = *radioData;
  657. // memcpy( &radioDataCopy, radioData, sizeof( RadioButtonData ) );
  658. duplicate =
  659. TheWindowManager->gogoGadgetRadioButton( parent,
  660. status,
  661. pos.x,
  662. pos.y,
  663. size.x,
  664. size.y,
  665. &instDataCopy,
  666. &radioDataCopy,
  667. source->winGetFont(),
  668. FALSE );
  669. } // end else if
  670. else if( BitTest( style, GWS_CHECK_BOX ) )
  671. {
  672. duplicate =
  673. TheWindowManager->gogoGadgetCheckbox( parent,
  674. status,
  675. pos.x,
  676. pos.y,
  677. size.x,
  678. size.y,
  679. &instDataCopy,
  680. source->winGetFont(),
  681. FALSE );
  682. } // end else if
  683. else if( BitTest( style, GWS_HORZ_SLIDER | GWS_VERT_SLIDER ) )
  684. {
  685. SliderData *sliderData = (SliderData *)source->winGetUserData();
  686. SliderData sliderDataCopy;
  687. sliderDataCopy = *sliderData;
  688. // memcpy( &sliderDataCopy, sliderData, sizeof( SliderData ) );
  689. duplicate = TheWindowManager->gogoGadgetSlider( parent,
  690. status,
  691. pos.x,
  692. pos.y,
  693. size.x,
  694. size.y,
  695. &instDataCopy,
  696. &sliderDataCopy,
  697. source->winGetFont(),
  698. FALSE );
  699. //
  700. // copy the color and image schemes of the sub controls that make
  701. // up a slider
  702. //
  703. if( duplicate )
  704. {
  705. WinInstanceData *instData;
  706. WinInstanceData *sourceInstData;
  707. // do the slider thumb
  708. GameWindow *thumb = GadgetSliderGetThumb( duplicate );
  709. GameWindow *sourceThumb = GadgetSliderGetThumb( source );
  710. if( thumb && sourceThumb )
  711. {
  712. instData = thumb->winGetInstanceData();
  713. sourceInstData = sourceThumb->winGetInstanceData();
  714. // do the copy of the colors for each state
  715. memcpy( &instData->m_enabledDrawData,
  716. &sourceInstData->m_enabledDrawData,
  717. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  718. memcpy( &instData->m_disabledDrawData,
  719. &sourceInstData->m_disabledDrawData,
  720. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  721. memcpy( &instData->m_hiliteDrawData,
  722. &sourceInstData->m_hiliteDrawData,
  723. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  724. } // end if
  725. } // end if
  726. } // end else if
  727. else if( BitTest( style, GWS_COMBO_BOX ) )
  728. {
  729. ComboBoxData *comboData = (ComboBoxData *)source->winGetUserData();
  730. ComboBoxData comboDataCopy;
  731. memset( &comboDataCopy, 0, sizeof( ComboBoxData ) );
  732. comboDataCopy.entryData = new EntryData;
  733. memset ( comboDataCopy.entryData, 0, sizeof(EntryData));
  734. comboDataCopy.listboxData = new ListboxData;
  735. memset ( comboDataCopy.listboxData, 0, sizeof(ListboxData));
  736. comboDataCopy.entryCount = comboData->entryCount;
  737. comboDataCopy.isEditable = comboData->isEditable;
  738. comboDataCopy.maxChars = comboData->maxChars;
  739. comboDataCopy.maxDisplay = comboData->maxDisplay;
  740. comboDataCopy.lettersAndNumbersOnly = comboData->lettersAndNumbersOnly;
  741. comboDataCopy.asciiOnly = comboData->asciiOnly;
  742. comboDataCopy.listboxData->autoPurge = comboData->listboxData->autoPurge;
  743. comboDataCopy.listboxData->autoScroll = comboData->listboxData->autoScroll;
  744. comboDataCopy.listboxData->scrollIfAtEnd = comboData->listboxData->scrollIfAtEnd;
  745. comboDataCopy.listboxData->forceSelect = comboData->listboxData->forceSelect;
  746. comboDataCopy.listboxData->listLength = comboData->listboxData->listLength;
  747. comboDataCopy.listboxData->multiSelect = comboData->listboxData->multiSelect;
  748. comboDataCopy.listboxData->scrollBar = comboData->listboxData->scrollBar;
  749. comboDataCopy.listboxData->columns = comboData->listboxData->columns;
  750. comboDataCopy.listboxData->columnWidth = comboData->listboxData->columnWidth;
  751. comboDataCopy.listboxData->columnWidthPercentage = comboData->listboxData->columnWidthPercentage;
  752. comboDataCopy.entryData->alphaNumericalOnly = comboData->entryData->alphaNumericalOnly;
  753. comboDataCopy.entryData->aSCIIOnly = comboData->entryData->aSCIIOnly;
  754. comboDataCopy.entryData->maxTextLen = comboData->entryData->maxTextLen;
  755. comboDataCopy.entryData->numericalOnly = comboData->entryData->numericalOnly;
  756. duplicate =
  757. TheWindowManager->gogoGadgetComboBox( parent,
  758. status,
  759. pos.x,
  760. pos.y,
  761. size.x,
  762. size.y,
  763. &instDataCopy,
  764. &comboDataCopy,
  765. source->winGetFont(),
  766. FALSE );
  767. //
  768. // copy the color and image schemes of the sub controls that make
  769. // up a listbox
  770. //
  771. if( duplicate )
  772. {
  773. ComboBoxData *comboData = (ComboBoxData *)duplicate->winGetUserData();
  774. ComboBoxData *sourceComboData = (ComboBoxData *)source->winGetUserData();
  775. WinInstanceData *instData;
  776. WinInstanceData *sourceInstData;
  777. // drop down button
  778. GameWindow *dropDownButton = comboData->dropDownButton;
  779. GameWindow *sourceDropDownButton = sourceComboData->dropDownButton;
  780. if(dropDownButton && sourceDropDownButton)
  781. {
  782. instData = dropDownButton->winGetInstanceData();
  783. sourceInstData = sourceDropDownButton->winGetInstanceData();
  784. InstDrawCopy(instData,sourceInstData);
  785. }
  786. // edit box
  787. GameWindow *editBox = comboData->editBox;
  788. GameWindow *sourceEditBox = sourceComboData->editBox;
  789. if(editBox && sourceEditBox)
  790. {
  791. instData = editBox->winGetInstanceData();
  792. sourceInstData = sourceEditBox->winGetInstanceData();
  793. InstDrawCopy(instData,sourceInstData);
  794. }
  795. // ListBox
  796. GameWindow *listBox = comboData->listBox;
  797. GameWindow *sourceListBox = sourceComboData->listBox;
  798. if(listBox && sourceListBox)
  799. {
  800. instData = listBox->winGetInstanceData();
  801. sourceInstData = sourceListBox->winGetInstanceData();
  802. InstDrawCopy(instData,sourceInstData);
  803. // up button
  804. GameWindow *upButton = comboData->listboxData->upButton;
  805. GameWindow *sourceUpButton = sourceComboData->listboxData->upButton;
  806. if( upButton && sourceUpButton )
  807. {
  808. instData = upButton->winGetInstanceData();
  809. sourceInstData = sourceUpButton->winGetInstanceData();
  810. // do the copy of the colors for each state
  811. memcpy( &instData->m_enabledDrawData,
  812. &sourceInstData->m_enabledDrawData,
  813. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  814. memcpy( &instData->m_disabledDrawData,
  815. &sourceInstData->m_disabledDrawData,
  816. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  817. memcpy( &instData->m_hiliteDrawData,
  818. &sourceInstData->m_hiliteDrawData,
  819. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  820. } // if
  821. // down button
  822. GameWindow *downButton = comboData->listboxData->downButton;
  823. GameWindow *sourceDownButton = sourceComboData->listboxData->downButton;
  824. if( downButton && sourceDownButton )
  825. {
  826. instData = downButton->winGetInstanceData();
  827. sourceInstData = sourceDownButton->winGetInstanceData();
  828. // do the copy of the colors for each state
  829. memcpy( &instData->m_enabledDrawData,
  830. &sourceInstData->m_enabledDrawData,
  831. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  832. memcpy( &instData->m_disabledDrawData,
  833. &sourceInstData->m_disabledDrawData,
  834. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  835. memcpy( &instData->m_hiliteDrawData,
  836. &sourceInstData->m_hiliteDrawData,
  837. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  838. } // if
  839. // slider
  840. GameWindow *slider = comboData->listboxData->slider;
  841. GameWindow *sourceSlider = sourceComboData->listboxData->slider;
  842. if( slider && sourceSlider )
  843. {
  844. instData = slider->winGetInstanceData();
  845. sourceInstData = sourceSlider->winGetInstanceData();
  846. // do the copy of the colors for each state
  847. memcpy( &instData->m_enabledDrawData,
  848. &sourceInstData->m_enabledDrawData,
  849. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  850. memcpy( &instData->m_disabledDrawData,
  851. &sourceInstData->m_disabledDrawData,
  852. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  853. memcpy( &instData->m_hiliteDrawData,
  854. &sourceInstData->m_hiliteDrawData,
  855. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  856. // do the slider thumb
  857. GameWindow *thumb = GadgetSliderGetThumb( slider );
  858. GameWindow *sourceThumb = GadgetSliderGetThumb( sourceSlider );
  859. if( thumb && sourceThumb )
  860. {
  861. instData = thumb->winGetInstanceData();
  862. sourceInstData = sourceThumb->winGetInstanceData();
  863. // do the copy of the colors for each state
  864. memcpy( &instData->m_enabledDrawData,
  865. &sourceInstData->m_enabledDrawData,
  866. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  867. memcpy( &instData->m_disabledDrawData,
  868. &sourceInstData->m_disabledDrawData,
  869. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  870. memcpy( &instData->m_hiliteDrawData,
  871. &sourceInstData->m_hiliteDrawData,
  872. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  873. } // end if
  874. } // if
  875. } // if
  876. } // end if
  877. } // end else if
  878. else if( BitTest( style, GWS_SCROLL_LISTBOX ) )
  879. {
  880. ListboxData *listData = (ListboxData *)source->winGetUserData();
  881. ListboxData listDataCopy;
  882. memset( &listDataCopy, 0, sizeof( listDataCopy ) );
  883. listDataCopy.autoPurge = listData->autoPurge;
  884. listDataCopy.autoScroll = listData->autoScroll;
  885. listDataCopy.scrollIfAtEnd = listData->scrollIfAtEnd;
  886. listDataCopy.forceSelect = listData->forceSelect;
  887. listDataCopy.listLength = listData->listLength;
  888. listDataCopy.multiSelect = listData->multiSelect;
  889. listDataCopy.scrollBar = listData->scrollBar;
  890. listDataCopy.columns = listData->columns;
  891. if(listData->columnWidth)
  892. {
  893. listDataCopy.columnWidth = new Int[listData->columns];
  894. for(Int i = 0; i < listData->columns; i ++)
  895. {
  896. listDataCopy.columnWidth[i] = listData->columnWidth[i];
  897. }
  898. }
  899. else
  900. listDataCopy.columnWidth = NULL;
  901. if(listData->columnWidthPercentage)
  902. {
  903. listDataCopy.columnWidthPercentage = new Int[listData->columns];
  904. for(Int i = 0; i < listData->columns; i ++)
  905. {
  906. listDataCopy.columnWidthPercentage[i] = listData->columnWidthPercentage[i];
  907. }
  908. }
  909. else
  910. listDataCopy.columnWidthPercentage = NULL;
  911. duplicate =
  912. TheWindowManager->gogoGadgetListBox( parent,
  913. status,
  914. pos.x,
  915. pos.y,
  916. size.x,
  917. size.y,
  918. &instDataCopy,
  919. &listDataCopy,
  920. source->winGetFont(),
  921. FALSE );
  922. //
  923. // copy the color and image schemes of the sub controls that make
  924. // up a listbox
  925. //
  926. if( duplicate )
  927. {
  928. ListboxData *listData = (ListboxData *)duplicate->winGetUserData();
  929. ListboxData *sourceListData = (ListboxData *)source->winGetUserData();
  930. WinInstanceData *instData;
  931. WinInstanceData *sourceInstData;
  932. // up button
  933. GameWindow *upButton = listData->upButton;
  934. GameWindow *sourceUpButton = sourceListData->upButton;
  935. if( upButton && sourceUpButton )
  936. {
  937. instData = upButton->winGetInstanceData();
  938. sourceInstData = sourceUpButton->winGetInstanceData();
  939. // do the copy of the colors for each state
  940. memcpy( &instData->m_enabledDrawData,
  941. &sourceInstData->m_enabledDrawData,
  942. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  943. memcpy( &instData->m_disabledDrawData,
  944. &sourceInstData->m_disabledDrawData,
  945. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  946. memcpy( &instData->m_hiliteDrawData,
  947. &sourceInstData->m_hiliteDrawData,
  948. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  949. } // if
  950. // down button
  951. GameWindow *downButton = listData->downButton;
  952. GameWindow *sourceDownButton = sourceListData->downButton;
  953. if( downButton && sourceDownButton )
  954. {
  955. instData = downButton->winGetInstanceData();
  956. sourceInstData = sourceDownButton->winGetInstanceData();
  957. // do the copy of the colors for each state
  958. memcpy( &instData->m_enabledDrawData,
  959. &sourceInstData->m_enabledDrawData,
  960. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  961. memcpy( &instData->m_disabledDrawData,
  962. &sourceInstData->m_disabledDrawData,
  963. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  964. memcpy( &instData->m_hiliteDrawData,
  965. &sourceInstData->m_hiliteDrawData,
  966. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  967. } // if
  968. // slider
  969. GameWindow *slider = listData->slider;
  970. GameWindow *sourceSlider = sourceListData->slider;
  971. if( slider && sourceSlider )
  972. {
  973. instData = slider->winGetInstanceData();
  974. sourceInstData = sourceSlider->winGetInstanceData();
  975. // do the copy of the colors for each state
  976. memcpy( &instData->m_enabledDrawData,
  977. &sourceInstData->m_enabledDrawData,
  978. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  979. memcpy( &instData->m_disabledDrawData,
  980. &sourceInstData->m_disabledDrawData,
  981. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  982. memcpy( &instData->m_hiliteDrawData,
  983. &sourceInstData->m_hiliteDrawData,
  984. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  985. // do the slider thumb
  986. GameWindow *thumb = GadgetSliderGetThumb( slider );
  987. GameWindow *sourceThumb = GadgetSliderGetThumb( sourceSlider );
  988. if( thumb && sourceThumb )
  989. {
  990. instData = thumb->winGetInstanceData();
  991. sourceInstData = sourceThumb->winGetInstanceData();
  992. // do the copy of the colors for each state
  993. memcpy( &instData->m_enabledDrawData,
  994. &sourceInstData->m_enabledDrawData,
  995. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  996. memcpy( &instData->m_disabledDrawData,
  997. &sourceInstData->m_disabledDrawData,
  998. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  999. memcpy( &instData->m_hiliteDrawData,
  1000. &sourceInstData->m_hiliteDrawData,
  1001. sizeof( WinDrawData ) * MAX_DRAW_DATA );
  1002. } // end if
  1003. } // if
  1004. } // end if
  1005. } // end else if
  1006. else if( BitTest( style, GWS_ENTRY_FIELD ) )
  1007. {
  1008. EntryData *entryData = (EntryData *)source->winGetUserData();
  1009. EntryData entryDataCopy;
  1010. memset( &entryDataCopy, 0, sizeof( entryDataCopy ) );
  1011. entryDataCopy.alphaNumericalOnly = entryData->alphaNumericalOnly;
  1012. entryDataCopy.aSCIIOnly = entryData->aSCIIOnly;
  1013. entryDataCopy.maxTextLen = entryData->maxTextLen;
  1014. entryDataCopy.numericalOnly = entryData->numericalOnly;
  1015. entryDataCopy.secretText = entryData->secretText;
  1016. duplicate =
  1017. TheWindowManager->gogoGadgetTextEntry( parent,
  1018. status,
  1019. pos.x,
  1020. pos.y,
  1021. size.x,
  1022. size.y,
  1023. &instDataCopy,
  1024. &entryDataCopy,
  1025. source->winGetFont(),
  1026. FALSE );
  1027. } // end else if
  1028. else if( BitTest( style, GWS_STATIC_TEXT ) )
  1029. {
  1030. TextData *textData = (TextData *)source->winGetUserData();
  1031. TextData textDataCopy;
  1032. textDataCopy.centered = textData->centered;
  1033. duplicate =
  1034. TheWindowManager->gogoGadgetStaticText( parent,
  1035. status,
  1036. pos.x,
  1037. pos.y,
  1038. size.x,
  1039. size.y,
  1040. &instDataCopy,
  1041. &textDataCopy,
  1042. source->winGetFont(),
  1043. FALSE );
  1044. } // end else if
  1045. else if( BitTest( style, GWS_PROGRESS_BAR ) )
  1046. {
  1047. duplicate =
  1048. TheWindowManager->gogoGadgetProgressBar( parent,
  1049. status,
  1050. pos.x,
  1051. pos.y,
  1052. size.x,
  1053. size.y,
  1054. &instDataCopy,
  1055. source->winGetFont(),
  1056. FALSE );
  1057. } // end else if
  1058. else if( BitTest( style, GWS_USER_WINDOW ) )
  1059. {
  1060. // create plain ol generic window
  1061. duplicate = TheWindowManager->winCreate( parent,
  1062. status,
  1063. pos.x,
  1064. pos.y,
  1065. size.x,
  1066. size.y,
  1067. NULL,
  1068. &instDataCopy );
  1069. } // end else if
  1070. else
  1071. {
  1072. MessageBox( TheEditor->getWindowHandle(),
  1073. "Cannot duplicate window, undefined style.",
  1074. "Internal Error", MB_OK );
  1075. assert( 0 );
  1076. memset( &instDataCopy, 0, sizeof( instDataCopy ) ); // see comment below
  1077. return NULL;
  1078. } // end else
  1079. // sanity
  1080. if( duplicate == NULL )
  1081. {
  1082. MessageBox( TheEditor->getWindowHandle(), "Unable to duplicate window",
  1083. "Internal Error", MB_OK );
  1084. assert( 0 );
  1085. memset( &instDataCopy, 0, sizeof( instDataCopy ) ); // see comment below
  1086. return NULL;
  1087. } // end if
  1088. //
  1089. // since we're using the real window system here to create things, we
  1090. // want to immediately remove it from the real system list cause we're
  1091. // not adding windows to the layout, only duplicating windows in
  1092. // isolation. Note that child windows are linked to their parents
  1093. // but that is totally isolated in the parent so that's OK and
  1094. // necessary.
  1095. //
  1096. if( parent == NULL )
  1097. unlinkWindow( duplicate );
  1098. // copy edit data, only for the editor
  1099. if( duplicate )
  1100. {
  1101. GameWindowEditData *editData = duplicate->winGetEditData();
  1102. GameWindowEditData *sourceEditData = source->winGetEditData();
  1103. // set edit data to zero or copy from source
  1104. if( sourceEditData && editData )
  1105. *editData = *sourceEditData;
  1106. // memcpy( editData, sourceEditData, sizeof( GameWindowEditData ) );
  1107. } // end if
  1108. //
  1109. // duplicate all the children for the window, except if this window
  1110. // is a gadget, those windows may have children but all of that
  1111. // is already taken care of in the creation above ... a gadget should
  1112. // be considered a single atomic unit
  1113. //
  1114. if( TheEditor->windowIsGadget( duplicate ) == FALSE )
  1115. {
  1116. GameWindow *child;
  1117. for( child = source->winGetChild(); child; child = child->winGetNext() )
  1118. duplicateWindow( child, duplicate );
  1119. } // end if
  1120. //
  1121. // the inst data copy was literally a copy, now it's going to go out of
  1122. // scope and we DONT want any data to be freed that points back to the
  1123. // original window e got it from. So therefore we'll just blow it away
  1124. //
  1125. memset( &instDataCopy, 0, sizeof( instDataCopy ) );
  1126. // return the duped window
  1127. return duplicate;
  1128. } // end duplicateWindow
  1129. //-------------------------------------------------------------------------------------------------
  1130. /** Create a duplicate everything on the clipboard list and put it
  1131. * on the m_clipboardDup list for pasting */
  1132. //-------------------------------------------------------------------------------------------------
  1133. void GUIEditWindowManager::createClipboardDuplicate( void )
  1134. {
  1135. GameWindow *duplicate;
  1136. GameWindow *window;
  1137. GameWindow *lastWindow;
  1138. // find last window in clipboard
  1139. lastWindow = m_clipboard;
  1140. while( lastWindow && lastWindow->winGetNext() != NULL )
  1141. lastWindow = lastWindow->winGetNext();
  1142. //
  1143. // go through each window in the clipboard, note we're starting from
  1144. // the bottom and going to the front to preserve the same order
  1145. // as the clipboard
  1146. //
  1147. for( window = lastWindow; window; window = window->winGetPrev() )
  1148. {
  1149. // duplicate the window and all its children
  1150. duplicate = duplicateWindow( window, NULL );
  1151. // add duplicate to list
  1152. if( duplicate )
  1153. linkToClipboard( duplicate, &m_clipboardDup );
  1154. } // end for
  1155. } // end createClipboardDuplicate
  1156. //-------------------------------------------------------------------------------------------------
  1157. /** Make the 'target' a child of the 'parent' */
  1158. //-------------------------------------------------------------------------------------------------
  1159. void GUIEditWindowManager::makeChildOf( GameWindow *target,
  1160. GameWindow *parent )
  1161. {
  1162. // sanity
  1163. if( target == NULL )
  1164. return;
  1165. // get target parent
  1166. GameWindow *prevParent = target->winGetParent();
  1167. // check for no parent
  1168. if( parent == NULL )
  1169. {
  1170. // if target already has no parent nothing to do
  1171. if( prevParent == NULL )
  1172. return;
  1173. //
  1174. // we are removing a parent from the target and placing target
  1175. // at the top of the window list. Be sure to preserve the
  1176. // screen position as the new coords so it's in the same place
  1177. //
  1178. ICoord2D screenPos;
  1179. target->winGetScreenPosition( &screenPos.x, &screenPos.y );
  1180. unlinkChildWindow( target );
  1181. linkWindow( target );
  1182. target->winSetPosition( screenPos.x, screenPos.y );
  1183. return;
  1184. } // end if
  1185. // check to see if this is already out parent, nothing to do
  1186. if( prevParent == parent )
  1187. return;
  1188. // you cannot make a window a child of a gadget control
  1189. if( TheEditor->windowIsGadget( parent ) )
  1190. {
  1191. MessageBox( TheEditor->getWindowHandle(),
  1192. "You cannot give a gadget control a child.",
  1193. "Child Not Allowed",
  1194. MB_OK );
  1195. return;
  1196. } // end if
  1197. // get the target screen position before the move to child
  1198. ICoord2D screenPosBeforeMove;
  1199. target->winGetScreenPosition( &screenPosBeforeMove.x,
  1200. &screenPosBeforeMove.y );
  1201. // remove the target from the window or any child list
  1202. if( prevParent )
  1203. unlinkChildWindow( target );
  1204. else
  1205. unlinkWindow( target );
  1206. // add as child of 'parent'
  1207. addWindowToParent( target, parent );
  1208. // adjust the position so it's relative to the new parent
  1209. ICoord2D parentPos;
  1210. parent->winGetScreenPosition( &parentPos.x, &parentPos.y );
  1211. target->winSetPosition( screenPosBeforeMove.x - parentPos.x,
  1212. screenPosBeforeMove.y - parentPos.y );
  1213. // notify the hierarchy of the change
  1214. TheHierarchyView->moveWindowChildOf( target, parent );
  1215. //
  1216. // run through the move code to keep the child in a legal position
  1217. // inside the parent client area
  1218. //
  1219. ICoord2D origin, safeLoc;
  1220. target->winGetScreenPosition( &origin.x, &origin.y );
  1221. // kee the location legal
  1222. TheEditor->computeSafeLocation( target, origin.x, origin.y,
  1223. &safeLoc.x, &safeLoc.y );
  1224. // move the target
  1225. TheEditor->moveWindowTo( target, safeLoc.x, safeLoc.y );
  1226. } // end makeChildOf
  1227. //-------------------------------------------------------------------------------------------------
  1228. /** Move the 'windowToMove' to be just in front of the 'aheadOf' window
  1229. * in either the master window list or in the child list */
  1230. //-------------------------------------------------------------------------------------------------
  1231. void GUIEditWindowManager::moveAheadOf( GameWindow *windowToMove,
  1232. GameWindow *aheadOf )
  1233. {
  1234. // sanity
  1235. if( windowToMove == NULL || aheadOf == NULL || windowToMove == aheadOf )
  1236. return;
  1237. //
  1238. // get our screen position before the move ... we want to appear in the
  1239. // same place after we're moved
  1240. //
  1241. ICoord2D beforeMoveScreenPos;
  1242. windowToMove->winGetScreenPosition( &beforeMoveScreenPos.x,
  1243. &beforeMoveScreenPos.y );
  1244. // get the parent of that which we are moving
  1245. GameWindow *prevParent = windowToMove->winGetParent();
  1246. // take the window to move off the chain
  1247. if( prevParent )
  1248. {
  1249. ICoord2D pos;
  1250. // get he screen position of the window BEFORE we unlink it
  1251. windowToMove->winGetScreenPosition( &pos.x, &pos.y );
  1252. // take off the child list, this will remove our parent pointer as well
  1253. unlinkChildWindow( windowToMove );
  1254. //
  1255. // now that we're unlinked, set the position to be accurate with
  1256. // the screen position and no parent
  1257. //
  1258. windowToMove->winSetPosition( pos.x, pos.y );
  1259. } // end if
  1260. else
  1261. {
  1262. // just take off the main list
  1263. unlinkWindow( windowToMove );
  1264. } // end else
  1265. // insert the window at the specified location
  1266. insertWindowAheadOf( windowToMove, aheadOf );
  1267. //
  1268. // adjust our position to be in the same place in our new location
  1269. // in the chain ... if we gained a parent we have to offset by
  1270. // the difference between our parent screen and our screen positions.
  1271. // if we lost a parent our position must be set to the absolute
  1272. // screen position
  1273. //
  1274. GameWindow *newParent = windowToMove->winGetParent();
  1275. ICoord2D parentPos = { 0 }; // init to top left of screen
  1276. if( newParent )
  1277. newParent->winGetScreenPosition( &parentPos.x, &parentPos.y );
  1278. windowToMove->winSetPosition( beforeMoveScreenPos.x - parentPos.x,
  1279. beforeMoveScreenPos.y - parentPos.y );
  1280. // move the window hierarchy representation of this window
  1281. TheHierarchyView->moveWindowAheadOf( windowToMove, aheadOf );
  1282. //
  1283. // run through the move code to keep the child in a legal position
  1284. // inside the parent client area
  1285. //
  1286. ICoord2D origin, safeLoc;
  1287. windowToMove->winGetScreenPosition( &origin.x, &origin.y );
  1288. // kee the location legal
  1289. TheEditor->computeSafeLocation( windowToMove, origin.x, origin.y,
  1290. &safeLoc.x, &safeLoc.y );
  1291. // move the target
  1292. TheEditor->moveWindowTo( windowToMove, safeLoc.x, safeLoc.y );
  1293. } // end moveAheadOf