CGUIEditWorkspace.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956
  1. // Copyright (C) 2002-2012 Nikolaus Gebhardt / Gaz Davidson
  2. // This file is part of the "Irrlicht Engine".
  3. // For conditions of distribution and use, see copyright notice in irrlicht.h
  4. // Thanks to Midnight for all his testing, bug fixes and patches :)
  5. #include "CGUIEditWorkspace.h"
  6. #include "IGUIEnvironment.h"
  7. #include "IVideoDriver.h"
  8. #include "IOSOperator.h"
  9. #include "IReadFile.h"
  10. #include "IFileSystem.h"
  11. #include "IXMLWriter.h"
  12. #include "IGUISkin.h"
  13. #include "IGUIElementFactory.h"
  14. #include "CGUIEditWindow.h"
  15. #include "IGUIContextMenu.h"
  16. #include "IGUIFileOpenDialog.h"
  17. #include "IGUITreeView.h"
  18. #include "CGUIAttribute.h"
  19. #include "CMemoryReadWriteFile.h"
  20. namespace irr
  21. {
  22. namespace gui
  23. {
  24. //! constructor
  25. CGUIEditWorkspace::CGUIEditWorkspace(IGUIEnvironment* environment, s32 id, IGUIElement *parent)
  26. : IGUIElement(EGUIET_ELEMENT, environment, parent ? parent : environment->getRootGUIElement(), id, environment->getRootGUIElement()->getAbsolutePosition()),
  27. CurrentMode(EGUIEDM_SELECT), MouseOverMode(EGUIEDM_SELECT),
  28. GridSize(10,10), MenuCommandStart(0x3D17), DrawGrid(false), UseGrid(true),
  29. MouseOverElement(0), SelectedElement(0), EditorWindow(0)
  30. {
  31. #ifdef _DEBUG
  32. setDebugName("CGUIEditWorkspace");
  33. #endif
  34. // this element is never saved.
  35. setSubElement(true);
  36. // it resizes to fit a resizing window
  37. setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
  38. // Types which we currently can't handle in editor
  39. // Most of them also just don't make sense in here (like Dialogs)
  40. // TODO: We should have a way to create context-menus
  41. UnusableElementTypeFilter.push_back(EGUIET_CONTEXT_MENU);
  42. UnusableElementTypeFilter.push_back(EGUIET_FILE_OPEN_DIALOG);
  43. UnusableElementTypeFilter.push_back(EGUIET_COLOR_SELECT_DIALOG);
  44. UnusableElementTypeFilter.push_back(EGUIET_MESSAGE_BOX);
  45. UnusableElementTypeFilter.push_back(EGUIET_MODAL_SCREEN);
  46. UnusableElementTypeFilter.push_back(EGUIET_ELEMENT); // wouldn't do anything, so don't show in menu
  47. UnusableElementTypeFilter.push_back(EGUIET_ROOT); // wouldn't do anything, so don't show in menu
  48. EditorWindow = (CGUIEditWindow*) Environment->addGUIElement("GUIEditWindow", this);
  49. if (EditorWindow)
  50. {
  51. EditorWindow->grab();
  52. EditorWindow->setSubElement(true);
  53. Environment->setFocus(EditorWindow);
  54. serializeAttributes(EditorWindow->getOptionEditor()->getAttribs());
  55. EditorWindow->getOptionEditor()->refreshAttribs();
  56. if (EditorWindow->getEnvironmentEditor())
  57. {
  58. Environment->serializeAttributes(EditorWindow->getEnvironmentEditor()->getAttribs());
  59. EditorWindow->getEnvironmentEditor()->refreshAttribs();
  60. }
  61. }
  62. }
  63. //! destructor
  64. CGUIEditWorkspace::~CGUIEditWorkspace()
  65. {
  66. if (EditorWindow)
  67. EditorWindow->drop();
  68. }
  69. void CGUIEditWorkspace::setMenuCommandIDStart(s32 id)
  70. {
  71. MenuCommandStart = id;
  72. }
  73. CGUIEditWorkspace::EGUIEDIT_MODE CGUIEditWorkspace::getModeFromPos(core::position2di p)
  74. {
  75. if (SelectedElement)
  76. {
  77. core::rect<s32> r = SelectedElement->getAbsolutePosition();
  78. if (TLRect.isPointInside(p))
  79. return EGUIEDM_RESIZE_TL;
  80. else if (TRRect.isPointInside(p))
  81. return EGUIEDM_RESIZE_TR;
  82. else if (BLRect.isPointInside(p) )
  83. return EGUIEDM_RESIZE_BL;
  84. else if (BRRect.isPointInside(p))
  85. return EGUIEDM_RESIZE_BR;
  86. else if (TopRect.isPointInside(p))
  87. return EGUIEDM_RESIZE_T;
  88. else if (BRect.isPointInside(p))
  89. return EGUIEDM_RESIZE_B;
  90. else if (LRect.isPointInside(p))
  91. return EGUIEDM_RESIZE_L;
  92. else if (RRect.isPointInside(p))
  93. return EGUIEDM_RESIZE_R;
  94. else if (getEditableElementFromPoint(SelectedElement, p) == SelectedElement)
  95. return EGUIEDM_MOVE;
  96. else
  97. return EGUIEDM_SELECT;
  98. }
  99. return EGUIEDM_SELECT;
  100. }
  101. IGUIElement* CGUIEditWorkspace::getEditableElementFromPoint(IGUIElement *start, const core::position2di &point, s32 index )
  102. {
  103. IGUIElement* target = 0;
  104. // we have to search from back to front.
  105. core::list<IGUIElement*>::ConstIterator it = start->getChildren().getLast();
  106. s32 count=0;
  107. while(it != start->getChildren().end())
  108. {
  109. target = getEditableElementFromPoint((*it),point);
  110. if (target)
  111. {
  112. if (!target->isSubElement() && !isMyChild(target) && target != this)
  113. {
  114. if (index == count)
  115. return target;
  116. else
  117. count++;
  118. }
  119. else
  120. target = 0;
  121. }
  122. --it;
  123. }
  124. if (start->getAbsolutePosition().isPointInside(point))
  125. target = start;
  126. return target;
  127. }
  128. void CGUIEditWorkspace::setSelectedElement(IGUIElement *sel)
  129. {
  130. IGUIElement* focus = Environment->getFocus();
  131. // we only give focus back to children
  132. if (!isMyChild(focus))
  133. focus = 0;
  134. if (SelectedElement != Parent)
  135. {
  136. if (SelectedElement != sel && EditorWindow)
  137. {
  138. EditorWindow->setSelectedElement(sel);
  139. SelectedElement = sel;
  140. }
  141. }
  142. else
  143. SelectedElement = 0;
  144. if (focus)
  145. Environment->setFocus(focus);
  146. else
  147. Environment->setFocus(this);
  148. }
  149. IGUIElement* CGUIEditWorkspace::getSelectedElement()
  150. {
  151. return SelectedElement;
  152. }
  153. void CGUIEditWorkspace::selectNextSibling()
  154. {
  155. IGUIElement* p=0;
  156. if (SelectedElement && SelectedElement->getParent())
  157. p = SelectedElement->getParent();
  158. else
  159. p = Parent;
  160. core::list<IGUIElement*>::ConstIterator it = p->getChildren().begin();
  161. // find selected element
  162. if (SelectedElement)
  163. while (*it != SelectedElement)
  164. ++it;
  165. if (it !=p->getChildren().end())
  166. ++it;
  167. // find next non sub-element
  168. while (it != p->getChildren().end() && (*it)->isSubElement())
  169. ++it;
  170. if (it != p->getChildren().end())
  171. setSelectedElement(*it);
  172. }
  173. void CGUIEditWorkspace::selectPreviousSibling()
  174. {
  175. IGUIElement* p=0;
  176. if (SelectedElement && SelectedElement->getParent())
  177. p = SelectedElement->getParent();
  178. else
  179. p = Parent;
  180. core::list<IGUIElement*>::ConstIterator it = p->getChildren().getLast();
  181. // find selected element
  182. if (SelectedElement)
  183. while (*it != SelectedElement)
  184. --it;
  185. if (it != p->getChildren().end())
  186. --it;
  187. // find next non sub-element
  188. while (it != p->getChildren().end() && (*it)->isSubElement())
  189. --it;
  190. if (it != p->getChildren().end())
  191. setSelectedElement(*it);
  192. }
  193. //! called if an event happened.
  194. bool CGUIEditWorkspace::OnEvent(const SEvent &e)
  195. {
  196. IGUIFileOpenDialog* dialog=0;
  197. switch(e.EventType)
  198. {
  199. case ATTRIBEDIT_ATTRIB_CHANGED:
  200. {
  201. switch (e.UserEvent.UserData1)
  202. {
  203. case EGUIEDCE_ATTRIB_EDITOR:
  204. {
  205. // update selected items attributes
  206. if (SelectedElement)
  207. {
  208. SelectedElement->deserializeAttributes(EditorWindow->getAttributeEditor()->getAttribs());
  209. EditorWindow->updateTree();
  210. }
  211. return true;
  212. }
  213. case EGUIEDCE_OPTION_EDITOR:
  214. {
  215. // update editor options
  216. deserializeAttributes(EditorWindow->getOptionEditor()->getAttribs());
  217. return true;
  218. }
  219. case EGUIEDCE_ENV_EDITOR:
  220. {
  221. // update environment
  222. Environment->deserializeAttributes(EditorWindow->getEnvironmentEditor()->getAttribs());
  223. return true;
  224. }
  225. }
  226. }
  227. break;
  228. case EET_KEY_INPUT_EVENT:
  229. if (!e.KeyInput.PressedDown)
  230. {
  231. switch (e.KeyInput.Key)
  232. {
  233. case KEY_DELETE:
  234. if (SelectedElement)
  235. {
  236. IGUIElement* el = SelectedElement;
  237. setSelectedElement(0);
  238. MouseOverElement = 0;
  239. el->remove();
  240. EditorWindow->updateTree();
  241. }
  242. break;
  243. case KEY_KEY_X:
  244. if (e.KeyInput.Control && SelectedElement)
  245. {
  246. // cut
  247. CopySelectedElementXML();
  248. // delete element
  249. IGUIElement *el = SelectedElement;
  250. setSelectedElement(0);
  251. MouseOverElement = 0;
  252. el->remove();
  253. }
  254. break;
  255. case KEY_KEY_C:
  256. // copy
  257. if (e.KeyInput.Control && SelectedElement)
  258. {
  259. CopySelectedElementXML();
  260. }
  261. break;
  262. case KEY_KEY_V:
  263. // paste
  264. if (e.KeyInput.Control)
  265. {
  266. PasteXMLToSelectedElement();
  267. }
  268. break;
  269. default:
  270. break;
  271. }
  272. return true;
  273. }
  274. break;
  275. case EET_MOUSE_INPUT_EVENT:
  276. switch(e.MouseInput.Event)
  277. {
  278. case EMIE_MOUSE_WHEEL:
  279. {
  280. f32 wheel = e.MouseInput.Wheel;
  281. if (wheel > 0)
  282. selectPreviousSibling();
  283. else
  284. selectNextSibling();
  285. }
  286. break;
  287. case EMIE_LMOUSE_PRESSED_DOWN:
  288. {
  289. core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y);
  290. IGUIElement* newSelection = getElementFromPoint(p);
  291. if (newSelection != this && isMyChild(newSelection) ) // redirect event
  292. {
  293. Environment->setFocus(newSelection);
  294. return true;
  295. }
  296. // hide the gui editor
  297. if (EditorWindow)
  298. EditorWindow->setVisible(false);
  299. if (CurrentMode == EGUIEDM_SELECT)
  300. {
  301. if (SelectedElement)
  302. {
  303. // start moving or dragging
  304. CurrentMode = getModeFromPos(p);
  305. if (CurrentMode == EGUIEDM_MOVE)
  306. StartMovePos = SelectedElement->getAbsolutePosition().UpperLeftCorner;
  307. DragStart = p;
  308. SelectedArea = SelectedElement->getAbsolutePosition();
  309. }
  310. if (CurrentMode < EGUIEDM_MOVE)
  311. {
  312. // selecting an element...
  313. MouseOverElement = getEditableElementFromPoint(Parent, p);
  314. if (MouseOverElement == Parent)
  315. MouseOverElement = 0;
  316. setSelectedElement(MouseOverElement);
  317. }
  318. }
  319. break;
  320. }
  321. case EMIE_RMOUSE_PRESSED_DOWN:
  322. if (CurrentMode == EGUIEDM_SELECT_NEW_PARENT || CurrentMode >= EGUIEDM_MOVE)
  323. {
  324. // cancel dragging
  325. CurrentMode = EGUIEDM_SELECT;
  326. }
  327. else
  328. {
  329. DragStart = core::position2di(e.MouseInput.X,e.MouseInput.Y);
  330. // root menu
  331. IGUIContextMenu* mnu = Environment->addContextMenu(
  332. core::rect<s32>(e.MouseInput.X, e.MouseInput.Y, e.MouseInput.Y+100, e.MouseInput.Y+100),this);
  333. mnu->addItem(L"File",-1,true,true);
  334. mnu->addItem(L"Edit",-1,true,true);
  335. mnu->addItem(L"View",-1,true,true);
  336. mnu->addItem(SelectedElement ? L"Add child" : L"Add" ,-1,true,true);
  337. // file menu
  338. IGUIContextMenu* sub = mnu->getSubMenu(0);
  339. IGUIContextMenu* sub2 =0;
  340. sub->addItem(L"New", MenuCommandStart + EGUIEDMC_FILE_NEW );
  341. sub->addItem(L"Load...",MenuCommandStart + EGUIEDMC_FILE_LOAD);
  342. sub->addItem(L"Save...",MenuCommandStart + EGUIEDMC_FILE_SAVE);
  343. // edit menu
  344. sub = mnu->getSubMenu(1);
  345. sub->addItem(L"Cut (ctrl+x)", MenuCommandStart + EGUIEDMC_CUT_ELEMENT, (SelectedElement != 0));
  346. sub->addItem(L"Copy (ctrl+c)", MenuCommandStart + EGUIEDMC_COPY_ELEMENT, (SelectedElement != 0));
  347. sub->addItem(L"Paste (ctrl+v)", MenuCommandStart + EGUIEDMC_PASTE_ELEMENT,
  348. (core::stringc(Environment->getOSOperator()->getTextFromClipboard()) != ""));
  349. sub->addItem(L"Delete (del)", MenuCommandStart + EGUIEDMC_DELETE_ELEMENT, (SelectedElement != 0));
  350. sub->addSeparator();
  351. sub->addItem(L"Set parent", MenuCommandStart + EGUIEDMC_SET_PARENT, (SelectedElement != 0));
  352. sub->addItem(L"Bring to front", MenuCommandStart + EGUIEDMC_BRING_TO_FRONT, (SelectedElement != 0));
  353. sub->addSeparator();
  354. sub->addItem(L"Save to XML...", MenuCommandStart + EGUIEDMC_SAVE_ELEMENT, (SelectedElement != 0));
  355. sub = mnu->getSubMenu(2);
  356. // view menu
  357. if (EditorWindow)
  358. sub->addItem(EditorWindow->isVisible() ? L"Hide window" : L"Show window", MenuCommandStart + EGUIEDMC_TOGGLE_EDITOR);
  359. sub = mnu->getSubMenu(3);
  360. s32 i,j,c=0;
  361. sub->addItem(L"Default factory",-1,true, true);
  362. // add elements from each factory
  363. for (i=0; u32(i) < Environment->getRegisteredGUIElementFactoryCount(); ++i)
  364. {
  365. sub2 = sub->getSubMenu(i);
  366. IGUIElementFactory *f = Environment->getGUIElementFactory(i);
  367. for (j=0; j< f->getCreatableGUIElementTypeCount(); ++j)
  368. {
  369. EGUI_ELEMENT_TYPE type = f->getCreateableGUIElementType(j);
  370. if ( UnusableElementTypeFilter.linear_search(type) < 0 )
  371. sub2->addItem(core::stringw(f->getCreateableGUIElementTypeName(j)).c_str(), MenuCommandStart + EGUIEDMC_COUNT + c);
  372. c++;
  373. }
  374. if (u32(i+1) < Environment->getRegisteredGUIElementFactoryCount())
  375. {
  376. core::stringw strFact;
  377. strFact = L"Factory ";
  378. strFact += i+1;
  379. sub->addItem(strFact.c_str(),-1, true, true);
  380. }
  381. }
  382. sub->addSeparator();
  383. sub->addItem(L"From XML...", MenuCommandStart + EGUIEDMC_INSERT_XML);
  384. // set focus to menu
  385. Environment->setFocus(mnu);
  386. }
  387. break;
  388. case EMIE_LMOUSE_LEFT_UP:
  389. // make window visible again
  390. if (EditorWindow)
  391. EditorWindow->setVisible(true);
  392. if (CurrentMode == EGUIEDM_SELECT_NEW_PARENT)
  393. {
  394. if (SelectedElement)
  395. {
  396. MouseOverElement = getEditableElementFromPoint(Parent,
  397. core::position2di(e.MouseInput.X,e.MouseInput.Y));
  398. if (MouseOverElement)
  399. {
  400. MouseOverElement->addChild(SelectedElement);
  401. setSelectedElement(0);
  402. setSelectedElement(SelectedElement);
  403. }
  404. }
  405. CurrentMode = EGUIEDM_SELECT;
  406. }
  407. else if (CurrentMode >= EGUIEDM_MOVE)
  408. {
  409. IGUIElement *sel = SelectedElement;
  410. // unselect
  411. setSelectedElement(0);
  412. // move
  413. core::position2d<s32> p(0,0);
  414. if (sel->getParent())
  415. p = sel->getParent()->getAbsolutePosition().UpperLeftCorner;
  416. sel->setRelativePosition(SelectedArea - p);
  417. // select
  418. setSelectedElement(sel);
  419. // reset selection mode...
  420. CurrentMode = EGUIEDM_SELECT;
  421. }
  422. break;
  423. case EMIE_MOUSE_MOVED:
  424. // always on top
  425. Parent->bringToFront(this);
  426. // if selecting
  427. if (CurrentMode == EGUIEDM_SELECT || CurrentMode == EGUIEDM_SELECT_NEW_PARENT)
  428. {
  429. core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y);
  430. // highlight the element that the mouse is over
  431. MouseOverElement = getEditableElementFromPoint(Parent, p);
  432. if (MouseOverElement == Parent)
  433. {
  434. MouseOverElement = 0;
  435. }
  436. if (CurrentMode == EGUIEDM_SELECT)
  437. {
  438. MouseOverMode = getModeFromPos(p);
  439. if (MouseOverMode > EGUIEDM_MOVE)
  440. {
  441. MouseOverElement = SelectedElement;
  442. }
  443. }
  444. }
  445. else if (CurrentMode == EGUIEDM_MOVE)
  446. {
  447. // get difference
  448. core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y);
  449. p -= DragStart;
  450. // apply to top corner
  451. p = StartMovePos + p;
  452. if (UseGrid)
  453. {
  454. p.X = (p.X/GridSize.Width)*GridSize.Width;
  455. p.Y = (p.Y/GridSize.Height)*GridSize.Height;
  456. }
  457. SelectedArea += p - SelectedArea.UpperLeftCorner;
  458. }
  459. else if (CurrentMode > EGUIEDM_MOVE)
  460. {
  461. // get difference from start position
  462. core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y);
  463. if (UseGrid)
  464. {
  465. p.X = (p.X/GridSize.Width)*GridSize.Width;
  466. p.Y = (p.Y/GridSize.Height)*GridSize.Height;
  467. }
  468. switch(CurrentMode)
  469. {
  470. case EGUIEDM_RESIZE_T:
  471. SelectedArea.UpperLeftCorner.Y = p.Y;
  472. break;
  473. case EGUIEDM_RESIZE_B:
  474. SelectedArea.LowerRightCorner.Y = p.Y;
  475. break;
  476. case EGUIEDM_RESIZE_L:
  477. SelectedArea.UpperLeftCorner.X = p.X;
  478. break;
  479. case EGUIEDM_RESIZE_R:
  480. SelectedArea.LowerRightCorner.X = p.X;
  481. break;
  482. case EGUIEDM_RESIZE_TL:
  483. SelectedArea.UpperLeftCorner = p;
  484. break;
  485. case EGUIEDM_RESIZE_TR:
  486. SelectedArea.UpperLeftCorner.Y = p.Y;
  487. SelectedArea.LowerRightCorner.X = p.X;
  488. break;
  489. case EGUIEDM_RESIZE_BL:
  490. SelectedArea.UpperLeftCorner.X = p.X;
  491. SelectedArea.LowerRightCorner.Y = p.Y;
  492. break;
  493. case EGUIEDM_RESIZE_BR:
  494. SelectedArea.LowerRightCorner = p;
  495. break;
  496. default:
  497. break;
  498. }
  499. }
  500. break;
  501. default:
  502. break;
  503. }
  504. break;
  505. case EET_GUI_EVENT:
  506. switch(e.GUIEvent.EventType)
  507. {
  508. case EGET_TREEVIEW_NODE_SELECT:
  509. {
  510. IGUITreeViewNode* eventnode = ((IGUITreeView*)e.GUIEvent.Caller)->getLastEventNode();
  511. if(!eventnode->isRoot())
  512. setSelectedElement((IGUIElement*)(eventnode->getData()));
  513. break;
  514. }
  515. // load a gui file
  516. case EGET_FILE_SELECTED:
  517. {
  518. dialog = (IGUIFileOpenDialog*)e.GUIEvent.Caller;
  519. core::stringc guiFilename(core::stringc(dialog->getFileName()).c_str());
  520. clearParentElements();
  521. Environment->loadGUI(guiFilename, Parent);
  522. EditorWindow->updateTree();
  523. break;
  524. }
  525. case EGET_MENU_ITEM_SELECTED:
  526. {
  527. IGUIContextMenu *menu = (IGUIContextMenu*)e.GUIEvent.Caller;
  528. s32 cmdID = menu->getItemCommandId(menu->getSelectedItem()) - MenuCommandStart;
  529. IGUIElement* el;
  530. switch(cmdID)
  531. {
  532. //! file commands
  533. case EGUIEDMC_FILE_NEW:
  534. clearParentElements();
  535. break;
  536. case EGUIEDMC_FILE_LOAD:
  537. Environment->addFileOpenDialog(L"Please select a GUI file to open", false, this);
  538. break;
  539. case EGUIEDMC_FILE_SAVE:
  540. Environment->saveGUI("guiTest.xml");
  541. break;
  542. //! edit menu
  543. case EGUIEDMC_CUT_ELEMENT:
  544. {
  545. CopySelectedElementXML();
  546. // delete element
  547. el = SelectedElement;
  548. setSelectedElement(0);
  549. MouseOverElement = 0;
  550. el->remove();
  551. break;
  552. }
  553. case EGUIEDMC_COPY_ELEMENT:
  554. CopySelectedElementXML();
  555. break;
  556. case EGUIEDMC_PASTE_ELEMENT:
  557. PasteXMLToSelectedElement();
  558. break;
  559. case EGUIEDMC_DELETE_ELEMENT:
  560. el = SelectedElement;
  561. setSelectedElement(0);
  562. MouseOverElement = 0;
  563. el->remove();
  564. break;
  565. case EGUIEDMC_SET_PARENT:
  566. CurrentMode = EGUIEDM_SELECT_NEW_PARENT;
  567. break;
  568. case EGUIEDMC_BRING_TO_FRONT:
  569. if (SelectedElement->getParent())
  570. SelectedElement->getParent()->bringToFront(SelectedElement);
  571. break;
  572. case EGUIEDMC_SAVE_ELEMENT:
  573. //TODO: add 'save' dialog.
  574. Environment->saveGUI("guiTest.xml", SelectedElement ? SelectedElement : Environment->getRootGUIElement() );
  575. break;
  576. //! toggle edit window
  577. case EGUIEDMC_TOGGLE_EDITOR:
  578. break;
  579. case EGUIEDMC_INSERT_XML:
  580. Environment->loadGUI("guiTest.xml", SelectedElement ? SelectedElement : Environment->getRootGUIElement() );
  581. break;
  582. default:
  583. // create element from factory?
  584. if (cmdID >= EGUIEDMC_COUNT)
  585. {
  586. s32 num = cmdID - EGUIEDMC_COUNT; // get index
  587. // loop through all factories
  588. s32 i, c=Environment->getRegisteredGUIElementFactoryCount();
  589. for (i=0; i<c && num > Environment->getGUIElementFactory(i)->getCreatableGUIElementTypeCount(); ++i)
  590. {
  591. num -= Environment->getGUIElementFactory(i)->getCreatableGUIElementTypeCount();
  592. }
  593. if (num < Environment->getGUIElementFactory(i)->getCreatableGUIElementTypeCount() )
  594. {
  595. core::stringc name = Environment->getGUIElementFactory(i)->getCreateableGUIElementTypeName(num);
  596. IGUIElement *parentElement = SelectedElement ? SelectedElement : Environment->getRootGUIElement();
  597. // add it
  598. IGUIElement *newElement = Environment->getGUIElementFactory(i)->addGUIElement(name.c_str(),parentElement);
  599. if (newElement)
  600. {
  601. core::position2di p = DragStart - parentElement->getAbsolutePosition().UpperLeftCorner;
  602. newElement->setRelativePosition(core::rect<s32>(p,p+core::position2di(100,100)));
  603. //Environment->removeFocus(newElement);
  604. }
  605. }
  606. }
  607. break;
  608. }
  609. EditorWindow->updateTree();
  610. }
  611. return true;
  612. default:
  613. break;
  614. }
  615. break;
  616. default:
  617. break;
  618. }
  619. // even if we didn't absorb the event,
  620. // we never pass events back to the GUI we're editing!
  621. return false;
  622. }
  623. //! draws the element and its children
  624. void CGUIEditWorkspace::draw()
  625. {
  626. video::IVideoDriver *driver = Environment->getVideoDriver();
  627. if (DrawGrid)
  628. {
  629. // draw the grid
  630. core::rect<s32> r = getAbsolutePosition();
  631. s32 cy = r.UpperLeftCorner.Y;
  632. while (cy < r.LowerRightCorner.Y)
  633. {
  634. s32 cx = r.UpperLeftCorner.X;
  635. while (cx < r.LowerRightCorner.X)
  636. {
  637. driver->draw2DRectangle(video::SColor(40,0,0,90),core::rect<s32>(cx+1,cy+1,GridSize.Width+cx,GridSize.Height+cy));
  638. cx += GridSize.Width;
  639. }
  640. cy += GridSize.Height;
  641. }
  642. }
  643. if (MouseOverElement &&
  644. MouseOverElement != SelectedElement &&
  645. MouseOverElement != Parent)
  646. {
  647. core::rect<s32> r = MouseOverElement->getAbsolutePosition();
  648. driver->draw2DRectangle(video::SColor(100,0,0,255), r);
  649. }
  650. if (SelectedElement && CurrentMode == EGUIEDM_SELECT)
  651. {
  652. driver->draw2DRectangle(video::SColor(100,0,255,0),SelectedElement->getAbsolutePosition());
  653. }
  654. if (CurrentMode >= EGUIEDM_MOVE)
  655. {
  656. driver->draw2DRectangle(video::SColor(100,255,0,0),SelectedArea);
  657. }
  658. if ( (SelectedElement && CurrentMode >= EGUIEDM_MOVE) ||
  659. (SelectedElement && MouseOverElement == SelectedElement && MouseOverMode >= EGUIEDM_MOVE) )
  660. {
  661. // draw handles for moving
  662. EGUIEDIT_MODE m = CurrentMode;
  663. core::rect<s32> r = SelectedArea;
  664. if (m < EGUIEDM_MOVE)
  665. {
  666. m = MouseOverMode;
  667. r = SelectedElement->getAbsolutePosition();
  668. }
  669. core::position2di d = core::position2di(4,4);
  670. TLRect = core::rect<s32>(r.UpperLeftCorner, r.UpperLeftCorner + d );
  671. TRRect = core::rect<s32>(r.LowerRightCorner.X-4, r.UpperLeftCorner.Y, r.LowerRightCorner.X, r.UpperLeftCorner.Y+4);
  672. TopRect = core::rect<s32>(r.getCenter().X-2, r.UpperLeftCorner.Y,r.getCenter().X+2, r.UpperLeftCorner.Y+4 );
  673. BLRect = core::rect<s32>(r.UpperLeftCorner.X, r.LowerRightCorner.Y-4, r.UpperLeftCorner.X+4, r.LowerRightCorner.Y);
  674. LRect = core::rect<s32>(r.UpperLeftCorner.X,r.getCenter().Y-2, r.UpperLeftCorner.X+4, r.getCenter().Y+2 );
  675. RRect = core::rect<s32>(r.LowerRightCorner.X-4,r.getCenter().Y-2, r.LowerRightCorner.X, r.getCenter().Y+2 );
  676. BRRect = core::rect<s32>(r.LowerRightCorner-d, r.LowerRightCorner);
  677. BRect = core::rect<s32>(r.getCenter().X-2, r.LowerRightCorner.Y-4,r.getCenter().X+2, r.LowerRightCorner.Y );
  678. // top left
  679. if (m == EGUIEDM_RESIZE_T || m == EGUIEDM_RESIZE_L || m == EGUIEDM_RESIZE_TL || m == EGUIEDM_MOVE )
  680. driver->draw2DRectangle(video::SColor(100,255,255,255), TLRect);
  681. if (m == EGUIEDM_RESIZE_T || m == EGUIEDM_RESIZE_R || m == EGUIEDM_RESIZE_TR || m == EGUIEDM_MOVE )
  682. driver->draw2DRectangle(video::SColor(100,255,255,255), TRRect);
  683. if (m == EGUIEDM_RESIZE_T || m == EGUIEDM_MOVE )
  684. driver->draw2DRectangle(video::SColor(100,255,255,255), TopRect);
  685. if (m == EGUIEDM_RESIZE_L || m == EGUIEDM_RESIZE_BL || m == EGUIEDM_RESIZE_B || m == EGUIEDM_MOVE )
  686. driver->draw2DRectangle(video::SColor(100,255,255,255), BLRect);
  687. if (m == EGUIEDM_RESIZE_L || m == EGUIEDM_MOVE )
  688. driver->draw2DRectangle(video::SColor(100,255,255,255), LRect);
  689. if (m == EGUIEDM_RESIZE_R || m == EGUIEDM_MOVE )
  690. driver->draw2DRectangle(video::SColor(100,255,255,255), RRect);
  691. if (m == EGUIEDM_RESIZE_R || m == EGUIEDM_RESIZE_BR || m == EGUIEDM_RESIZE_B || m == EGUIEDM_MOVE )
  692. driver->draw2DRectangle(video::SColor(100,255,255,255), BRRect );
  693. if (m == EGUIEDM_RESIZE_B || m == EGUIEDM_MOVE )
  694. driver->draw2DRectangle(video::SColor(100,255,255,255), BRect);
  695. }
  696. IGUIElement::draw();
  697. }
  698. void CGUIEditWorkspace::setDrawGrid(bool drawGrid)
  699. {
  700. DrawGrid = drawGrid;
  701. }
  702. void CGUIEditWorkspace::setGridSize(const core::dimension2di& gridSize)
  703. {
  704. GridSize = gridSize;
  705. if (GridSize.Width < 2)
  706. GridSize.Width = 2;
  707. if (GridSize.Height < 2)
  708. GridSize.Height = 2;
  709. }
  710. void CGUIEditWorkspace::setUseGrid(bool useGrid)
  711. {
  712. UseGrid = useGrid;
  713. }
  714. //! Removes a child.
  715. void CGUIEditWorkspace::removeChild(IGUIElement* child)
  716. {
  717. IGUIElement::removeChild(child);
  718. // TODO: Can anyone find out why the workspace removes itself when it has no more children
  719. // and document it here?
  720. if (Children.empty())
  721. remove();
  722. }
  723. void CGUIEditWorkspace::clearParentElements()
  724. {
  725. setSelectedElement(0);
  726. MouseOverElement = 0;
  727. IGUIElement * el = Parent;
  728. grab();
  729. if ( el->isMyChild(Environment->getFocus()) )
  730. Environment->setFocus(0);
  731. while (!el->getChildren().empty())
  732. {
  733. el->removeChild(*(el->getChildren().begin()));
  734. }
  735. el->addChild(this);
  736. drop();
  737. }
  738. void CGUIEditWorkspace::updateAbsolutePosition()
  739. {
  740. core::rect<s32> parentRect(0,0,0,0);
  741. if (Parent)
  742. {
  743. parentRect = Parent->getAbsolutePosition();
  744. RelativeRect.UpperLeftCorner.X = 0;
  745. RelativeRect.UpperLeftCorner.Y = 0;
  746. RelativeRect.LowerRightCorner.X = parentRect.getWidth();
  747. RelativeRect.LowerRightCorner.Y = parentRect.getHeight();
  748. }
  749. IGUIElement::updateAbsolutePosition();
  750. }
  751. void CGUIEditWorkspace::CopySelectedElementXML()
  752. {
  753. core::stringc XMLText;
  754. core::stringw wXMLText;
  755. // create memory write file
  756. io::CMemoryReadWriteFile* memWrite = new io::CMemoryReadWriteFile("#Clipboard#");
  757. // save gui to mem file
  758. io::IXMLWriter* xml = Environment->getFileSystem()->createXMLWriter(memWrite);
  759. Environment->writeGUIElement(xml, SelectedElement);
  760. // copy to clipboard- wide chars not supported yet :(
  761. wXMLText = (wchar_t*)&memWrite->getData()[0];
  762. u32 i = memWrite->getData().size()/sizeof(wchar_t);
  763. if (wXMLText.size() > i)
  764. wXMLText[i] = L'\0';
  765. XMLText = wXMLText.c_str();
  766. memWrite->drop();
  767. xml->drop();
  768. Environment->getOSOperator()->copyToClipboard(XMLText.c_str());
  769. }
  770. void CGUIEditWorkspace::PasteXMLToSelectedElement()
  771. {
  772. // get clipboard data
  773. const char * p = Environment->getOSOperator()->getTextFromClipboard();
  774. irr::core::stringw wXMLText;
  775. core::multibyteToWString(wXMLText, p);
  776. io::CMemoryReadWriteFile* memWrite = new io::CMemoryReadWriteFile("#Clipboard#");
  777. io::IXMLWriter* xmlw = Environment->getFileSystem()->createXMLWriter(memWrite);
  778. xmlw->writeXMLHeader(); // it needs one of those
  779. xmlw->drop();
  780. // write clipboard data
  781. memWrite->write((void*)&wXMLText[0], wXMLText.size() * sizeof(wchar_t));
  782. // rewind file
  783. memWrite->seek(0, false);
  784. // read xml
  785. Environment->loadGUI(memWrite, SelectedElement);
  786. // reset focus
  787. Environment->setFocus(this);
  788. // drop the read file
  789. memWrite->drop();
  790. }
  791. void CGUIEditWorkspace::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options)
  792. {
  793. out->addBool("DrawGrid", DrawGrid);
  794. out->addBool("UseGrid", UseGrid);
  795. out->addPosition2d("GridSize", core::position2di(GridSize.Width, GridSize.Height));
  796. out->addInt("MenuCommandStart", MenuCommandStart);
  797. }
  798. void CGUIEditWorkspace::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
  799. {
  800. setDrawGrid(in->getAttributeAsBool("DrawGrid"));
  801. setUseGrid(in->getAttributeAsBool("UseGrid"));
  802. core::position2di tmpp = in->getAttributeAsPosition2d("GridSize");
  803. core::dimension2di tmpd(tmpp.X, tmpp.Y);
  804. setGridSize(tmpd);
  805. setMenuCommandIDStart(in->getAttributeAsInt("MenuCommandStart"));
  806. }
  807. } // end namespace gui
  808. } // end namespace irr