guiEditCtrl.cc 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "console/console.h"
  23. #include "console/consoleTypes.h"
  24. #include "graphics/dgl.h"
  25. #include "sim/simBase.h"
  26. #include "gui/guiCanvas.h"
  27. #include "gui/editor/guiEditCtrl.h"
  28. #include "platform/event.h"
  29. #include "io/fileStream.h"
  30. #include "gui/containers/guiScrollCtrl.h"
  31. IMPLEMENT_CONOBJECT(GuiEditCtrl);
  32. GuiEditCtrl::GuiEditCtrl(): mCurrentAddSet(NULL),
  33. mContentControl(NULL),
  34. mGridSnap(0,0),
  35. mDragBeginPoint(-1,-1)
  36. {
  37. VECTOR_SET_ASSOCIATION(mSelectedControls);
  38. VECTOR_SET_ASSOCIATION(mDragBeginPoints);
  39. mActive = true;
  40. mDragBeginPoints.clear();
  41. mSelectedControls.clear();
  42. mDefaultCursor = NULL;
  43. mLeftRightCursor = NULL;
  44. mUpDownCursor = NULL;
  45. mNWSECursor = NULL;
  46. mNESWCursor = NULL;
  47. mMoveCursor = NULL;
  48. }
  49. bool GuiEditCtrl::onAdd()
  50. {
  51. if(!Parent::onAdd())
  52. return false;
  53. mTrash.registerObject();
  54. mSelectedSet.registerObject();
  55. mUndoManager.registerObject();
  56. return true;
  57. }
  58. void GuiEditCtrl::onRemove()
  59. {
  60. Parent::onRemove();
  61. mTrash.unregisterObject();
  62. mSelectedSet.unregisterObject();
  63. mUndoManager.unregisterObject();
  64. }
  65. ConsoleMethod( GuiEditCtrl, setRoot, void, 3, 3, "(GuiControl root) Sets the given control as root\n"
  66. "@return No return value.")
  67. {
  68. GuiControl *ctrl;
  69. if(!Sim::findObject(argv[2], ctrl))
  70. return;
  71. object->setRoot(ctrl);
  72. }
  73. ConsoleMethod( GuiEditCtrl, addNewCtrl, void, 3, 3, "(GuiControl ctrl) Adds the given control to the control list\n"
  74. "@return No return value.")
  75. {
  76. GuiControl *ctrl;
  77. if(!Sim::findObject(argv[2], ctrl))
  78. return;
  79. object->addNewControl(ctrl);
  80. }
  81. ConsoleMethod( GuiEditCtrl, addSelection, void, 3, 3, "(ctrlID) Adds the selected control.\n"
  82. "@return No return value.")
  83. {
  84. S32 id = dAtoi(argv[2]);
  85. object->addSelection(id);
  86. }
  87. ConsoleMethod( GuiEditCtrl, removeSelection, void, 3, 3, "(ctrlID) Removes the selected control from list.\n"
  88. "@return No return value.")
  89. {
  90. S32 id = dAtoi(argv[2]);
  91. object->removeSelection(id);
  92. }
  93. ConsoleMethod( GuiEditCtrl, clearSelection, void, 2, 2, "() Clear selected controls list.\n"
  94. "@return No return value.")
  95. {
  96. object->clearSelection();
  97. }
  98. ConsoleMethod( GuiEditCtrl, select, void, 3, 3, "(GuiControl ctrl) Finds and selects given object\n"
  99. "@return No return value.")
  100. {
  101. GuiControl *ctrl;
  102. if(!Sim::findObject(argv[2], ctrl))
  103. return;
  104. object->setSelection(ctrl, false);
  105. }
  106. ConsoleMethod( GuiEditCtrl, setCurrentAddSet, void, 3, 3, "(GuiControl ctrl) Set the current control set in which controls are added.\n"
  107. "@param ctrl The addset\n"
  108. "@return No return value.")
  109. {
  110. GuiControl *addSet;
  111. if (!Sim::findObject(argv[2], addSet))
  112. {
  113. Con::printf("%s(): Invalid control: %s", argv[0], argv[2]);
  114. return;
  115. }
  116. object->setCurrentAddSet(addSet);
  117. }
  118. ConsoleMethod( GuiEditCtrl, getCurrentAddSet, S32, 2, 2, "()\n @return Returns the set to which new controls will be added")
  119. {
  120. const GuiControl* add = object->getCurrentAddSet();
  121. return add ? add->getId() : 0;
  122. }
  123. ConsoleMethod( GuiEditCtrl, toggle, void, 2, 2, "() Toggle activation.\n"
  124. "@return No return value.")
  125. {
  126. object->setEditMode(! object->mActive);
  127. }
  128. ConsoleMethod( GuiEditCtrl, justify, void, 3, 3, "(int mode) Sets justification mode of selection\n"
  129. "@return No return value." )
  130. {
  131. object->justifySelection((GuiEditCtrl::Justification)dAtoi(argv[2]));
  132. }
  133. ConsoleMethod( GuiEditCtrl, bringToFront, void, 2, 2, "() Brings control to front\n"
  134. "@return No return value.")
  135. {
  136. object->bringToFront();
  137. }
  138. ConsoleMethod( GuiEditCtrl, pushToBack, void, 2, 2, "() Sends control to back\n"
  139. "@return No return value.")
  140. {
  141. object->pushToBack();
  142. }
  143. ConsoleMethod( GuiEditCtrl, deleteSelection, void, 2, 2, "Delete the selected text.\n"
  144. "@return No return value.")
  145. {
  146. object->deleteSelection();
  147. }
  148. ConsoleMethod( GuiEditCtrl, moveSelection, void, 4, 4, "(int deltax, int deltay) Moves selection to given (relative to current position) point\n"
  149. "@param deltax,deltay The change in coordinates.\n"
  150. "@return No return value.")
  151. {
  152. object->moveAndSnapSelection(Point2I(dAtoi(argv[2]), dAtoi(argv[3])));
  153. }
  154. ConsoleMethod( GuiEditCtrl, saveSelection, void, 3, 3, "(string fileName) Saves the current selection to given filename\n"
  155. "@return No return value.")
  156. {
  157. object->saveSelection(argv[2]);
  158. }
  159. ConsoleMethod( GuiEditCtrl, loadSelection, void, 3, 3, "(string fileName) Loads from given filename\n"
  160. "@return No return value.")
  161. {
  162. object->loadSelection(argv[2]);
  163. }
  164. ConsoleMethod( GuiEditCtrl, selectAll, void, 2, 2, "() Selects all controls in list\n"
  165. "@return No return value.")
  166. {
  167. object->selectAll();
  168. }
  169. ConsoleMethod( GuiEditCtrl, getSelected, S32, 2, 2, "() Gets the GUI control(s) the editor is currently selecting\n"
  170. "@return Returns the ID of the control.")
  171. {
  172. return object->getSelectedSet().getId();
  173. }
  174. ConsoleMethod( GuiEditCtrl, getTrash, S32, 2, 2, "() Gets the GUI controls(s) that are currently in the trash.\n"
  175. "@return Returns the ID of the control")
  176. {
  177. return object->getTrash().getId();
  178. }
  179. ConsoleMethod( GuiEditCtrl, getUndoManager, S32, 2, 2, "() Gets the Gui Editor's UndoManager object\n"
  180. "@return Returns the ID of the object.")
  181. {
  182. return object->getUndoManager().getId();
  183. }
  184. bool GuiEditCtrl::onWake()
  185. {
  186. if (! Parent::onWake())
  187. return false;
  188. // Set GUI Controls to DesignTime mode
  189. GuiControl::smDesignTime = true;
  190. GuiControl::smEditorHandle = this;
  191. setEditMode(true);
  192. // TODO: paxorr: I'm not sure this is the best way to set these defaults.
  193. bool snap = Con::getBoolVariable("$pref::GuiEditor::snap2grid",false);
  194. U32 grid = Con::getIntVariable("$pref::GuiEditor::snap2gridsize",8);
  195. Con::setBoolVariable("$pref::GuiEditor::snap2grid", snap);
  196. Con::setIntVariable("$pref::GuiEditor::snap2gridsize",grid);
  197. setSnapToGrid( snap ? grid : 0);
  198. return true;
  199. }
  200. void GuiEditCtrl::onSleep()
  201. {
  202. // Set GUI Controls to run time mode
  203. GuiControl::smDesignTime = false;
  204. GuiControl::smEditorHandle = NULL;
  205. Parent::onSleep();
  206. }
  207. void GuiEditCtrl::setRoot(GuiControl *root)
  208. {
  209. mContentControl = root;
  210. if( root != NULL ) root->mIsContainer = true;
  211. mCurrentAddSet = mContentControl;
  212. Con::executef(this, 1, "onClearSelected");
  213. mSelectedControls.clear();
  214. }
  215. enum GuiEditConstants {
  216. GUI_BLACK = 0,
  217. GUI_WHITE = 255,
  218. NUT_SIZE = 4
  219. };
  220. // Sizing Cursors
  221. bool GuiEditCtrl::initCursors()
  222. {
  223. if (mMoveCursor == NULL || mUpDownCursor == NULL || mLeftRightCursor == NULL || mDefaultCursor == NULL || mNWSECursor == NULL || mNESWCursor == NULL)
  224. {
  225. SimObject *obj;
  226. obj = Sim::findObject("MoveCursor");
  227. mMoveCursor = dynamic_cast<GuiCursor*>(obj);
  228. obj = Sim::findObject("UpDownCursor");
  229. mUpDownCursor = dynamic_cast<GuiCursor*>(obj);
  230. obj = Sim::findObject("LeftRightCursor");
  231. mLeftRightCursor = dynamic_cast<GuiCursor*>(obj);
  232. obj = Sim::findObject("DefaultCursor");
  233. mDefaultCursor = dynamic_cast<GuiCursor*>(obj);
  234. obj = Sim::findObject("NESWCursor");
  235. mNESWCursor = dynamic_cast<GuiCursor*>(obj);
  236. obj = Sim::findObject("NWSECursor");
  237. mNWSECursor = dynamic_cast<GuiCursor*>(obj);
  238. obj = Sim::findObject("MoveCursor");
  239. mMoveCursor = dynamic_cast<GuiCursor*>(obj);
  240. return(mMoveCursor != NULL && mUpDownCursor != NULL && mLeftRightCursor != NULL && mDefaultCursor != NULL && mNWSECursor != NULL && mNESWCursor != NULL && mMoveCursor != NULL);
  241. }
  242. else
  243. return(true);
  244. }
  245. void GuiEditCtrl::setEditMode(bool value)
  246. {
  247. mActive = value;
  248. Con::executef(this, 1, "onClearSelected");
  249. mSelectedControls.clear();
  250. if (mActive && mAwake)
  251. mCurrentAddSet = NULL;
  252. }
  253. void GuiEditCtrl::setCurrentAddSet(GuiControl *ctrl, bool clearSelection)
  254. {
  255. if (ctrl != mCurrentAddSet)
  256. {
  257. if(clearSelection)
  258. {
  259. Con::executef(this, 1, "onClearSelected");
  260. mSelectedControls.clear();
  261. }
  262. mCurrentAddSet = ctrl;
  263. }
  264. }
  265. const GuiControl* GuiEditCtrl::getCurrentAddSet() const
  266. {
  267. return mCurrentAddSet ? mCurrentAddSet : mContentControl;
  268. }
  269. void GuiEditCtrl::clearSelection(void)
  270. {
  271. mSelectedControls.clear();
  272. }
  273. void GuiEditCtrl::setSelection(GuiControl *ctrl, bool inclusive)
  274. {
  275. //sanity check
  276. if (! ctrl)
  277. return;
  278. if(mContentControl == ctrl)
  279. {
  280. mCurrentAddSet = ctrl;
  281. Con::executef(this, 1, "onClearSelected");
  282. mSelectedControls.clear();
  283. }
  284. else
  285. {
  286. // otherwise, we hit a new control...
  287. GuiControl *newAddSet = ctrl->getParent();
  288. //see if we should clear the old selection set
  289. if (newAddSet != mCurrentAddSet || (! inclusive)) {
  290. Con::executef(this, 1, "onClearSelected");
  291. mSelectedControls.clear();
  292. }
  293. //set the selection
  294. mCurrentAddSet = newAddSet;
  295. //if (!(ctrl->isLocked())) {
  296. mSelectedControls.push_back(ctrl);
  297. Con::executef(this, 2, "onAddSelected", Con::getIntArg(ctrl->getId()));
  298. //}
  299. }
  300. }
  301. void GuiEditCtrl::addNewControl(GuiControl *ctrl)
  302. {
  303. if (! mCurrentAddSet)
  304. mCurrentAddSet = mContentControl;
  305. mCurrentAddSet->addObject(ctrl);
  306. Con::executef(this, 1, "onClearSelected");
  307. mSelectedControls.clear();
  308. //if (!(ctrl->isLocked())) {
  309. mSelectedControls.push_back(ctrl);
  310. Con::executef(this, 2, "onAddSelected", Con::getIntArg(ctrl->getId()));
  311. //}
  312. // undo
  313. Con::executef(this, 2, "onAddNewCtrl", Con::getIntArg(ctrl->getId()));
  314. }
  315. void GuiEditCtrl::drawNut(const Point2I &nut, ColorI &outlineColor, ColorI &nutColor)
  316. {
  317. RectI r(nut.x - NUT_SIZE, nut.y - NUT_SIZE, 2 * NUT_SIZE, 2 * NUT_SIZE);
  318. r.inset(1, 1);
  319. dglDrawRectFill(r, nutColor);
  320. r.inset(-1, -1);
  321. dglDrawRect(r, outlineColor);
  322. }
  323. static inline bool inNut(const Point2I &pt, S32 x, S32 y)
  324. {
  325. S32 dx = pt.x - x;
  326. S32 dy = pt.y - y;
  327. return dx <= NUT_SIZE && dx >= -NUT_SIZE && dy <= NUT_SIZE && dy >= -NUT_SIZE;
  328. }
  329. S32 GuiEditCtrl::getSizingHitKnobs(const Point2I &pt, const RectI &box)
  330. {
  331. S32 lx = box.point.x, rx = box.point.x + box.extent.x - 1;
  332. S32 cx = (lx + rx) >> 1;
  333. S32 ty = box.point.y, by = box.point.y + box.extent.y - 1;
  334. S32 cy = (ty + by) >> 1;
  335. // adjust nuts, so they dont straddle the controls
  336. lx -= NUT_SIZE;
  337. ty -= NUT_SIZE;
  338. rx += NUT_SIZE;
  339. by += NUT_SIZE;
  340. if (inNut(pt, lx, ty))
  341. return sizingLeft | sizingTop;
  342. if (inNut(pt, cx, ty))
  343. return sizingTop;
  344. if (inNut(pt, rx, ty))
  345. return sizingRight | sizingTop;
  346. if (inNut(pt, lx, by))
  347. return sizingLeft | sizingBottom;
  348. if (inNut(pt, cx, by))
  349. return sizingBottom;
  350. if (inNut(pt, rx, by))
  351. return sizingRight | sizingBottom;
  352. if (inNut(pt, lx, cy))
  353. return sizingLeft;
  354. if (inNut(pt, rx, cy))
  355. return sizingRight;
  356. return sizingNone;
  357. }
  358. void GuiEditCtrl::drawNuts(RectI &box, ColorI &outlineColor, ColorI &nutColor)
  359. {
  360. S32 lx = box.point.x, rx = box.point.x + box.extent.x - 1;
  361. S32 cx = (lx + rx) >> 1;
  362. S32 ty = box.point.y, by = box.point.y + box.extent.y - 1;
  363. S32 cy = (ty + by) >> 1;
  364. ColorF greenLine(0.0f, 1.0f, 0.0f ,0.6f);
  365. ColorF lightGreenLine(0.0f, 1.0f, 0.0f, 0.3f);
  366. if(lx > 0 && ty > 0)
  367. {
  368. dglDrawLine(0, ty, lx, ty, greenLine);
  369. dglDrawLine(lx, 0, lx, ty, greenLine);
  370. }
  371. if(lx > 0 && by > 0)
  372. dglDrawLine(0, by, lx, by, greenLine);
  373. if(rx > 0 && ty > 0)
  374. dglDrawLine(rx, 0, rx, ty, greenLine);
  375. Point2I extent = localToGlobalCoord(mBounds.extent);
  376. if(lx < extent.x && by < extent.y)
  377. dglDrawLine(lx, by, lx, extent.y, lightGreenLine);
  378. if(rx < extent.x && by < extent.y)
  379. {
  380. dglDrawLine(rx, by, rx, extent.y, lightGreenLine);
  381. dglDrawLine(rx, by, extent.x, by, lightGreenLine);
  382. }
  383. if(rx < extent.x && ty < extent.y)
  384. dglDrawLine(rx, ty, extent.x, ty, lightGreenLine);
  385. // adjust nuts, so they dont straddle the controls
  386. lx -= NUT_SIZE;
  387. ty -= NUT_SIZE;
  388. rx += NUT_SIZE;
  389. by += NUT_SIZE;
  390. drawNut(Point2I(lx, ty), outlineColor, nutColor);
  391. drawNut(Point2I(lx, cy), outlineColor, nutColor);
  392. drawNut(Point2I(lx, by), outlineColor, nutColor);
  393. drawNut(Point2I(rx, ty), outlineColor, nutColor);
  394. drawNut(Point2I(rx, cy), outlineColor, nutColor);
  395. drawNut(Point2I(rx, by), outlineColor, nutColor);
  396. drawNut(Point2I(cx, ty), outlineColor, nutColor);
  397. drawNut(Point2I(cx, by), outlineColor, nutColor);
  398. }
  399. void GuiEditCtrl::getDragRect(RectI &box)
  400. {
  401. box.point.x = getMin(mLastMousePos.x, mSelectionAnchor.x);
  402. box.extent.x = getMax(mLastMousePos.x, mSelectionAnchor.x) - box.point.x + 1;
  403. box.point.y = getMin(mLastMousePos.y, mSelectionAnchor.y);
  404. box.extent.y = getMax(mLastMousePos.y, mSelectionAnchor.y) - box.point.y + 1;
  405. }
  406. void GuiEditCtrl::onPreRender()
  407. {
  408. setUpdate();
  409. }
  410. void GuiEditCtrl::onRender(Point2I offset, const RectI &updateRect)
  411. {
  412. Point2I ctOffset;
  413. Point2I cext;
  414. bool keyFocused = isFirstResponder();
  415. if (mActive)
  416. {
  417. if (mCurrentAddSet)
  418. {
  419. // draw a white frame inset around the current add set.
  420. cext = mCurrentAddSet->getExtent();
  421. ctOffset = mCurrentAddSet->localToGlobalCoord(Point2I(0,0));
  422. RectI box(ctOffset.x, ctOffset.y, cext.x, cext.y);
  423. box.inset(-5, -5);
  424. dglDrawRect(box, ColorI(0, 101, 0,160));
  425. box.inset(1,1);
  426. dglDrawRect(box, ColorI(0, 101, 0,170));
  427. box.inset(1,1);
  428. dglDrawRect(box, ColorI(0, 101, 0,180));
  429. box.inset(1,1);
  430. dglDrawRect(box, ColorI(0, 101, 0,190));
  431. box.inset(1,1);
  432. dglDrawRect(box, ColorI(0, 101, 0,200));
  433. }
  434. Vector<GuiControl *>::iterator i;
  435. bool multisel = mSelectedControls.size() > 1;
  436. for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  437. {
  438. GuiControl *ctrl = (*i);
  439. cext = ctrl->getExtent();
  440. ctOffset = ctrl->localToGlobalCoord(Point2I(0,0));
  441. RectI box(ctOffset.x,ctOffset.y, cext.x, cext.y);
  442. ColorI nutColor = multisel ? ColorI(255,255,255) : ColorI(0,0,0);
  443. ColorI outlineColor = multisel ? ColorI(0,0,0) : ColorI(255,255,255);
  444. if(!keyFocused)
  445. nutColor.set(128,128,128);
  446. drawNuts(box, outlineColor, nutColor);
  447. }
  448. if (mMouseDownMode == DragSelecting)
  449. {
  450. RectI b;
  451. getDragRect(b);
  452. b.point += offset;
  453. dglDrawRect(b, ColorI(255, 255, 255));
  454. }
  455. }
  456. renderChildControls(offset, mBounds, updateRect);
  457. if(mActive && mCurrentAddSet && (mGridSnap.x && mGridSnap.y) &&
  458. (mMouseDownMode == MovingSelection || mMouseDownMode == SizingSelection))
  459. {
  460. Point2I cext = mCurrentAddSet->getExtent();
  461. Point2I coff = mCurrentAddSet->localToGlobalCoord(Point2I(0,0));
  462. // create point-dots
  463. Point2I snap = mGridSnap;
  464. if(snap.x < 6)
  465. snap *= 2;
  466. if(snap.x < 6)
  467. snap *= 2;
  468. U32 maxdot = (cext.x / snap.x) * (cext.y / snap.y);
  469. Point2F* dots = new Point2F[maxdot];
  470. U32 ndot = 0;
  471. for(U32 ix = (U32)snap.x; ix < (U32)cext.x; ix += snap.x)
  472. {
  473. for(U32 iy = snap.y; iy < (U32)cext.y; iy += snap.y)
  474. {
  475. dots[ndot].x = (F32)(ix + coff.x);
  476. dots[ndot++].y = (F32)(iy + coff.y);
  477. }
  478. }
  479. AssertFatal(ndot <= maxdot, "dot overflow");
  480. // draw the points.
  481. glEnableClientState(GL_VERTEX_ARRAY);
  482. glEnable( GL_BLEND );
  483. glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
  484. glVertexPointer(2, GL_FLOAT, 0, dots);
  485. glColor4ub(50, 50, 254, 200);
  486. glDrawArrays( GL_POINTS, 0, ndot);
  487. glDisableClientState(GL_VERTEX_ARRAY);
  488. glDisable(GL_BLEND);
  489. delete[] dots;
  490. }
  491. }
  492. bool GuiEditCtrl::selectionContains(GuiControl *ctrl)
  493. {
  494. Vector<GuiControl *>::iterator i;
  495. for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  496. if (ctrl == *i) return true;
  497. return false;
  498. }
  499. void GuiEditCtrl::onRightMouseDown(const GuiEvent &event)
  500. {
  501. if (! mActive || !mContentControl)
  502. {
  503. Parent::onRightMouseDown(event);
  504. return;
  505. }
  506. setFirstResponder();
  507. //search for the control hit in any layer below the edit layer
  508. GuiControl *hitCtrl = mContentControl->findHitControl(globalToLocalCoord(event.mousePoint), mLayer - 1);
  509. if (hitCtrl != mCurrentAddSet)
  510. {
  511. Con::executef(this, 1, "onClearSelected");
  512. mSelectedControls.clear();
  513. mCurrentAddSet = hitCtrl;
  514. }
  515. // select the parent if we right-click on the current add set
  516. else if( mCurrentAddSet != mContentControl)
  517. {
  518. mCurrentAddSet = hitCtrl->getParent();
  519. select(hitCtrl);
  520. }
  521. //Design time mouse events
  522. GuiEvent designEvent = event;
  523. designEvent.mousePoint = mLastMousePos;
  524. hitCtrl->onRightMouseDownEditor( designEvent, localToGlobalCoord( Point2I(0,0) ) );
  525. }
  526. void GuiEditCtrl::select(GuiControl *ctrl)
  527. {
  528. Con::executef(this, 1, "onClearSelected");
  529. mSelectedControls.clear();
  530. if(ctrl != mContentControl) {
  531. //if (!(ctrl->isLocked())) {
  532. mSelectedControls.push_back(ctrl);
  533. Con::executef(this, 2, "onAddSelected", Con::getIntArg(ctrl->getId()));
  534. //}
  535. }
  536. else
  537. mCurrentAddSet = mContentControl;
  538. }
  539. void GuiEditCtrl::getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent)
  540. {
  541. showCursor = true;
  542. Point2I ctOffset;
  543. Point2I cext;
  544. GuiControl *ctrl;
  545. Point2I mousePos = globalToLocalCoord(lastGuiEvent.mousePoint);
  546. // first see if we hit a sizing knob on the currently selected control...
  547. if (mSelectedControls.size() == 1 && initCursors() == true )
  548. {
  549. ctrl = mSelectedControls.first();
  550. cext = ctrl->getExtent();
  551. ctOffset = globalToLocalCoord(ctrl->localToGlobalCoord(Point2I(0,0)));
  552. RectI box(ctOffset.x,ctOffset.y,cext.x, cext.y);
  553. GuiEditCtrl::sizingModes sizeMode = (GuiEditCtrl::sizingModes)getSizingHitKnobs(mousePos, box);
  554. if( mMouseDownMode == SizingSelection )
  555. {
  556. if ( ( mSizingMode == ( sizingBottom | sizingRight ) ) || ( mSizingMode == ( sizingTop | sizingLeft ) ) )
  557. cursor = mNWSECursor;
  558. else if ( ( mSizingMode == ( sizingBottom | sizingLeft ) ) || ( mSizingMode == ( sizingTop | sizingRight ) ) )
  559. cursor = mNESWCursor;
  560. else if ( mSizingMode == sizingLeft || mSizingMode == sizingRight )
  561. cursor = mLeftRightCursor;
  562. else if (mSizingMode == sizingTop || mSizingMode == sizingBottom )
  563. cursor = mUpDownCursor;
  564. else
  565. cursor = NULL;
  566. }
  567. else
  568. {
  569. // Check for current mouse position after checking for actual sizing mode
  570. if ( ( sizeMode == ( sizingBottom | sizingRight ) ) ||
  571. ( sizeMode == ( sizingTop | sizingLeft ) ) )
  572. cursor = mNWSECursor;
  573. else if ( ( sizeMode == ( sizingBottom | sizingLeft ) ) ||
  574. ( sizeMode == ( sizingTop | sizingRight ) ) )
  575. cursor = mNESWCursor;
  576. else if (sizeMode == sizingLeft || sizeMode == sizingRight )
  577. cursor = mLeftRightCursor;
  578. else if (sizeMode == sizingTop || sizeMode == sizingBottom )
  579. cursor = mUpDownCursor;
  580. else
  581. cursor = NULL;
  582. }
  583. }
  584. if( mMouseDownMode == MovingSelection && cursor == NULL )
  585. cursor = mMoveCursor;
  586. }
  587. void GuiEditCtrl::onTouchDown(const GuiEvent &event)
  588. {
  589. if (! mActive)
  590. {
  591. Parent::onTouchDown(event);
  592. return;
  593. }
  594. if(!mContentControl)
  595. return;
  596. setFirstResponder();
  597. //lock the mouse
  598. mouseLock();
  599. Point2I ctOffset;
  600. Point2I cext;
  601. GuiControl *ctrl;
  602. mLastMousePos = globalToLocalCoord(event.mousePoint);
  603. // first see if we hit a sizing knob on the currently selected control...
  604. if (mSelectedControls.size() == 1)
  605. {
  606. ctrl = mSelectedControls.first();
  607. cext = ctrl->getExtent();
  608. ctOffset = globalToLocalCoord(ctrl->localToGlobalCoord(Point2I(0,0)));
  609. RectI box(ctOffset.x,ctOffset.y,cext.x, cext.y);
  610. if ((mSizingMode = (GuiEditCtrl::sizingModes)getSizingHitKnobs(mLastMousePos, box)) != 0)
  611. {
  612. mMouseDownMode = SizingSelection;
  613. // undo
  614. Con::executef(this, 2, "onPreEdit", Con::getIntArg(getSelectedSet().getId()));
  615. return;
  616. }
  617. }
  618. if(!mCurrentAddSet)
  619. mCurrentAddSet = mContentControl;
  620. //find the control we clicked
  621. ctrl = mContentControl->findHitControl(mLastMousePos, mCurrentAddSet->mLayer);
  622. bool handledEvent = ctrl->onMouseDownEditor( event, localToGlobalCoord( Point2I(0,0) ) );
  623. if( handledEvent == true )
  624. {
  625. // The Control handled the event and requested the edit ctrl
  626. // *NOT* act on it. The dude abides.
  627. return;
  628. }
  629. else if ( selectionContains(ctrl) )
  630. {
  631. //if we're holding shift, de-select the clicked ctrl
  632. if (event.modifier & SI_SHIFT)
  633. {
  634. Vector<GuiControl *>::iterator i;
  635. for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  636. {
  637. if (*i == ctrl)
  638. {
  639. Con::executef(this, 2, "onRemoveSelected", Con::getIntArg(ctrl->getId()));
  640. mSelectedControls.erase(i);
  641. break;
  642. }
  643. }
  644. //set the mode
  645. mMouseDownMode = Selecting;
  646. }
  647. else //else we hit a ctrl we've already selected, so set the mode to moving
  648. {
  649. // For calculating mouse delta
  650. mDragBeginPoint = event.mousePoint;
  651. // Allocate enough space for our selected controls
  652. mDragBeginPoints.reserve( mSelectedControls.size() );
  653. // For snapping to origin
  654. Vector<GuiControl *>::iterator i;
  655. for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  656. mDragBeginPoints.push_back( (*i)->mBounds.point );
  657. // Set Mouse Mode
  658. mMouseDownMode = MovingSelection;
  659. // undo
  660. Con::executef(this, 2, "onPreEdit", Con::getIntArg(getSelectedSet().getId()));
  661. }
  662. }
  663. //else we clicked on an unselected control
  664. else
  665. {
  666. //if we clicked in the current add set
  667. if (ctrl == mCurrentAddSet)
  668. {
  669. // start dragging a rectangle
  670. // if the shift is not down, nuke prior selection
  671. if (!(event.modifier & SI_SHIFT)) {
  672. Con::executef(this, 1, "onClearSelected");
  673. mSelectedControls.clear();
  674. }
  675. mSelectionAnchor = mLastMousePos;
  676. mMouseDownMode = DragSelecting;
  677. }
  678. else
  679. {
  680. //find the new add set
  681. GuiControl *newAddSet = ctrl->getParent();
  682. //if we're holding shift and the ctrl is in the same add set
  683. if (event.modifier & SI_SHIFT && newAddSet == mCurrentAddSet)
  684. {
  685. //if (!(ctrl->isLocked())) {
  686. mSelectedControls.push_back(ctrl);
  687. Con::executef(this, 2, "onAddSelected", Con::getIntArg(ctrl->getId()));
  688. //}
  689. mMouseDownMode = Selecting;
  690. }
  691. else if (ctrl != mContentControl)
  692. {
  693. //find and set the new add set
  694. mCurrentAddSet = ctrl->getParent();
  695. //clear and set the selected controls
  696. Con::executef(this, 1, "onClearSelected");
  697. mSelectedControls.clear();
  698. //if (!(ctrl->isLocked())) {
  699. mSelectedControls.push_back(ctrl);
  700. Con::executef(this, 2, "onAddSelected", Con::getIntArg(ctrl->getId()));
  701. //}
  702. mMouseDownMode = Selecting;
  703. }
  704. else
  705. mMouseDownMode = Selecting;
  706. }
  707. }
  708. }
  709. void GuiEditCtrl::addSelection(S32 id)
  710. {
  711. GuiControl * ctrl;
  712. if(Sim::findObject(id, ctrl))
  713. mSelectedControls.push_back(ctrl);
  714. }
  715. void GuiEditCtrl::removeSelection(S32 id)
  716. {
  717. GuiControl * ctrl;
  718. if (Sim::findObject(id, ctrl)) {
  719. Vector<GuiControl *>::iterator i;
  720. for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  721. {
  722. if (*i == ctrl)
  723. {
  724. mSelectedControls.erase(i);
  725. break;
  726. }
  727. }
  728. }
  729. }
  730. void GuiEditCtrl::onTouchUp(const GuiEvent &event)
  731. {
  732. if (! mActive || !mContentControl || !mCurrentAddSet )
  733. {
  734. Parent::onTouchUp(event);
  735. return;
  736. }
  737. //find the control we clicked
  738. GuiControl *ctrl = mContentControl->findHitControl(mLastMousePos, mCurrentAddSet->mLayer);
  739. bool handledEvent = ctrl->onMouseUpEditor( event, localToGlobalCoord( Point2I(0,0) ) );
  740. if( handledEvent == true )
  741. {
  742. // The Control handled the event and requested the edit ctrl
  743. // *NOT* act on it. The dude abides.
  744. return;
  745. }
  746. //unlock the mouse
  747. mouseUnlock();
  748. // Reset Drag Axis Alignment Information
  749. mDragBeginPoint.set(-1,-1);
  750. mDragBeginPoints.clear();
  751. mLastMousePos = globalToLocalCoord(event.mousePoint);
  752. if (mMouseDownMode == DragSelecting)
  753. {
  754. RectI b;
  755. getDragRect(b);
  756. GuiControl::iterator i;
  757. for(i = mCurrentAddSet->begin(); i != mCurrentAddSet->end(); i++)
  758. {
  759. GuiControl *ctrl = dynamic_cast<GuiControl *>(*i);
  760. Point2I upperL = globalToLocalCoord(ctrl->localToGlobalCoord(Point2I(0,0)));
  761. Point2I lowerR = upperL + ctrl->mBounds.extent - Point2I(1, 1);
  762. if (b.pointInRect(upperL) && b.pointInRect(lowerR) && !selectionContains(ctrl)) {
  763. //if (!(ctrl->isLocked())) {
  764. mSelectedControls.push_back(ctrl);
  765. Con::executef(this, 2, "onAddSelected", Con::getIntArg(ctrl->getId()));
  766. //}
  767. }
  768. }
  769. }
  770. if (mSelectedControls.size() == 1)
  771. Con::executef(this, 2, "onSelect", Con::getIntArg(mSelectedControls[0]->getId()));
  772. // deliver post edit event if we've been editing
  773. // note: paxorr: this may need to be moved earlier, if the selection has changed.
  774. // undo
  775. if(mMouseDownMode == SizingSelection || mMouseDownMode == MovingSelection)
  776. Con::executef(this, 2, "onPostEdit", Con::getIntArg(getSelectedSet().getId()));
  777. //reset the mouse mode
  778. setFirstResponder();
  779. mMouseDownMode = Selecting;
  780. }
  781. void GuiEditCtrl::onTouchDragged(const GuiEvent &event)
  782. {
  783. if (! mActive || !mContentControl || !mCurrentAddSet)
  784. {
  785. Parent::onTouchDragged(event);
  786. return;
  787. }
  788. if(!mCurrentAddSet)
  789. mCurrentAddSet = mContentControl;
  790. Point2I mousePoint = globalToLocalCoord(event.mousePoint);
  791. //find the control we clicked
  792. GuiControl *ctrl = mContentControl->findHitControl(mousePoint, mCurrentAddSet->mLayer);
  793. bool handledEvent = ctrl->onMouseDraggedEditor( event, localToGlobalCoord( Point2I(0,0) ) );
  794. if( handledEvent == true )
  795. {
  796. // The Control handled the event and requested the edit ctrl
  797. // *NOT* act on it. The dude abides.
  798. return;
  799. }
  800. if (mMouseDownMode == SizingSelection)
  801. {
  802. if (mGridSnap.x)
  803. mousePoint.x -= mousePoint.x % mGridSnap.x;
  804. if (mGridSnap.y)
  805. mousePoint.y -= mousePoint.y % mGridSnap.y;
  806. GuiControl *ctrl = mSelectedControls.first();
  807. // can't resize a locked control
  808. if (ctrl && ctrl->isLocked())
  809. return;
  810. Point2I ctrlPoint = mCurrentAddSet->globalToLocalCoord(event.mousePoint);
  811. if (mGridSnap.x)
  812. ctrlPoint.x -= ctrlPoint.x % mGridSnap.x;
  813. if (mGridSnap.y)
  814. ctrlPoint.y -= ctrlPoint.y % mGridSnap.y;
  815. Point2I newPosition = ctrl->getPosition();
  816. Point2I newExtent = ctrl->getExtent();
  817. Point2I minExtent = ctrl->getMinExtent();
  818. if (mSizingMode & sizingLeft)
  819. {
  820. newPosition.x = ctrlPoint.x;
  821. newExtent.x = ctrl->mBounds.extent.x + ctrl->mBounds.point.x - ctrlPoint.x;
  822. if(newExtent.x < minExtent.x)
  823. {
  824. newPosition.x -= minExtent.x - newExtent.x;
  825. newExtent.x = minExtent.x;
  826. }
  827. }
  828. else if (mSizingMode & sizingRight)
  829. {
  830. newExtent.x = ctrlPoint.x - ctrl->mBounds.point.x;
  831. if(mGridSnap.x)
  832. newExtent.x -= newExtent.x % mGridSnap.x;
  833. if(newExtent.x < minExtent.x)
  834. newExtent.x = minExtent.x;
  835. }
  836. if (mSizingMode & sizingTop)
  837. {
  838. newPosition.y = ctrlPoint.y;
  839. newExtent.y = ctrl->mBounds.extent.y + ctrl->mBounds.point.y - ctrlPoint.y;
  840. if(newExtent.y < minExtent.y)
  841. {
  842. newPosition.y -= minExtent.y - newExtent.y;
  843. newExtent.y = minExtent.y;
  844. }
  845. }
  846. else if (mSizingMode & sizingBottom)
  847. {
  848. newExtent.y = ctrlPoint.y - ctrl->mBounds.point.y;
  849. if(newExtent.y < minExtent.y)
  850. newExtent.y = minExtent.y;
  851. }
  852. if(mGridSnap.x)
  853. {
  854. newPosition.x -= newPosition.x % mGridSnap.x;
  855. newExtent.x -= newExtent.x % mGridSnap.x;
  856. }
  857. if(mGridSnap.y)
  858. {
  859. newPosition.y -= newPosition.y % mGridSnap.y;
  860. newExtent.y -= newExtent.y % mGridSnap.y;
  861. }
  862. ctrl->resize(newPosition, newExtent);
  863. mCurrentAddSet->childResized(ctrl);
  864. Con::executef(this, 2, "onSelect", Con::getIntArg(mSelectedControls[0]->getId()));
  865. }
  866. else if (mMouseDownMode == MovingSelection && mSelectedControls.size())
  867. {
  868. Vector<GuiControl *>::iterator i = mSelectedControls.begin();
  869. //Point2I minPos = (*i)->mBounds.point;
  870. Point2I minPos (S32_MAX, S32_MAX);
  871. for(; i != mSelectedControls.end(); i++)
  872. {
  873. // skip locked controls
  874. if ((*i)->isLocked())
  875. continue;
  876. if ((*i)->mBounds.point.x < minPos.x)
  877. minPos.x = (*i)->mBounds.point.x;
  878. if ((*i)->mBounds.point.y < minPos.y)
  879. minPos.y = (*i)->mBounds.point.y;
  880. }
  881. Point2I delta = mousePoint - mLastMousePos;
  882. delta += minPos; // find new minPos;
  883. if (mGridSnap.x)
  884. delta.x -= delta.x % mGridSnap.x;
  885. if (mGridSnap.y)
  886. delta.y -= delta.y % mGridSnap.y;
  887. delta -= minPos;
  888. // Do we want to align this drag to the X and Y axes within a certain threshold?
  889. if( event.modifier & SI_SHIFT )
  890. {
  891. Point2I dragTotalDelta = event.mousePoint - mDragBeginPoint;
  892. if( dragTotalDelta.y < 10 && dragTotalDelta.y > -10 )
  893. {
  894. for(S32 i = 0; i < mSelectedControls.size(); i++)
  895. {
  896. // skip locked controls
  897. if (mSelectedControls[i]->isLocked())
  898. continue;
  899. Point2I snapBackPoint( mSelectedControls[i]->mBounds.point.x, mDragBeginPoints[i].y);
  900. // This is kind of nasty but we need to snap back if we're not at origin point with selection - JDD
  901. if( mSelectedControls[i]->mBounds.point.y != mDragBeginPoints[i].y )
  902. mSelectedControls[i]->resize( snapBackPoint, mSelectedControls[i]->mBounds.extent);
  903. }
  904. delta.y = 0;
  905. }
  906. if( dragTotalDelta.x < 10 && dragTotalDelta.x > -10 )
  907. {
  908. for(S32 i = 0; i < mSelectedControls.size(); i++)
  909. {
  910. // skip locked controls
  911. if (mSelectedControls[i]->isLocked())
  912. continue;
  913. Point2I snapBackPoint( mDragBeginPoints[i].x,mSelectedControls[i]->mBounds.point.y);
  914. // This is kind of nasty but we need to snap back if we're not at origin point with selection - JDD
  915. if( mSelectedControls[i]->mBounds.point.x != mDragBeginPoints[i].x )
  916. mSelectedControls[i]->resize( snapBackPoint, mSelectedControls[i]->mBounds.extent);
  917. }
  918. delta.x = 0;
  919. }
  920. }
  921. moveSelection(delta);
  922. // find the current control under the mouse but not in the selected set.
  923. // setting a control invisible makes sure it wont be seen by findHitControl()
  924. for(int i = 0; i< mSelectedControls.size(); i++)
  925. mSelectedControls[i]->setVisible(false);
  926. GuiControl *inCtrl = mContentControl->findHitControl(mousePoint, mCurrentAddSet->mLayer);
  927. for(int i = 0; i< mSelectedControls.size(); i++)
  928. mSelectedControls[i]->setVisible(true);
  929. // find the nearest control up the heirarchy from the control the mouse is in
  930. // that is flagged as a container.
  931. while(! inCtrl->mIsContainer)
  932. inCtrl = inCtrl->getParent();
  933. // if the control under the mouse is not our parent, move the selected controls
  934. // into the new parent.
  935. if(mSelectedControls[0]->getParent() != inCtrl && inCtrl->mIsContainer)
  936. {
  937. moveSelectionToCtrl(inCtrl);
  938. setCurrentAddSet(inCtrl,false);
  939. }
  940. mLastMousePos += delta;
  941. }
  942. else
  943. mLastMousePos = mousePoint;
  944. }
  945. void GuiEditCtrl::moveSelectionToCtrl(GuiControl *newParent)
  946. {
  947. for(int i = 0; i < mSelectedControls.size(); i++)
  948. {
  949. GuiControl* ctrl = mSelectedControls[i];
  950. if(ctrl->getParent() == newParent)
  951. continue;
  952. // skip locked controls
  953. if (ctrl->isLocked())
  954. continue;
  955. Point2I globalpos = ctrl->localToGlobalCoord(Point2I(0,0));
  956. newParent->addObject(ctrl);
  957. Point2I newpos = ctrl->globalToLocalCoord(globalpos) + ctrl->mBounds.point;
  958. ctrl->mBounds.set(newpos, ctrl->mBounds.extent);
  959. }
  960. Con::executef(this, 1, "onSelectionParentChange");
  961. }
  962. static Point2I snapPoint(Point2I point, Point2I delta, Point2I gridSnap)
  963. {
  964. S32 snap;
  965. if(gridSnap.x && delta.x)
  966. {
  967. snap = point.x % gridSnap.x;
  968. point.x -= snap;
  969. if(delta.x > 0 && snap != 0)
  970. point.x += gridSnap.x;
  971. }
  972. if(gridSnap.y && delta.y)
  973. {
  974. snap = point.y % gridSnap.y;
  975. point.y -= snap;
  976. if(delta.y > 0 && snap != 0)
  977. point.y += gridSnap.y;
  978. }
  979. return point;
  980. }
  981. //-----------------
  982. void GuiEditCtrl::moveAndSnapSelection(const Point2I &delta)
  983. {
  984. // move / nudge gets a special callback so that multiple small moves can be
  985. // coalesced into one large undo action.
  986. // undo
  987. Con::executef(this, 2, "onPreSelectionNudged", Con::getIntArg(getSelectedSet().getId()));
  988. Vector<GuiControl *>::iterator i;
  989. Point2I newPos;
  990. for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  991. {
  992. newPos = (*i)->mBounds.point + delta;
  993. newPos = snapPoint(newPos, delta, mGridSnap);
  994. (*i)->resize(newPos, (*i)->mBounds.extent);
  995. }
  996. // undo
  997. Con::executef(this, 2, "onPostSelectionNudged", Con::getIntArg(getSelectedSet().getId()));
  998. // allow script to update the inspector
  999. if (mSelectedControls.size() == 1)
  1000. Con::executef(this, 2, "onSelectionMoved", Con::getIntArg(mSelectedControls[0]->getId()));
  1001. }
  1002. void GuiEditCtrl::moveSelection(const Point2I &delta)
  1003. {
  1004. Vector<GuiControl *>::iterator i;
  1005. for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  1006. {
  1007. // skip locked controls
  1008. if ((*i)->isLocked())
  1009. continue;
  1010. (*i)->resize((*i)->mBounds.point + delta, (*i)->mBounds.extent);
  1011. }
  1012. // allow script to update the inspector
  1013. if (mSelectedControls.size() == 1)
  1014. Con::executef(this, 2, "onSelectionMoved", Con::getIntArg(mSelectedControls[0]->getId()));
  1015. }
  1016. void GuiEditCtrl::justifySelection(Justification j)
  1017. {
  1018. S32 minX, maxX;
  1019. S32 minY, maxY;
  1020. S32 extentX, extentY;
  1021. if (mSelectedControls.size() < 2)
  1022. return;
  1023. Vector<GuiControl *>::iterator i = mSelectedControls.begin();
  1024. minX = (*i)->mBounds.point.x;
  1025. maxX = minX + (*i)->mBounds.extent.x;
  1026. minY = (*i)->mBounds.point.y;
  1027. maxY = minY + (*i)->mBounds.extent.y;
  1028. extentX = (*i)->mBounds.extent.x;
  1029. extentY = (*i)->mBounds.extent.y;
  1030. i++;
  1031. for(;i != mSelectedControls.end(); i++)
  1032. {
  1033. minX = getMin(minX, (*i)->mBounds.point.x);
  1034. maxX = getMax(maxX, (*i)->mBounds.point.x + (*i)->mBounds.extent.x);
  1035. minY = getMin(minY, (*i)->mBounds.point.y);
  1036. maxY = getMax(maxY, (*i)->mBounds.point.y + (*i)->mBounds.extent.y);
  1037. extentX += (*i)->mBounds.extent.x;
  1038. extentY += (*i)->mBounds.extent.y;
  1039. }
  1040. S32 deltaX = maxX - minX;
  1041. S32 deltaY = maxY - minY;
  1042. switch(j)
  1043. {
  1044. case JUSTIFY_LEFT:
  1045. for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  1046. (*i)->resize(Point2I(minX, (*i)->mBounds.point.y), (*i)->mBounds.extent);
  1047. break;
  1048. case JUSTIFY_TOP:
  1049. for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  1050. (*i)->resize(Point2I((*i)->mBounds.point.x, minY), (*i)->mBounds.extent);
  1051. break;
  1052. case JUSTIFY_RIGHT:
  1053. for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  1054. (*i)->resize(Point2I(maxX - (*i)->mBounds.extent.x + 1, (*i)->mBounds.point.y), (*i)->mBounds.extent);
  1055. break;
  1056. case JUSTIFY_BOTTOM:
  1057. for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  1058. (*i)->resize(Point2I((*i)->mBounds.point.x, maxY - (*i)->mBounds.extent.y + 1), (*i)->mBounds.extent);
  1059. break;
  1060. case JUSTIFY_CENTER:
  1061. for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  1062. (*i)->resize(Point2I(minX + ((deltaX - (*i)->mBounds.extent.x) >> 1), (*i)->mBounds.point.y),
  1063. (*i)->mBounds.extent);
  1064. break;
  1065. case SPACING_VERTICAL:
  1066. {
  1067. Vector<GuiControl *> sortedList;
  1068. Vector<GuiControl *>::iterator k;
  1069. for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  1070. {
  1071. for(k = sortedList.begin(); k != sortedList.end(); k++)
  1072. {
  1073. if ((*i)->mBounds.point.y < (*k)->mBounds.point.y)
  1074. break;
  1075. }
  1076. sortedList.insert(k, *i);
  1077. }
  1078. S32 space = (deltaY - extentY) / (mSelectedControls.size() - 1);
  1079. S32 curY = minY;
  1080. for(k = sortedList.begin(); k != sortedList.end(); k++)
  1081. {
  1082. (*k)->resize(Point2I((*k)->mBounds.point.x, curY), (*k)->mBounds.extent);
  1083. curY += (*k)->mBounds.extent.y + space;
  1084. }
  1085. }
  1086. break;
  1087. case SPACING_HORIZONTAL:
  1088. {
  1089. Vector<GuiControl *> sortedList;
  1090. Vector<GuiControl *>::iterator k;
  1091. for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  1092. {
  1093. for(k = sortedList.begin(); k != sortedList.end(); k++)
  1094. {
  1095. if ((*i)->mBounds.point.x < (*k)->mBounds.point.x)
  1096. break;
  1097. }
  1098. sortedList.insert(k, *i);
  1099. }
  1100. S32 space = (deltaX - extentX) / (mSelectedControls.size() - 1);
  1101. S32 curX = minX;
  1102. for(k = sortedList.begin(); k != sortedList.end(); k++)
  1103. {
  1104. (*k)->resize(Point2I(curX, (*k)->mBounds.point.y), (*k)->mBounds.extent);
  1105. curX += (*k)->mBounds.extent.x + space;
  1106. }
  1107. }
  1108. break;
  1109. }
  1110. }
  1111. void GuiEditCtrl::deleteSelection(void)
  1112. {
  1113. // undo
  1114. Con::executef(this, 2, "onTrashSelection", Con::getIntArg(getSelectedSet().getId()));
  1115. Vector<GuiControl *>::iterator i;
  1116. for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  1117. {
  1118. mTrash.addObject(*i);
  1119. }
  1120. mSelectedControls.clear();
  1121. }
  1122. void GuiEditCtrl::loadSelection(const char* filename)
  1123. {
  1124. if (! mCurrentAddSet)
  1125. mCurrentAddSet = mContentControl;
  1126. Con::executef(2, "exec", filename);
  1127. SimSet *set;
  1128. if(!Sim::findObject("guiClipboard", set))
  1129. return;
  1130. if(set->size())
  1131. {
  1132. Con::executef(this, 1, "onClearSelected");
  1133. mSelectedControls.clear();
  1134. for(U32 i = 0; i < (U32)set->size(); i++)
  1135. {
  1136. GuiControl *ctrl = dynamic_cast<GuiControl *>((*set)[i]);
  1137. if(ctrl)
  1138. {
  1139. mCurrentAddSet->addObject(ctrl);
  1140. mSelectedControls.push_back(ctrl);
  1141. Con::executef(this, 2, "onAddSelected", Con::getIntArg(ctrl->getId()));
  1142. }
  1143. }
  1144. // Undo
  1145. Con::executef(this, 2, "onAddNewCtrlSet", Con::getIntArg(getSelectedSet().getId()));
  1146. }
  1147. set->deleteObject();
  1148. }
  1149. void GuiEditCtrl::saveSelection(const char* filename)
  1150. {
  1151. // if there are no selected objects, then don't save
  1152. if (mSelectedControls.size() == 0)
  1153. return;
  1154. FileStream stream;
  1155. if(!ResourceManager->openFileForWrite(stream, filename))
  1156. return;
  1157. SimSet *clipboardSet = new SimSet;
  1158. clipboardSet->registerObject();
  1159. Sim::getRootGroup()->addObject(clipboardSet, "guiClipboard");
  1160. Vector<GuiControl *>::iterator i;
  1161. for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  1162. clipboardSet->addObject(*i);
  1163. clipboardSet->write(stream, 0);
  1164. clipboardSet->deleteObject();
  1165. }
  1166. void GuiEditCtrl::selectAll()
  1167. {
  1168. GuiControl::iterator i;
  1169. if (!mCurrentAddSet)
  1170. return;
  1171. Con::executef(this, 1, "onClearSelected");
  1172. mSelectedControls.clear();
  1173. for(i = mCurrentAddSet->begin(); i != mCurrentAddSet->end(); i++)
  1174. {
  1175. GuiControl *ctrl = dynamic_cast<GuiControl *>(*i);
  1176. //if (!(ctrl->isLocked())) {
  1177. mSelectedControls.push_back(ctrl);
  1178. Con::executef(this, 2, "onAddSelected", Con::getIntArg(ctrl->getId()));
  1179. //}
  1180. }
  1181. }
  1182. void GuiEditCtrl::bringToFront()
  1183. {
  1184. // undo
  1185. if (mSelectedControls.size() != 1)
  1186. return;
  1187. GuiControl *ctrl = *(mSelectedControls.begin());
  1188. mCurrentAddSet->pushObjectToBack(ctrl);
  1189. }
  1190. void GuiEditCtrl::pushToBack()
  1191. {
  1192. // undo
  1193. if (mSelectedControls.size() != 1)
  1194. return;
  1195. GuiControl *ctrl = *(mSelectedControls.begin());
  1196. mCurrentAddSet->bringObjectToFront(ctrl);
  1197. }
  1198. bool GuiEditCtrl::onKeyDown(const GuiEvent &event)
  1199. {
  1200. if (! mActive)
  1201. return Parent::onKeyDown(event);
  1202. if (!(event.modifier & SI_CTRL))
  1203. {
  1204. switch(event.keyCode)
  1205. {
  1206. case KEY_BACKSPACE:
  1207. case KEY_DELETE:
  1208. deleteSelection();
  1209. Con::executef(this,1,"onDelete");
  1210. return true;
  1211. }
  1212. }
  1213. return false;
  1214. }
  1215. ConsoleMethod(GuiEditCtrl, setSnapToGrid, void, 3, 3, "(gridsize) Set the size of the snap-to grid.\n"
  1216. "@return No return value.")
  1217. {
  1218. U32 gridsize = dAtoi(argv[2]);
  1219. object->setSnapToGrid(gridsize);
  1220. }
  1221. void GuiEditCtrl::setSnapToGrid(U32 gridsize)
  1222. {
  1223. mGridSnap.set(gridsize, gridsize);
  1224. }
  1225. void GuiEditCtrl::controlInspectPreApply(GuiControl* object)
  1226. {
  1227. // undo
  1228. Con::executef(this, 2, "onControlInspectPreApply", Con::getIntArg(object->getId()));
  1229. }
  1230. void GuiEditCtrl::controlInspectPostApply(GuiControl* object)
  1231. {
  1232. // undo
  1233. Con::executef(this, 2, "onControlInspectPostApply", Con::getIntArg(object->getId()));
  1234. }
  1235. void GuiEditCtrl::updateSelectedSet()
  1236. {
  1237. mSelectedSet.clear();
  1238. Vector<GuiControl*>::iterator i;
  1239. for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
  1240. {
  1241. mSelectedSet.addObject(*i);
  1242. }
  1243. }
  1244. // -----------------------------------------------------------------------------
  1245. // GuiEditor Ruler
  1246. // -----------------------------------------------------------------------------
  1247. class GuiEditorRuler : public GuiControl {
  1248. StringTableEntry refCtrl;
  1249. typedef GuiControl Parent;
  1250. public:
  1251. void onPreRender()
  1252. {
  1253. setUpdate();
  1254. }
  1255. void onRender(Point2I offset, const RectI &updateRect)
  1256. {
  1257. dglDrawRectFill(updateRect, ColorF(1,1,1,1));
  1258. GuiScrollCtrl *ref;
  1259. SimObject *o = Sim::findObject(refCtrl);
  1260. //Sim::findObject(refCtrl, &ref);
  1261. ref = dynamic_cast<GuiScrollCtrl *>(o);
  1262. Point2I choffset(0,0);
  1263. //if(ref)
  1264. // choffset = ref->getChildPos();
  1265. if(mBounds.extent.x > mBounds.extent.y)
  1266. {
  1267. // it's horizontal.
  1268. for(U32 i = 0; i < (U32)mBounds.extent.x; i++)
  1269. {
  1270. S32 x = offset.x + i;
  1271. S32 pos = i - choffset.x;
  1272. if(!(pos % 10))
  1273. {
  1274. S32 start = 6;
  1275. if(!(pos %20))
  1276. start = 4;
  1277. if(!(pos % 100))
  1278. start = 1;
  1279. dglDrawLine(x, offset.y + start, x, offset.y + 10, ColorF(0,0,0,1));
  1280. }
  1281. }
  1282. }
  1283. else
  1284. {
  1285. // it's vertical.
  1286. for(U32 i = 0; i < (U32)mBounds.extent.y; i++)
  1287. {
  1288. S32 y = offset.y + i;
  1289. S32 pos = i - choffset.y;
  1290. if(!(pos % 10))
  1291. {
  1292. S32 start = 6;
  1293. if(!(pos %20))
  1294. start = 4;
  1295. if(!(pos % 100))
  1296. start = 1;
  1297. dglDrawLine(offset.x + start, y, offset.x + 10, y, ColorF(0,0,0,1));
  1298. }
  1299. }
  1300. }
  1301. }
  1302. static void initPersistFields()
  1303. {
  1304. Parent::initPersistFields();
  1305. addField("refCtrl", TypeString, Offset(refCtrl, GuiEditorRuler));
  1306. }
  1307. DECLARE_CONOBJECT(GuiEditorRuler);
  1308. };
  1309. IMPLEMENT_CONOBJECT(GuiEditorRuler);