1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2013 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "console/console.h"
- #include "console/consoleTypes.h"
- #include "graphics/dgl.h"
- #include "sim/simBase.h"
- #include "gui/guiCanvas.h"
- #include "gui/editor/guiEditCtrl.h"
- #include "platform/event.h"
- #include "io/fileStream.h"
- #include "gui/containers/guiScrollCtrl.h"
- IMPLEMENT_CONOBJECT(GuiEditCtrl);
- GuiEditCtrl::GuiEditCtrl() : mCurrentAddSet(NULL), mEditorRoot(NULL), mGridSnap(10, 10), mDragBeginPoint(-1, -1)
- {
- VECTOR_SET_ASSOCIATION(mSelectedControls);
- VECTOR_SET_ASSOCIATION(mDragBeginPoints);
- mActive = true;
- mDragBeginPoints.clear();
- mSelectedControls.clear();
- mUseGridSnap = true;
- mMouseLockedEditCtrl = nullptr;
- mDefaultCursor = NULL;
- mLeftRightCursor = NULL;
- mUpDownCursor = NULL;
- mNWSECursor = NULL;
- mNESWCursor = NULL;
- mMoveCursor = NULL;
- }
- bool GuiEditCtrl::onAdd()
- {
- if (!Parent::onAdd())
- return false;
- mTrash.registerObject();
- mSelectedSet.registerObject();
- mUndoManager.registerObject();
- return true;
- }
- void GuiEditCtrl::onRemove()
- {
- Parent::onRemove();
- mTrash.unregisterObject();
- mSelectedSet.unregisterObject();
- mUndoManager.unregisterObject();
- }
- ConsoleMethod(GuiEditCtrl, setRoot, void, 3, 3, "(GuiControl root) Sets the given control as root\n"
- "@return No return value.")
- {
- GuiControl* ctrl;
- if (!Sim::findObject(argv[2], ctrl))
- return;
- object->setRoot(ctrl);
- }
- ConsoleMethod(GuiEditCtrl, addNewCtrl, void, 3, 3, "(GuiControl ctrl) Adds the given control to the control list\n"
- "@return No return value.")
- {
- GuiControl* ctrl;
- if (!Sim::findObject(argv[2], ctrl))
- return;
- object->addNewControl(ctrl);
- }
- ConsoleMethod(GuiEditCtrl, addSelection, void, 3, 3, "(ctrlID) Adds the selected control.\n"
- "@return No return value.")
- {
- S32 id = dAtoi(argv[2]);
- object->addSelection(id);
- }
- ConsoleMethod(GuiEditCtrl, removeSelection, void, 3, 3, "(ctrlID) Removes the selected control from list.\n"
- "@return No return value.")
- {
- S32 id = dAtoi(argv[2]);
- object->removeSelection(id);
- }
- ConsoleMethod(GuiEditCtrl, clearSelection, void, 2, 2, "() Clear selected controls list.\n"
- "@return No return value.")
- {
- object->clearSelection();
- }
- ConsoleMethod(GuiEditCtrl, select, void, 3, 3, "(GuiControl ctrl) Finds and selects given object\n"
- "@return No return value.")
- {
- GuiControl* ctrl;
- if (!Sim::findObject(argv[2], ctrl))
- return;
- object->setSelection(ctrl);
- }
- ConsoleMethod(GuiEditCtrl, setCurrentAddSet, void, 3, 3, "(GuiControl ctrl) Set the current control set in which controls are added.\n"
- "@param ctrl The addset\n"
- "@return No return value.")
- {
- GuiControl* addSet;
- if (!Sim::findObject(argv[2], addSet))
- {
- Con::printf("%s(): Invalid control: %s", argv[0], argv[2]);
- return;
- }
- object->setCurrentAddSet(addSet);
- }
- ConsoleMethod(GuiEditCtrl, getCurrentAddSet, S32, 2, 2, "()\n @return Returns the set to which new controls will be added")
- {
- const GuiControl* add = object->getCurrentAddSet();
- return add ? add->getId() : 0;
- }
- ConsoleMethod(GuiEditCtrl, toggle, void, 2, 2, "() Toggle activation.\n"
- "@return No return value.")
- {
- object->setEditMode(!object->mActive);
- }
- ConsoleMethod(GuiEditCtrl, justify, void, 3, 3, "(int mode) Sets justification mode of selection\n"
- "@return No return value.")
- {
- object->justifySelection((GuiEditCtrl::Justification)dAtoi(argv[2]));
- }
- ConsoleMethod(GuiEditCtrl, bringToFront, void, 2, 2, "() Brings control to front\n"
- "@return No return value.")
- {
- object->bringToFront();
- }
- ConsoleMethod(GuiEditCtrl, pushToBack, void, 2, 2, "() Sends control to back\n"
- "@return No return value.")
- {
- object->pushToBack();
- }
- ConsoleMethod(GuiEditCtrl, deleteSelection, void, 2, 2, "Delete the selected text.\n"
- "@return No return value.")
- {
- object->deleteSelection();
- }
- ConsoleMethod(GuiEditCtrl, moveSelection, void, 4, 4, "(int deltax, int deltay) Moves selection to given (relative to current position) point\n"
- "@param deltax,deltay The change in coordinates.\n"
- "@return No return value.")
- {
- if (object->hasSnapToGrid())
- {
- object->moveAndSnapSelection(Point2I(dAtoi(argv[2]), dAtoi(argv[3])));
- }
- else
- {
- object->moveSelection(Point2I(dAtoi(argv[2]), dAtoi(argv[3])));
- }
- }
- ConsoleMethod(GuiEditCtrl, saveSelection, void, 3, 3, "(string fileName) Saves the current selection to given filename\n"
- "@return No return value.")
- {
- object->saveSelection(argv[2]);
- }
- ConsoleMethod(GuiEditCtrl, loadSelection, void, 3, 3, "(string fileName) Loads from given filename\n"
- "@return No return value.")
- {
- object->loadSelection(argv[2]);
- }
- ConsoleMethod(GuiEditCtrl, selectAll, void, 2, 2, "() Selects all controls\n"
- "@return No return value.")
- {
- object->selectAll();
- }
- ConsoleMethod(GuiEditCtrl, getSelected, S32, 2, 2, "() Gets the GUI control(s) the editor is currently selecting\n"
- "@return Returns the ID of the control.")
- {
- return object->getSelectedSet().getId();
- }
- ConsoleMethod(GuiEditCtrl, getTrash, S32, 2, 2, "() Gets the GUI controls(s) that are currently in the trash.\n"
- "@return Returns the ID of the control")
- {
- return object->getTrash().getId();
- }
- ConsoleMethod(GuiEditCtrl, getUndoManager, S32, 2, 2, "() Gets the Gui Editor's UndoManager object\n"
- "@return Returns the ID of the object.")
- {
- return object->getUndoManager().getId();
- }
- bool GuiEditCtrl::onWake()
- {
- if (!Parent::onWake())
- return false;
- // Set GUI Controls to DesignTime mode
- GuiControl::smDesignTime = true;
- GuiControl::smEditorHandle = this;
- setEditMode(true);
- return true;
- }
- void GuiEditCtrl::onSleep()
- {
- // Set GUI Controls to run time mode
- GuiControl::smDesignTime = false;
- GuiControl::smEditorHandle = NULL;
- Parent::onSleep();
- }
- void GuiEditCtrl::setRoot(GuiControl* root)
- {
- mEditorRoot = root;
- if (root != NULL) root->mIsContainer = true;
- mCurrentAddSet = mEditorRoot;
- Con::executef(this, 1, "onClearSelected");
- mSelectedControls.clear();
- }
- enum GuiEditConstants {
- GUI_BLACK = 0,
- GUI_WHITE = 255,
- NUT_SIZE = 4
- };
- // Sizing Cursors
- bool GuiEditCtrl::initCursors()
- {
- if (mMoveCursor == NULL || mUpDownCursor == NULL || mLeftRightCursor == NULL || mDefaultCursor == NULL || mNWSECursor == NULL || mNESWCursor == NULL)
- {
- SimObject* obj;
- obj = Sim::findObject("MoveCursor");
- mMoveCursor = dynamic_cast<GuiCursor*>(obj);
- obj = Sim::findObject("UpDownCursor");
- mUpDownCursor = dynamic_cast<GuiCursor*>(obj);
- obj = Sim::findObject("LeftRightCursor");
- mLeftRightCursor = dynamic_cast<GuiCursor*>(obj);
- obj = Sim::findObject("DefaultCursor");
- mDefaultCursor = dynamic_cast<GuiCursor*>(obj);
- obj = Sim::findObject("NESWCursor");
- mNESWCursor = dynamic_cast<GuiCursor*>(obj);
- obj = Sim::findObject("NWSECursor");
- mNWSECursor = dynamic_cast<GuiCursor*>(obj);
- obj = Sim::findObject("MoveCursor");
- mMoveCursor = dynamic_cast<GuiCursor*>(obj);
- return(mMoveCursor != NULL && mUpDownCursor != NULL && mLeftRightCursor != NULL && mDefaultCursor != NULL && mNWSECursor != NULL && mNESWCursor != NULL && mMoveCursor != NULL);
- }
- else
- return(true);
- }
- void GuiEditCtrl::setEditMode(bool value)
- {
- mActive = value;
- Con::executef(this, 1, "onClearSelected");
- mSelectedControls.clear();
- if (mActive && mAwake)
- mCurrentAddSet = mEditorRoot;
- }
- void GuiEditCtrl::setCurrentAddSet(GuiControl* ctrl, bool clearSelection)
- {
- if (ctrl != mCurrentAddSet)
- {
- if (clearSelection)
- {
- Con::executef(this, 1, "onClearSelected");
- mSelectedControls.clear();
- }
- mCurrentAddSet = ctrl;
- }
- }
- const GuiControl* GuiEditCtrl::getCurrentAddSet() const
- {
- return mCurrentAddSet ? mCurrentAddSet : mEditorRoot;
- }
- void GuiEditCtrl::clearSelection(void)
- {
- mSelectedControls.clear();
- if (isMethod("onClearSelected"))
- {
- Con::executef(this, 1, "onClearSelected");
- }
- }
- void GuiEditCtrl::setSelection(GuiControl* ctrl)
- {
- //sanity check
- if (!ctrl)
- return;
- if (mEditorRoot == ctrl)
- {
- mCurrentAddSet = ctrl;
- Con::executef(this, 1, "onClearSelected");
- mSelectedControls.clear();
- }
- else
- {
- // otherwise, we hit a new control...
- GuiControl* newAddSet = ctrl->getParent();
- //see if we should clear the old selection set
- if (newAddSet != mCurrentAddSet) {
- Con::executef(this, 1, "onClearSelected");
- mSelectedControls.clear();
- }
- //set the selection
- mCurrentAddSet = newAddSet;
- mSelectedControls.push_back(ctrl);
- Con::executef(this, 2, "onAddSelected", Con::getIntArg(ctrl->getId()));
- }
- }
- void GuiEditCtrl::addNewControl(GuiControl* ctrl)
- {
- if (!mCurrentAddSet)
- mCurrentAddSet = mEditorRoot;
- mCurrentAddSet->addObject(ctrl);
- Con::executef(this, 1, "onClearSelected");
- mSelectedControls.clear();
- //if (!(ctrl->isLocked())) {
- mSelectedControls.push_back(ctrl);
- Con::executef(this, 2, "onAddSelected", Con::getIntArg(ctrl->getId()));
- //}
- // undo
- Con::executef(this, 2, "onAddNewCtrl", Con::getIntArg(ctrl->getId()));
- }
- void GuiEditCtrl::drawNut(const Point2I& nut, ColorI& outlineColor, ColorI& nutColor)
- {
- RectI r(nut.x - NUT_SIZE, nut.y - NUT_SIZE, 2 * NUT_SIZE, 2 * NUT_SIZE);
- r.inset(1, 1);
- dglDrawRectFill(r, nutColor);
- r.inset(-1, -1);
- dglDrawRect(r, outlineColor);
- }
- static inline bool inNut(const Point2I& pt, S32 x, S32 y)
- {
- S32 dx = pt.x - x;
- S32 dy = pt.y - y;
- return dx <= NUT_SIZE && dx >= -NUT_SIZE && dy <= NUT_SIZE && dy >= -NUT_SIZE;
- }
- S32 GuiEditCtrl::getSizingHitKnobs(const Point2I& pt, const RectI& box)
- {
- S32 lx = box.point.x, rx = box.point.x + box.extent.x - 1;
- S32 cx = (lx + rx) >> 1;
- S32 ty = box.point.y, by = box.point.y + box.extent.y - 1;
- S32 cy = (ty + by) >> 1;
- // adjust nuts, so they dont straddle the controls
- lx -= NUT_SIZE;
- ty -= NUT_SIZE;
- rx += NUT_SIZE;
- by += NUT_SIZE;
- if (inNut(pt, lx, ty))
- return sizingLeft | sizingTop;
- if (inNut(pt, cx, ty))
- return sizingTop;
- if (inNut(pt, rx, ty))
- return sizingRight | sizingTop;
- if (inNut(pt, lx, by))
- return sizingLeft | sizingBottom;
- if (inNut(pt, cx, by))
- return sizingBottom;
- if (inNut(pt, rx, by))
- return sizingRight | sizingBottom;
- if (inNut(pt, lx, cy))
- return sizingLeft;
- if (inNut(pt, rx, cy))
- return sizingRight;
- return sizingNone;
- }
- void GuiEditCtrl::drawControlDecoration(GuiControl* ctrl, RectI& box, ColorI& outlineColor, ColorI& nutColor)
- {
- S32 lx = box.point.x, rx = box.point.x + box.extent.x - 1;
- S32 cx = (lx + rx) >> 1;
- S32 ty = box.point.y, by = box.point.y + box.extent.y - 1;
- S32 cy = (ty + by) >> 1;
- ColorI fillColor = mProfile->getFillColor(DisabledState);
- ColorI weakColor(fillColor.red, fillColor.green, fillColor.blue, 120);
- ColorI strongColor(fillColor.red, fillColor.green, fillColor.blue, 200);
- ColorI strongestColor(fillColor.red, fillColor.green, fillColor.blue, 255);
- drawTargetLines(lx, ty, weakColor, by, rx, strongColor);
-
- if (ctrl->isHidden())
- {
- box.inset(-1, -1);
- drawDashedLine(10, lx, ty, rx, ty, strongestColor);
- drawDashedLine(10, lx, ty, lx, by, strongestColor);
- drawDashedLine(10, rx, ty, rx, by, strongestColor);
- drawDashedLine(10, lx, by, rx, by, strongestColor);
- if (ctrl->isLocked())
- {
- box.inset(-1, -1);
- dglDrawRect(box, outlineColor);
- }
- }
- else if (ctrl->isLocked())
- {
- box.inset(-1, -1);
- dglDrawRect(box, strongestColor);
- box.inset(-1,-1);
- dglDrawRect(box, outlineColor);
- }
- else
- {
- drawNuts(lx, ty, rx, by, outlineColor, nutColor, cy, cx);
- }
- }
- void GuiEditCtrl::drawDashedLine(const F32& dashLength, const S32& x1, const S32& y1, const S32& x2, const S32& y2, ColorI& color)
- {
- F32 dx = x2 - x1;
- F32 dy = y2 - y1;
- F32 lineLength = mSqrt(dx * dx + dy * dy);
- S32 numSegments = mCeil(lineLength / dashLength);
- F32 unitX = dx / lineLength;
- F32 unitY = dy / lineLength;
- for (int i = 0; i < numSegments; i++)
- {
- F32 startX = x1 + (i * dashLength * unitX);
- F32 startY = y1 + (i * dashLength * unitY);
- F32 remainingLength = lineLength - (i * dashLength);
- F32 currentDashLength = getMin((dashLength), remainingLength);
- F32 endX = startX + (currentDashLength * unitX);
- F32 endY = startY + (currentDashLength * unitY);
- if (i % 2 == 0) {
- dglDrawLine(startX, startY, endX, endY, color);
- }
- }
- }
- void GuiEditCtrl::drawTargetLines(const S32& lx, const S32& ty, ColorI& weakColor, const S32& by, const S32& rx, ColorI& strongColor)
- {
- if (lx > 0 && ty > 0)
- {
- dglDrawLine(0, ty, lx, ty, weakColor);
- dglDrawLine(lx, 0, lx, ty, weakColor);
- }
- if (lx > 0 && by > 0)
- dglDrawLine(0, by, lx, by, weakColor);
- if (rx > 0 && ty > 0)
- dglDrawLine(rx, 0, rx, ty, weakColor);
- Point2I extent = localToGlobalCoord(mBounds.extent);
- if (lx < extent.x && by < extent.y)
- dglDrawLine(lx, by, lx, extent.y, strongColor);
- if (rx < extent.x && by < extent.y)
- {
- dglDrawLine(rx, by, rx, extent.y, strongColor);
- dglDrawLine(rx, by, extent.x, by, strongColor);
- }
- if (rx < extent.x && ty < extent.y)
- dglDrawLine(rx, ty, extent.x, ty, strongColor);
- }
- void GuiEditCtrl::drawNuts(S32& lx, S32& ty, S32& rx, S32& by, ColorI& outlineColor, ColorI& nutColor, const S32& cy, const S32& cx)
- {
- // adjust nuts, so they dont straddle the controls
- lx -= NUT_SIZE;
- ty -= NUT_SIZE;
- rx += NUT_SIZE;
- by += NUT_SIZE;
- drawNut(Point2I(lx, ty), outlineColor, nutColor);
- drawNut(Point2I(lx, cy), outlineColor, nutColor);
- drawNut(Point2I(lx, by), outlineColor, nutColor);
- drawNut(Point2I(rx, ty), outlineColor, nutColor);
- drawNut(Point2I(rx, cy), outlineColor, nutColor);
- drawNut(Point2I(rx, by), outlineColor, nutColor);
- drawNut(Point2I(cx, ty), outlineColor, nutColor);
- drawNut(Point2I(cx, by), outlineColor, nutColor);
- }
- void GuiEditCtrl::getDragRect(RectI& box)
- {
- box.point.x = getMin(mLastMousePos.x, mSelectionAnchor.x);
- box.extent.x = getMax(mLastMousePos.x, mSelectionAnchor.x) - box.point.x + 1;
- box.point.y = getMin(mLastMousePos.y, mSelectionAnchor.y);
- box.extent.y = getMax(mLastMousePos.y, mSelectionAnchor.y) - box.point.y + 1;
- }
- void GuiEditCtrl::onPreRender()
- {
- setUpdate();
- }
- void GuiEditCtrl::onRender(Point2I offset, const RectI& updateRect)
- {
- Point2I ctOffset;
- Point2I cext;
- bool keyFocused = isFirstResponder();
- if (mActive)
- {
- if (mCurrentAddSet)
- {
- // draw a white frame inset around the current add set.
- cext = mCurrentAddSet->getExtent();
- ctOffset = mCurrentAddSet->localToGlobalCoord(Point2I(0, 0));
- RectI box(ctOffset.x, ctOffset.y, cext.x, cext.y);
- ColorI fillColor = mProfile->getFillColor(DisabledState);
- bool isRoot = (getCurrentAddSet() == mEditorRoot);
- S32 d = isRoot ? 1 : -1;
- if (!isRoot)
- {
- box.inset(d, d);
- }
- dglDrawRect(box, ColorI(fillColor.red, fillColor.green, fillColor.blue, 200));
- box.inset(d, d);
- dglDrawRect(box, ColorI(fillColor.red, fillColor.green, fillColor.blue, 180));
- box.inset(d, d);
- dglDrawRect(box, ColorI(fillColor.red, fillColor.green, fillColor.blue, 160));
- box.inset(d, d);
- dglDrawRect(box, ColorI(fillColor.red, fillColor.green, fillColor.blue, 140));
- box.inset(d, d);
- dglDrawRect(box, ColorI(fillColor.red, fillColor.green, fillColor.blue, 120));
- }
- Vector<GuiControl*>::iterator i;
- bool multisel = mSelectedControls.size() > 1;
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- {
- GuiControl* ctrl = (*i);
- cext = ctrl->getExtent();
- ctOffset = ctrl->localToGlobalCoord(Point2I(0, 0));
- RectI box(ctOffset.x, ctOffset.y, cext.x, cext.y);
- auto border = mProfile->getTopBorder();
- ColorI nutColor = multisel ? mProfile->getFillColor(HighlightState) : mProfile->getFillColor(NormalState);
- ColorI outlineColor = multisel ? border->getBorderColor(HighlightState) : border->getBorderColor(NormalState);
- if (keyFocused)
- {
- nutColor = mProfile->getFillColor(SelectedState);
- outlineColor = border->getBorderColor(SelectedState);
- }
- drawControlDecoration(ctrl, box, outlineColor, nutColor);
- }
- if (mMouseDownMode == DragSelecting)
- {
- RectI b;
- getDragRect(b);
- b.point += offset;
- ColorI fillColor = mProfile->getFillColor(DisabledState);
- dglDrawRect(b, fillColor);
- }
- }
- RectI contentRect = RectI(offset, mBounds.extent);
- renderChildControls(offset, contentRect, updateRect);
- if (mActive && mCurrentAddSet && mUseGridSnap &&
- (mMouseDownMode == MovingSelection || mMouseDownMode == SizingSelection))
- {
- Point2I cext = mCurrentAddSet->getExtent();
- Point2I coff = mCurrentAddSet->localToGlobalCoord(Point2I(0, 0));
- // create point-dots
- Point2I snap = mGridSnap;
- if (snap.x < 6)
- snap *= 2;
- if (snap.x < 6)
- snap *= 2;
- U32 maxdot = (cext.x / snap.x) * (cext.y / snap.y);
- Point2F* dots = new Point2F[maxdot];
- U32 ndot = 0;
- for (U32 ix = (U32)snap.x; ix < (U32)cext.x; ix += snap.x)
- {
- for (U32 iy = snap.y; iy < (U32)cext.y; iy += snap.y)
- {
- dots[ndot].x = (F32)(ix + coff.x);
- dots[ndot++].y = (F32)(iy + coff.y);
- }
- }
- AssertFatal(ndot <= maxdot, "dot overflow");
- // draw the points.
- ColorI fillColor = mProfile->getFillColor(DisabledState);
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glVertexPointer(2, GL_FLOAT, 0, dots);
- glColor4ub(fillColor.red, fillColor.green, fillColor.blue, 200);
- glDrawArrays(GL_POINTS, 0, ndot);
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisable(GL_BLEND);
- delete[] dots;
- }
- }
- bool GuiEditCtrl::selectionContains(GuiControl* ctrl)
- {
- Vector<GuiControl*>::iterator i;
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- if (ctrl == *i) return true;
- return false;
- }
- void GuiEditCtrl::onRightMouseDown(const GuiEvent& event)
- {
- if (!mActive || !mEditorRoot)
- {
- Parent::onRightMouseDown(event);
- return;
- }
- setFirstResponder();
- //search for the control hit in any layer below the edit layer
- GuiControl* hitCtrl = mEditorRoot->findHitControl(globalToLocalCoord(event.mousePoint), mLayer - 1, true, true);
- if (hitCtrl != mCurrentAddSet)
- {
- Con::executef(this, 1, "onClearSelected");
- mSelectedControls.clear();
- mCurrentAddSet = hitCtrl;
- }
- // select the parent if we right-click on the current add set
- else if (mCurrentAddSet != mEditorRoot)
- {
- mCurrentAddSet = hitCtrl->getParent();
- select(hitCtrl);
- }
- //Design time mouse events
- GuiEvent designEvent = event;
- designEvent.mousePoint = mLastMousePos;
- Point2I localOffset = localToGlobalCoord(Point2I(0, 0));
- hitCtrl->onRightMouseDownEditor(designEvent, localOffset);
- }
- void GuiEditCtrl::select(GuiControl* ctrl)
- {
- Con::executef(this, 1, "onClearSelected");
- mSelectedControls.clear();
- if (ctrl != mEditorRoot) {
- //if (!(ctrl->isLocked())) {
- mSelectedControls.push_back(ctrl);
- Con::executef(this, 2, "onAddSelected", Con::getIntArg(ctrl->getId()));
- //}
- }
- else
- mCurrentAddSet = mEditorRoot;
- }
- void GuiEditCtrl::getCursor(GuiCursor*& cursor, bool& showCursor, const GuiEvent& lastGuiEvent)
- {
- showCursor = true;
- Point2I ctOffset;
- Point2I cext;
- GuiControl* ctrl;
- Point2I mousePos = globalToLocalCoord(lastGuiEvent.mousePoint);
- // first see if we hit a sizing knob on the currently selected control...
- if (mSelectedControls.size() == 1 && initCursors() == true)
- {
- ctrl = mSelectedControls.first();
- cext = ctrl->getExtent();
- ctOffset = globalToLocalCoord(ctrl->localToGlobalCoord(Point2I(0, 0)));
- RectI box(ctOffset.x, ctOffset.y, cext.x, cext.y);
- GuiEditCtrl::sizingModes sizeMode = (GuiEditCtrl::sizingModes)getSizingHitKnobs(mousePos, box);
- if (mMouseDownMode == SizingSelection)
- {
- if ((mSizingMode == (sizingBottom | sizingRight)) || (mSizingMode == (sizingTop | sizingLeft)))
- cursor = mNWSECursor;
- else if ((mSizingMode == (sizingBottom | sizingLeft)) || (mSizingMode == (sizingTop | sizingRight)))
- cursor = mNESWCursor;
- else if (mSizingMode == sizingLeft || mSizingMode == sizingRight)
- cursor = mLeftRightCursor;
- else if (mSizingMode == sizingTop || mSizingMode == sizingBottom)
- cursor = mUpDownCursor;
- else
- cursor = NULL;
- }
- else
- {
- // Check for current mouse position after checking for actual sizing mode
- if ((sizeMode == (sizingBottom | sizingRight)) ||
- (sizeMode == (sizingTop | sizingLeft)))
- cursor = mNWSECursor;
- else if ((sizeMode == (sizingBottom | sizingLeft)) ||
- (sizeMode == (sizingTop | sizingRight)))
- cursor = mNESWCursor;
- else if (sizeMode == sizingLeft || sizeMode == sizingRight)
- cursor = mLeftRightCursor;
- else if (sizeMode == sizingTop || sizeMode == sizingBottom)
- cursor = mUpDownCursor;
- else
- cursor = NULL;
- }
- }
- if (mMouseDownMode == MovingSelection && cursor == NULL)
- cursor = mMoveCursor;
- }
- void GuiEditCtrl::onTouchDown(const GuiEvent& event)
- {
- if (!mActive)
- {
- Parent::onTouchDown(event);
- return;
- }
- if (!mEditorRoot)
- return;
- setFirstResponder();
- //lock the mouse
- mouseLock();
- Point2I ctOffset;
- Point2I cext;
- GuiControl* ctrl;
- mLastMousePos = globalToLocalCoord(event.mousePoint);
- // first see if we hit a sizing knob on the currently selected control...
- if (mSelectedControls.size() == 1)
- {
- ctrl = mSelectedControls.first();
- cext = ctrl->getExtent();
- ctOffset = globalToLocalCoord(ctrl->localToGlobalCoord(Point2I(0, 0)));
- RectI box(ctOffset.x, ctOffset.y, cext.x, cext.y);
- if ((mSizingMode = (GuiEditCtrl::sizingModes)getSizingHitKnobs(mLastMousePos, box)) != 0)
- {
- mMouseDownMode = SizingSelection;
- // undo
- Con::executef(this, 2, "onPreEdit", Con::getIntArg(getSelectedSet().getId()));
- return;
- }
- }
- if (!mCurrentAddSet)
- mCurrentAddSet = mEditorRoot;
- bool handledEvent = false;
- Point2I editorOffset = localToGlobalCoord(Point2I(0, 0));
- if (mMouseLockedEditCtrl)
- {
- handledEvent = mMouseLockedEditCtrl->onMouseDownEditor(event, editorOffset);
- }
- else
- {
- //find the control we clicked
- ctrl = mEditorRoot->findHitControl(mLastMousePos, mCurrentAddSet->mLayer, true, true);
- handledEvent = ctrl->onMouseDownEditor(event, editorOffset);
- }
- if (handledEvent)
- {
- // The Control handled the event and requested the edit ctrl
- // *NOT* act on it. The dude abides.
- return;
- }
- else if (selectionContains(ctrl))
- {
- //if we're holding shift, de-select the clicked ctrl
- if (event.modifier & SI_SHIFT)
- {
- Vector<GuiControl*>::iterator i;
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- {
- if (*i == ctrl)
- {
- Con::executef(this, 2, "onRemoveSelected", Con::getIntArg(ctrl->getId()));
- mSelectedControls.erase(i);
- break;
- }
- }
- //set the mode
- mMouseDownMode = Selecting;
- }
- else //else we hit a ctrl we've already selected, so set the mode to moving
- {
- // For calculating mouse delta
- mDragBeginPoint = event.mousePoint;
- // Allocate enough space for our selected controls
- mDragBeginPoints.reserve(mSelectedControls.size());
- // For snapping to origin
- Vector<GuiControl*>::iterator i;
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- mDragBeginPoints.push_back((*i)->mBounds.point);
- // Set Mouse Mode
- mMouseDownMode = MovingSelection;
- // undo
- Con::executef(this, 2, "onPreEdit", Con::getIntArg(getSelectedSet().getId()));
- }
- }
- else //else we clicked on an unselected control
- {
- //if we clicked in the current add set
- if (ctrl == mCurrentAddSet)
- {
- // start dragging a rectangle
- // if the shift is not down, nuke prior selection
- if (!(event.modifier & SI_SHIFT)) {
- Con::executef(this, 1, "onClearSelected");
- mSelectedControls.clear();
- }
- mSelectionAnchor = mLastMousePos;
- mMouseDownMode = DragSelecting;
- }
- else
- {
- //find the new add set
- GuiControl* newAddSet = ctrl->getParent();
- //if we're holding shift and the ctrl is in the same add set
- if (event.modifier & SI_SHIFT && newAddSet == mCurrentAddSet)
- {
- mSelectedControls.push_back(ctrl);
- Con::executef(this, 2, "onAddSelected", Con::getIntArg(ctrl->getId()));
- mMouseDownMode = Selecting;
- }
- else if (ctrl != mEditorRoot)
- {
- //find and set the new add set
- mCurrentAddSet = newAddSet;
- //clear and set the selected controls
- Con::executef(this, 1, "onClearSelected");
- mSelectedControls.clear();
- mSelectedControls.push_back(ctrl);
- Con::executef(this, 2, "onAddSelected", Con::getIntArg(ctrl->getId()));
- mMouseDownMode = Selecting;
- }
- else
- mMouseDownMode = Selecting;
- }
- }
- }
- void GuiEditCtrl::addSelection(S32 id)
- {
- GuiControl* ctrl;
- if (Sim::findObject(id, ctrl))
- mSelectedControls.push_back(ctrl);
- }
- void GuiEditCtrl::removeSelection(S32 id)
- {
- GuiControl* ctrl;
- if (Sim::findObject(id, ctrl)) {
- Vector<GuiControl*>::iterator i;
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- {
- if (*i == ctrl)
- {
- mSelectedControls.erase(i);
- break;
- }
- }
- }
- }
- void GuiEditCtrl::onTouchUp(const GuiEvent& event)
- {
- if (!mActive || !mEditorRoot || !mCurrentAddSet)
- {
- Parent::onTouchUp(event);
- return;
- }
- //find the control we clicked
- GuiControl* ctrl = mEditorRoot->findHitControl(mLastMousePos, mCurrentAddSet->mLayer, true, true);
- Point2I localOffset = localToGlobalCoord(Point2I(0, 0));
- bool handledEvent = false;
- if (mMouseLockedEditCtrl)
- {
- handledEvent = mMouseLockedEditCtrl->onMouseUpEditor(event, localOffset);
- }
- else
- {
- handledEvent = ctrl->onMouseUpEditor(event, localOffset);
- }
- if (handledEvent == true)
- {
- // The Control handled the event and requested the edit ctrl
- // *NOT* act on it. The dude abides.
- return;
- }
- //unlock the mouse
- mouseUnlock();
- editMouseUnlock();
- // Reset Drag Axis Alignment Information
- mDragBeginPoint.set(-1, -1);
- mDragBeginPoints.clear();
- mLastMousePos = globalToLocalCoord(event.mousePoint);
- if (mMouseDownMode == DragSelecting)
- {
- RectI b;
- getDragRect(b);
- GuiControl::iterator i;
- for (i = mCurrentAddSet->begin(); i != mCurrentAddSet->end(); i++)
- {
- GuiControl* ctrl = dynamic_cast<GuiControl*>(*i);
- Point2I upperL = globalToLocalCoord(ctrl->localToGlobalCoord(Point2I(0, 0)));
- Point2I lowerR = upperL + ctrl->mBounds.extent - Point2I(1, 1);
- if (b.pointInRect(upperL) && b.pointInRect(lowerR) && !selectionContains(ctrl)) {
- mSelectedControls.push_back(ctrl);
- Con::executef(this, 2, "onAddSelected", Con::getIntArg(ctrl->getId()));
- }
- }
- }
- if (isMethod("onEdit") && mSelectedControls.size() > 0)
- {
- Con::executef(this, 2, "onEdit", Con::getIntArg(mSelectedControls[0]->getId()));
- }
- // deliver post edit event if we've been editing
- // note: paxorr: this may need to be moved earlier, if the selection has changed.
- // undo
- if (mMouseDownMode == SizingSelection || mMouseDownMode == MovingSelection)
- Con::executef(this, 2, "onPostEdit", Con::getIntArg(getSelectedSet().getId()));
- //reset the mouse mode
- setFirstResponder();
- mMouseDownMode = Selecting;
- }
- void GuiEditCtrl::onTouchDragged(const GuiEvent& event)
- {
- if (!mActive || !mEditorRoot || !mCurrentAddSet)
- {
- Parent::onTouchDragged(event);
- return;
- }
- if (!mCurrentAddSet)
- mCurrentAddSet = mEditorRoot;
- Point2I mousePoint = globalToLocalCoord(event.mousePoint);
- Point2I localOffset = localToGlobalCoord(Point2I(0, 0));
- bool handledEvent = false;
- if (mMouseLockedEditCtrl)
- {
- handledEvent = mMouseLockedEditCtrl->onMouseDraggedEditor(event, localOffset);
- }
- else
- {
- GuiControl* ctrl = mEditorRoot->findHitControl(mousePoint, mCurrentAddSet->mLayer, true, true);
- handledEvent = ctrl->onMouseDraggedEditor(event, localOffset);
- }
- if (handledEvent)
- {
- // The Control handled the event and requested the edit ctrl
- // *NOT* act on it. The dude abides.
- return;
- }
- if (mMouseDownMode == SizingSelection)
- {
- if (mGridSnap.x)
- mousePoint.x -= mousePoint.x % mGridSnap.x;
- if (mGridSnap.y)
- mousePoint.y -= mousePoint.y % mGridSnap.y;
- GuiControl* ctrl = mSelectedControls.first();
- // can't resize a locked control
- if (ctrl && ctrl->isLocked())
- return;
- Point2I ctrlPoint = mCurrentAddSet->globalToLocalCoord(event.mousePoint);
- if (mGridSnap.x)
- ctrlPoint.x -= ctrlPoint.x % mGridSnap.x;
- if (mGridSnap.y)
- ctrlPoint.y -= ctrlPoint.y % mGridSnap.y;
- Point2I newPosition = ctrl->getPosition();
- Point2I newExtent = ctrl->getExtent();
- Point2I minExtent = ctrl->getMinExtent();
- if (mSizingMode & sizingLeft)
- {
- newPosition.x = ctrlPoint.x;
- newExtent.x = ctrl->mBounds.extent.x + ctrl->mBounds.point.x - ctrlPoint.x;
- if (newExtent.x < minExtent.x)
- {
- newPosition.x -= minExtent.x - newExtent.x;
- newExtent.x = minExtent.x;
- }
- }
- else if (mSizingMode & sizingRight)
- {
- newExtent.x = ctrlPoint.x - ctrl->mBounds.point.x;
- if (mGridSnap.x)
- newExtent.x -= newExtent.x % mGridSnap.x;
- if (newExtent.x < minExtent.x)
- newExtent.x = minExtent.x;
- }
- if (mSizingMode & sizingTop)
- {
- newPosition.y = ctrlPoint.y;
- newExtent.y = ctrl->mBounds.extent.y + ctrl->mBounds.point.y - ctrlPoint.y;
- if (newExtent.y < minExtent.y)
- {
- newPosition.y -= minExtent.y - newExtent.y;
- newExtent.y = minExtent.y;
- }
- }
- else if (mSizingMode & sizingBottom)
- {
- newExtent.y = ctrlPoint.y - ctrl->mBounds.point.y;
- if (newExtent.y < minExtent.y)
- newExtent.y = minExtent.y;
- }
- if (mGridSnap.x)
- {
- newPosition.x -= newPosition.x % mGridSnap.x;
- newExtent.x -= newExtent.x % mGridSnap.x;
- }
- if (mGridSnap.y)
- {
- newPosition.y -= newPosition.y % mGridSnap.y;
- newExtent.y -= newExtent.y % mGridSnap.y;
- }
- ctrl->resize(newPosition, newExtent);
- }
- else if (mMouseDownMode == MovingSelection && mSelectedControls.size())
- {
- Vector<GuiControl*>::iterator i = mSelectedControls.begin();
- //Point2I minPos = (*i)->mBounds.point;
- Point2I minPos(S32_MAX, S32_MAX);
- for (; i != mSelectedControls.end(); i++)
- {
- // skip locked controls
- if ((*i)->isLocked())
- continue;
- if ((*i)->mBounds.point.x < minPos.x)
- minPos.x = (*i)->mBounds.point.x;
- if ((*i)->mBounds.point.y < minPos.y)
- minPos.y = (*i)->mBounds.point.y;
- }
- Point2I delta = mousePoint - mLastMousePos;
- delta += minPos; // find new minPos;
- if (mGridSnap.x)
- delta.x -= delta.x % mGridSnap.x;
- if (mGridSnap.y)
- delta.y -= delta.y % mGridSnap.y;
- delta -= minPos;
- // Do we want to align this drag to the X and Y axes within a certain threshold?
- if (event.modifier & SI_SHIFT)
- {
- Point2I dragTotalDelta = event.mousePoint - mDragBeginPoint;
- if (dragTotalDelta.y < 10 && dragTotalDelta.y > -10)
- {
- for (S32 i = 0; i < mSelectedControls.size(); i++)
- {
- // skip locked controls
- if (mSelectedControls[i]->isLocked())
- continue;
- Point2I snapBackPoint(mSelectedControls[i]->mBounds.point.x, mDragBeginPoints[i].y);
- // This is kind of nasty but we need to snap back if we're not at origin point with selection - JDD
- if (mSelectedControls[i]->mBounds.point.y != mDragBeginPoints[i].y)
- mSelectedControls[i]->resize(snapBackPoint, mSelectedControls[i]->mBounds.extent);
- }
- delta.y = 0;
- }
- if (dragTotalDelta.x < 10 && dragTotalDelta.x > -10)
- {
- for (S32 i = 0; i < mSelectedControls.size(); i++)
- {
- // skip locked controls
- if (mSelectedControls[i]->isLocked())
- continue;
- Point2I snapBackPoint(mDragBeginPoints[i].x, mSelectedControls[i]->mBounds.point.y);
- // This is kind of nasty but we need to snap back if we're not at origin point with selection - JDD
- if (mSelectedControls[i]->mBounds.point.x != mDragBeginPoints[i].x)
- mSelectedControls[i]->resize(snapBackPoint, mSelectedControls[i]->mBounds.extent);
- }
- delta.x = 0;
- }
- }
- moveSelection(delta);
- // find the current control under the mouse but not in the selected set.
- GuiControl* inCtrl = mEditorRoot->findHitControl(mousePoint, mCurrentAddSet->mLayer, true, false);
- // find the nearest control up the heirarchy from the control the mouse is in
- // that is flagged as a container.
- while (!inCtrl->mIsContainer)
- inCtrl = inCtrl->getParent();
- // if the control under the mouse is not our parent, move the selected controls
- // into the new parent.
- if (mSelectedControls[0]->getParent() != inCtrl && inCtrl->mIsContainer)
- {
- moveSelectionToCtrl(inCtrl);
- setCurrentAddSet(inCtrl, false);
- }
- mLastMousePos += delta;
- }
- else
- {
- mLastMousePos = mousePoint;
- }
- if (isMethod("onEdit") && mSelectedControls.size() > 0)
- {
- Con::executef(this, 2, "onEdit", Con::getIntArg(mSelectedControls[0]->getId()));
- }
- }
- void GuiEditCtrl::moveSelectionToCtrl(GuiControl* newParent)
- {
- for (int i = 0; i < mSelectedControls.size(); i++)
- {
- GuiControl* ctrl = mSelectedControls[i];
- if (ctrl->getParent() == newParent)
- continue;
- // skip locked controls
- if (ctrl->isLocked())
- continue;
- Point2I globalpos = ctrl->localToGlobalCoord(Point2I(0, 0));
- newParent->addObject(ctrl);
- Point2I newpos = ctrl->globalToLocalCoord(globalpos) + ctrl->mBounds.point;
- ctrl->mBounds.set(newpos, ctrl->mBounds.extent);
- }
- Con::executef(this, 2, "onSelectionParentChange", Con::getIntArg(newParent->getId()));
- }
- static Point2I snapPoint(Point2I point, Point2I delta, Point2I gridSnap)
- {
- S32 snap;
- if (gridSnap.x && delta.x)
- {
- snap = point.x % gridSnap.x;
- point.x -= snap;
- if (delta.x > 0 && snap != 0)
- point.x += gridSnap.x;
- }
- if (gridSnap.y && delta.y)
- {
- snap = point.y % gridSnap.y;
- point.y -= snap;
- if (delta.y > 0 && snap != 0)
- point.y += gridSnap.y;
- }
- return point;
- }
- //-----------------
- void GuiEditCtrl::moveAndSnapSelection(const Point2I& delta)
- {
- // move / nudge gets a special callback so that multiple small moves can be
- // coalesced into one large undo action.
- // undo
- Con::executef(this, 2, "onPreSelectionNudged", Con::getIntArg(getSelectedSet().getId()));
- Vector<GuiControl*>::iterator i;
- Point2I newPos;
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- {
- newPos = (*i)->mBounds.point + delta;
- newPos = snapPoint(newPos, delta, mGridSnap);
- (*i)->resize(newPos, (*i)->mBounds.extent);
- }
- // undo
- Con::executef(this, 2, "onPostSelectionNudged", Con::getIntArg(getSelectedSet().getId()));
- // allow script to update the inspector
- if (mSelectedControls.size() == 1)
- Con::executef(this, 2, "onSelectionMoved", Con::getIntArg(mSelectedControls[0]->getId()));
- }
- void GuiEditCtrl::moveSelection(const Point2I& delta)
- {
- // move / nudge gets a special callback so that multiple small moves can be
- // coalesced into one large undo action.
- // undo
- Con::executef(this, 2, "onPreSelectionNudged", Con::getIntArg(getSelectedSet().getId()));
- Vector<GuiControl*>::iterator i;
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- {
- // skip locked controls
- if ((*i)->isLocked())
- continue;
- (*i)->resize((*i)->mBounds.point + delta, (*i)->mBounds.extent);
- }
- // undo
- Con::executef(this, 2, "onPostSelectionNudged", Con::getIntArg(getSelectedSet().getId()));
- // allow script to update the inspector
- if (mSelectedControls.size() == 1)
- Con::executef(this, 2, "onSelectionMoved", Con::getIntArg(mSelectedControls[0]->getId()));
- }
- void GuiEditCtrl::justifySelection(Justification j)
- {
- S32 minX, maxX;
- S32 minY, maxY;
- S32 extentX, extentY;
- if (mSelectedControls.size() < 2)
- return;
- Vector<GuiControl*>::iterator i = mSelectedControls.begin();
- minX = (*i)->mBounds.point.x;
- maxX = minX + (*i)->mBounds.extent.x;
- minY = (*i)->mBounds.point.y;
- maxY = minY + (*i)->mBounds.extent.y;
- extentX = (*i)->mBounds.extent.x;
- extentY = (*i)->mBounds.extent.y;
- i++;
- for (; i != mSelectedControls.end(); i++)
- {
- minX = getMin(minX, (*i)->mBounds.point.x);
- maxX = getMax(maxX, (*i)->mBounds.point.x + (*i)->mBounds.extent.x);
- minY = getMin(minY, (*i)->mBounds.point.y);
- maxY = getMax(maxY, (*i)->mBounds.point.y + (*i)->mBounds.extent.y);
- extentX += (*i)->mBounds.extent.x;
- extentY += (*i)->mBounds.extent.y;
- }
- S32 deltaX = maxX - minX;
- S32 deltaY = maxY - minY;
- switch (j)
- {
- case JUSTIFY_LEFT:
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- (*i)->resize(Point2I(minX, (*i)->mBounds.point.y), (*i)->mBounds.extent);
- break;
- case JUSTIFY_TOP:
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- (*i)->resize(Point2I((*i)->mBounds.point.x, minY), (*i)->mBounds.extent);
- break;
- case JUSTIFY_RIGHT:
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- (*i)->resize(Point2I(maxX - (*i)->mBounds.extent.x + 1, (*i)->mBounds.point.y), (*i)->mBounds.extent);
- break;
- case JUSTIFY_BOTTOM:
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- (*i)->resize(Point2I((*i)->mBounds.point.x, maxY - (*i)->mBounds.extent.y + 1), (*i)->mBounds.extent);
- break;
- case JUSTIFY_CENTER:
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- (*i)->resize(Point2I(minX + ((deltaX - (*i)->mBounds.extent.x) >> 1), (*i)->mBounds.point.y),
- (*i)->mBounds.extent);
- break;
- case SPACING_VERTICAL:
- {
- Vector<GuiControl*> sortedList;
- Vector<GuiControl*>::iterator k;
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- {
- for (k = sortedList.begin(); k != sortedList.end(); k++)
- {
- if ((*i)->mBounds.point.y < (*k)->mBounds.point.y)
- break;
- }
- sortedList.insert(k, *i);
- }
- S32 space = (deltaY - extentY) / (mSelectedControls.size() - 1);
- S32 curY = minY;
- for (k = sortedList.begin(); k != sortedList.end(); k++)
- {
- (*k)->resize(Point2I((*k)->mBounds.point.x, curY), (*k)->mBounds.extent);
- curY += (*k)->mBounds.extent.y + space;
- }
- }
- break;
- case SPACING_HORIZONTAL:
- {
- Vector<GuiControl*> sortedList;
- Vector<GuiControl*>::iterator k;
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- {
- for (k = sortedList.begin(); k != sortedList.end(); k++)
- {
- if ((*i)->mBounds.point.x < (*k)->mBounds.point.x)
- break;
- }
- sortedList.insert(k, *i);
- }
- S32 space = (deltaX - extentX) / (mSelectedControls.size() - 1);
- S32 curX = minX;
- for (k = sortedList.begin(); k != sortedList.end(); k++)
- {
- (*k)->resize(Point2I(curX, (*k)->mBounds.point.y), (*k)->mBounds.extent);
- curX += (*k)->mBounds.extent.x + space;
- }
- }
- break;
- }
- }
- void GuiEditCtrl::deleteSelection(void)
- {
- // undo
- Con::executef(this, 2, "onTrashSelection", Con::getIntArg(getSelectedSet().getId()));
- Vector<GuiControl*>::iterator i;
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- {
- mTrash.addObject(*i);
- }
- mSelectedControls.clear();
- }
- void GuiEditCtrl::loadSelection(const char* filename)
- {
- if (!mCurrentAddSet)
- mCurrentAddSet = mEditorRoot;
- Con::executef(2, "exec", filename);
- SimSet* set;
- if (!Sim::findObject("guiClipboard", set))
- return;
- if (set->size())
- {
- Con::executef(this, 1, "onClearSelected");
- mSelectedControls.clear();
- for (U32 i = 0; i < (U32)set->size(); i++)
- {
- GuiControl* ctrl = dynamic_cast<GuiControl*>((*set)[i]);
- if (ctrl)
- {
- mCurrentAddSet->addObject(ctrl);
- mSelectedControls.push_back(ctrl);
- Con::executef(this, 2, "onAddSelected", Con::getIntArg(ctrl->getId()));
- }
- }
- // Undo
- Con::executef(this, 2, "onAddNewCtrlSet", Con::getIntArg(getSelectedSet().getId()));
- }
- set->deleteObject();
- }
- void GuiEditCtrl::saveSelection(const char* filename)
- {
- // if there are no selected objects, then don't save
- if (mSelectedControls.size() == 0)
- return;
- FileStream stream;
- if (!ResourceManager->openFileForWrite(stream, filename))
- return;
- SimSet* clipboardSet = new SimSet;
- clipboardSet->registerObject();
- Sim::getRootGroup()->addObject(clipboardSet, "guiClipboard");
- Vector<GuiControl*>::iterator i;
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- clipboardSet->addObject(*i);
- clipboardSet->write(stream, 0);
- clipboardSet->deleteObject();
- }
- void GuiEditCtrl::selectAll()
- {
- if (!mCurrentAddSet)
- return;
- mSelectedControls.clear();
- if (isMethod("onClearSelected"))
- {
- Con::executef(this, 1, "onClearSelected");
- }
- for (GuiControl::iterator i = mCurrentAddSet->begin(); i != mCurrentAddSet->end(); i++)
- {
- GuiControl* ctrl = dynamic_cast<GuiControl*>(*i);
- if (ctrl)
- {
- mSelectedControls.push_back(ctrl);
- if (isMethod("onAddSelected"))
- {
- Con::executef(this, 2, "onAddSelected", Con::getIntArg(ctrl->getId()));
- }
- }
- }
- }
- void GuiEditCtrl::bringToFront()
- {
- // undo
- if (mSelectedControls.size() != 1)
- return;
- GuiControl* ctrl = *(mSelectedControls.begin());
- mCurrentAddSet->pushObjectToBack(ctrl);
- }
- void GuiEditCtrl::pushToBack()
- {
- // undo
- if (mSelectedControls.size() != 1)
- return;
- GuiControl* ctrl = *(mSelectedControls.begin());
- mCurrentAddSet->bringObjectToFront(ctrl);
- }
- bool GuiEditCtrl::onKeyDown(const GuiEvent& event)
- {
- if (!mActive)
- return Parent::onKeyDown(event);
- if (!(event.modifier & SI_CTRL) && !(event.modifier & SI_SHIFT))
- {
- switch (event.keyCode)
- {
- case KEY_BACKSPACE:
- case KEY_DELETE:
- deleteSelection();
- Con::executef(this, 1, "onDelete");
- return true;
- }
- }
- else if (event.modifier & SI_SHIFT && !(event.modifier & SI_CTRL))
- {
- //holding shift while using arrow keys toggles the grid snap
- switch (event.keyCode)
- {
- case KEY_LEFT:
- moveSelection(Point2I(mUseGridSnap ? -1 : -mGridSnap.x, 0));
- return true;
- case KEY_RIGHT:
- moveSelection(Point2I(mUseGridSnap ? 1 : mGridSnap.x, 0));
- return true;
- case KEY_UP:
- moveSelection(Point2I(0, mUseGridSnap ? -1 : -mGridSnap.y));
- return true;
- case KEY_DOWN:
- moveSelection(Point2I(0, mUseGridSnap ? 1 : mGridSnap.y));
- return true;
- }
- }
- return false;
- }
- ConsoleMethod(GuiEditCtrl, setSnapToGrid, void, 3, 3, "(gridsize) Set the size of the snap-to grid.\n"
- "@return No return value.")
- {
- U32 gridsize = dAtoi(argv[2]);
- object->setSnapToGrid(gridsize);
- }
- ConsoleMethod(GuiEditCtrl, getGridSize, S32, 2, 2, "() Returns the grid size even if the grid is off.\n"
- "@return A single int as the grid size.")
- {
- U32 gridSize = object->getGridSize();
- return gridSize;
- }
- void GuiEditCtrl::setSnapToGrid(U32 gridsize)
- {
- if (gridsize == 0)
- {
- mUseGridSnap = false;
- }
- else
- {
- mGridSnap.set(gridsize, gridsize);
- mUseGridSnap = true;
- }
- }
- void GuiEditCtrl::controlInspectPreApply(GuiControl* object)
- {
- // undo
- Con::executef(this, 2, "onControlInspectPreApply", Con::getIntArg(object->getId()));
- }
- void GuiEditCtrl::controlInspectPostApply(GuiControl* object)
- {
- // undo
- Con::executef(this, 2, "onControlInspectPostApply", Con::getIntArg(object->getId()));
- }
- void GuiEditCtrl::updateSelectedSet()
- {
- mSelectedSet.clear();
- Vector<GuiControl*>::iterator i;
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- {
- mSelectedSet.addObject(*i);
- }
- }
- // -----------------------------------------------------------------------------
- // GuiEditor Ruler
- // -----------------------------------------------------------------------------
- class GuiEditorRuler : public GuiControl {
- StringTableEntry refCtrl;
- typedef GuiControl Parent;
- public:
- void onPreRender()
- {
- setUpdate();
- }
- void onRender(Point2I offset, const RectI& updateRect)
- {
- dglDrawRectFill(updateRect, ColorF(1, 1, 1, 1));
- GuiScrollCtrl* ref;
- SimObject* o = Sim::findObject(refCtrl);
- //Sim::findObject(refCtrl, &ref);
- ref = dynamic_cast<GuiScrollCtrl*>(o);
- Point2I choffset(0, 0);
- //if(ref)
- // choffset = ref->getChildPos();
- if (mBounds.extent.x > mBounds.extent.y)
- {
- // it's horizontal.
- for (U32 i = 0; i < (U32)mBounds.extent.x; i++)
- {
- S32 x = offset.x + i;
- S32 pos = i - choffset.x;
- if (!(pos % 10))
- {
- S32 start = 6;
- if (!(pos % 20))
- start = 4;
- if (!(pos % 100))
- start = 1;
- dglDrawLine(x, offset.y + start, x, offset.y + 10, ColorF(0, 0, 0, 1));
- }
- }
- }
- else
- {
- // it's vertical.
- for (U32 i = 0; i < (U32)mBounds.extent.y; i++)
- {
- S32 y = offset.y + i;
- S32 pos = i - choffset.y;
- if (!(pos % 10))
- {
- S32 start = 6;
- if (!(pos % 20))
- start = 4;
- if (!(pos % 100))
- start = 1;
- dglDrawLine(offset.x + start, y, offset.x + 10, y, ColorF(0, 0, 0, 1));
- }
- }
- }
- }
- static void initPersistFields()
- {
- Parent::initPersistFields();
- addField("refCtrl", TypeString, Offset(refCtrl, GuiEditorRuler));
- }
- DECLARE_CONOBJECT(GuiEditorRuler);
- };
- IMPLEMENT_CONOBJECT(GuiEditorRuler);
|