123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 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 "platform/platform.h"
- #include "gui/editor/guiEditCtrl.h"
- #include "core/frameAllocator.h"
- #include "core/stream/fileStream.h"
- #include "core/stream/memStream.h"
- #include "console/consoleTypes.h"
- #include "gui/core/guiCanvas.h"
- #include "gui/containers/guiScrollCtrl.h"
- #include "core/strings/stringUnit.h"
- #include "console/engineAPI.h"
- IMPLEMENT_CONOBJECT( GuiEditCtrl );
- ConsoleDocClass( GuiEditCtrl,
- "@brief Native side of the GUI editor.\n\n"
- "Editor use only.\n\n"
- "@internal"
- );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onHierarchyChanged, void, (), (),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onDelete, void, (), (),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onPreEdit, void, ( SimSet* selection ), ( selection ),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onPostEdit, void, ( SimSet* selection ), ( selection ),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onClearSelected, void, (), (),
- "" )
- IMPLEMENT_CALLBACK( GuiEditCtrl, onSelect, void, ( GuiControl* control ), ( control ),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onAddSelected, void, ( GuiControl* control ), ( control ),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onRemoveSelected, void, ( GuiControl* control ), ( control ),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onPreSelectionNudged, void, ( SimSet* selection ), ( selection ),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onPostSelectionNudged, void, ( SimSet* selection ), ( selection ),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onSelectionMoved, void, ( GuiControl* control ), ( control ),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onSelectionCloned, void, ( SimSet* selection ), ( selection ),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onTrashSelection, void, ( SimSet* selection ), ( selection ),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onAddNewCtrl, void, ( GuiControl* control ), ( control ),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onAddNewCtrlSet, void, ( SimSet* set ), ( set ),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onSelectionResized, void, ( GuiControl* control ), ( control ),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onFitIntoParent, void, ( bool width, bool height ), ( width, height ),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onMouseModeChange, void, (), (),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onControlInspectPreApply, void, ( GuiControl* control ), ( control ),
- "" );
- IMPLEMENT_CALLBACK( GuiEditCtrl, onControlInspectPostApply, void, ( GuiControl* control ), ( control ),
- "" );
- StringTableEntry GuiEditCtrl::smGuidesPropertyName[ 2 ];
- //-----------------------------------------------------------------------------
- GuiEditCtrl::GuiEditCtrl()
- : mCurrentAddSet( NULL ),
- mContentControl( NULL ),
- mGridSnap( 0, 0 ),
- mDragBeginPoint( -1, -1 ),
- mSnapToControls( true ),
- mSnapToEdges( true ),
- mSnapToGuides( true ),
- mSnapToCenters( true ),
- mSnapToCanvas( true ),
- mDrawBorderLines( true ),
- mFullBoxSelection( false ),
- mSnapSensitivity( 2 ),
- mDrawGuides( true ),
- mDragAddSelection(false),
- mDragMoveUndo(false)
- {
- VECTOR_SET_ASSOCIATION( mSelectedControls );
- VECTOR_SET_ASSOCIATION( mDragBeginPoints );
- VECTOR_SET_ASSOCIATION( mSnapHits[ 0 ] );
- VECTOR_SET_ASSOCIATION( mSnapHits[ 1 ] );
-
- mActive = true;
- mDotSB = NULL;
-
- mSnapped[ SnapVertical ] = false;
- mSnapped[ SnapHorizontal ] = false;
- mDragGuide[ GuideVertical ] = false;
- mDragGuide[ GuideHorizontal ] = false;
- mDragGuideIndex[0] = 0;
- mDragGuideIndex[1] = 1;
- std::fill_n(mSnapOffset, 2, 0);
- std::fill_n(mSnapEdge, 2, SnapEdgeMin);
-
- if( !smGuidesPropertyName[ GuideVertical ] )
- smGuidesPropertyName[ GuideVertical ] = StringTable->insert( "guidesVertical" );
- if( !smGuidesPropertyName[ GuideHorizontal ] )
- smGuidesPropertyName[ GuideHorizontal ] = StringTable->insert( "guidesHorizontal" );
- mTrash = NULL;
- mSelectedSet = NULL;
- mMouseDownMode = GuiEditCtrl::Selecting;
- mSizingMode = GuiEditCtrl::sizingNone;
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::initPersistFields()
- {
- docsURL;
- addGroup( "Snapping" );
- addField( "snapToControls", TypeBool, Offset( mSnapToControls, GuiEditCtrl ),
- "If true, edge and center snapping will work against controls." );
- addField( "snapToGuides", TypeBool, Offset( mSnapToGuides, GuiEditCtrl ),
- "If true, edge and center snapping will work against guides." );
- addField( "snapToCanvas", TypeBool, Offset( mSnapToCanvas, GuiEditCtrl ),
- "If true, edge and center snapping will work against canvas (toplevel control)." );
- addField( "snapToEdges", TypeBool, Offset( mSnapToEdges, GuiEditCtrl ),
- "If true, selection edges will snap into alignment when moved or resized." );
- addField( "snapToCenters", TypeBool, Offset( mSnapToCenters, GuiEditCtrl ),
- "If true, selection centers will snap into alignment when moved or resized." );
- addField( "snapSensitivity", TypeS32, Offset( mSnapSensitivity, GuiEditCtrl ),
- "Distance in pixels that edge and center snapping will work across." );
- endGroup( "Snapping" );
-
- addGroup( "Selection" );
- addField( "fullBoxSelection", TypeBool, Offset( mFullBoxSelection, GuiEditCtrl ),
- "If true, rectangle selection will only select controls fully inside the drag rectangle." );
- endGroup( "Selection" );
-
- addGroup( "Rendering" );
- addField( "drawBorderLines", TypeBool, Offset( mDrawBorderLines, GuiEditCtrl ),
- "If true, lines will be drawn extending along the edges of selected objects." );
- addField( "drawGuides", TypeBool, Offset( mDrawGuides, GuiEditCtrl ),
- "If true, guides will be included in rendering." );
- endGroup( "Rendering" );
- Parent::initPersistFields();
- }
- //=============================================================================
- // Events.
- //=============================================================================
- // MARK: ---- Events ----
- //-----------------------------------------------------------------------------
- bool GuiEditCtrl::onAdd()
- {
- if( !Parent::onAdd() )
- return false;
-
- mTrash = new SimGroup();
- mSelectedSet = new SimSet();
-
- if( !mTrash->registerObject() )
- return false;
- if( !mSelectedSet->registerObject() )
- return false;
- return true;
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::onRemove()
- {
- Parent::onRemove();
-
- mDotSB = NULL;
-
- mTrash->deleteObject();
- mSelectedSet->deleteObject();
-
- mTrash = NULL;
- mSelectedSet = NULL;
- }
- //-----------------------------------------------------------------------------
- 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();
- }
- //-----------------------------------------------------------------------------
- bool GuiEditCtrl::onKeyDown(const GuiEvent &event)
- {
- if (! mActive)
- return Parent::onKeyDown(event);
- if (!(event.modifier & SI_PRIMARY_CTRL))
- {
- switch(event.keyCode)
- {
- case KEY_BACKSPACE:
- case KEY_DELETE:
- deleteSelection();
- onDelete_callback();
- return true;
- default:
- break;
- }
- }
- return false;
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::onMouseDown(const GuiEvent &event)
- {
- if (! mActive)
- {
- Parent::onMouseDown(event);
- return;
- }
- if(!mContentControl)
- return;
- setFirstResponder();
- mouseLock();
- mLastMousePos = globalToLocalCoord( event.mousePoint );
- // Check whether we've hit a guide. If so, start a guide drag.
- // Don't do this if SHIFT is down.
-
- if( !( event.modifier & SI_SHIFT ) )
- {
- for( U32 axis = 0; axis < 2; ++ axis )
- {
- const S32 guide = findGuide( ( guideAxis ) axis, event.mousePoint, 1 );
- if( guide != -1 )
- {
- setMouseMode( DragGuide );
-
- mDragGuide[ axis ] = true;
- mDragGuideIndex[ axis ] = guide;
- }
- }
-
- if( mMouseDownMode == DragGuide )
- return;
- }
-
- // Check whether we have hit a sizing knob on any of the currently selected
- // controls.
-
- for( U32 i = 0, num = mSelectedControls.size(); i < num; ++ i )
- {
- GuiControl* ctrl = mSelectedControls[ i ];
-
- Point2I cext = ctrl->getExtent();
- Point2I 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 )
- {
- setMouseMode( SizingSelection );
- mLastDragPos = event.mousePoint;
-
- // undo
- onPreEdit_callback( getSelectedSet() );
- return;
- }
- }
- // Find the control we have hit.
-
- GuiControl* ctrl = mContentControl->findHitControl( mLastMousePos, getCurrentAddSet()->mLayer );
- // Give the control itself the opportunity to handle the event
- // to implement custom editing logic.
- bool handledEvent = ctrl->onMouseDownEditor( event, localToGlobalCoord( Point2I(0,0) ) );
- if( handledEvent == true )
- {
- // The Control handled the event and requested the edit ctrl
- // *NOT* act on it.
- return;
- }
- else if( event.modifier & SI_SHIFT )
- {
- // Shift is down. Start rectangle selection in add mode
- // no matter what we have hit.
-
- startDragRectangle( event.mousePoint );
- mDragAddSelection = true;
- }
- else if( selectionContains( ctrl ) )
- {
- // We hit a selected control. If the multiselect key is pressed,
- // deselect the control. Otherwise start a drag move.
-
- if( event.modifier & SI_MULTISELECT )
- {
- removeSelection( ctrl );
- //set the mode
- setMouseMode( Selecting );
- }
- else if( event.modifier & SI_PRIMARY_ALT )
- {
- // Alt is down. Start a drag clone.
-
- startDragClone( event.mousePoint );
- }
- else
- {
- startDragMove( event.mousePoint );
- }
- }
- else
- {
- // We clicked an unselected control.
-
- if( ctrl == getContentControl() )
- {
- // Clicked in toplevel control. Start a rectangle selection.
-
- startDragRectangle( event.mousePoint );
- mDragAddSelection = false;
- }
- else if( event.modifier & SI_PRIMARY_ALT && ctrl != getContentControl() )
- {
- // Alt is down. Start a drag clone.
-
- clearSelection();
- addSelection( ctrl );
-
- startDragClone( event.mousePoint );
- }
- else if( event.modifier & SI_MULTISELECT )
- addSelection( ctrl );
- else
- {
- // Clicked on child control. Start move.
-
- clearSelection();
- addSelection( ctrl );
-
- startDragMove( event.mousePoint );
- }
- }
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::onMouseUp(const GuiEvent &event)
- {
- if (! mActive || !mContentControl || !getCurrentAddSet() )
- {
- Parent::onMouseUp(event);
- return;
- }
- //find the control we clicked
- GuiControl *ctrl = mContentControl->findHitControl(mLastMousePos, getCurrentAddSet()->mLayer);
- bool handledEvent = ctrl->onMouseUpEditor( event, localToGlobalCoord( Point2I(0,0) ) );
- 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();
- // Reset Drag Axis Alignment Information
- mDragBeginPoint.set(-1,-1);
- mDragBeginPoints.clear();
- mLastMousePos = globalToLocalCoord(event.mousePoint);
- if( mMouseDownMode == DragGuide )
- {
- // Check to see if the mouse has moved off the canvas. If so,
- // remove the guides being dragged.
-
- for( U32 axis = 0; axis < 2; ++ axis )
- if( mDragGuide[ axis ] && !getContentControl()->getGlobalBounds().pointInRect( event.mousePoint ) )
- mGuides[ axis ].erase( mDragGuideIndex[ axis ] );
- }
- else if( mMouseDownMode == DragSelecting )
- {
- // If not multiselecting, clear the current selection.
-
- if( !( event.modifier & SI_MULTISELECT ) && !mDragAddSelection )
- clearSelection();
-
- RectI rect;
- getDragRect( rect );
-
- // If the region is somewhere less than at least 2x2, count this as a
- // normal, non-rectangular selection.
-
- if( rect.extent.x <= 2 && rect.extent.y <= 2 )
- addSelectControlAt( rect.point );
- else
- {
- // Use HIT_AddParentHits by default except if ALT is pressed.
- // Use HIT_ParentPreventsChildHit if ALT+CTRL is pressed.
-
- U32 hitFlags = 0;
- if( !( event.modifier & SI_PRIMARY_ALT ) )
- hitFlags |= HIT_AddParentHits;
- if( event.modifier & SI_PRIMARY_ALT && event.modifier & SI_CTRL )
- hitFlags |= HIT_ParentPreventsChildHit;
-
- addSelectControlsInRegion( rect, hitFlags );
- }
- }
- else if( ctrl == getContentControl() && mMouseDownMode == Selecting )
- setCurrentAddSet( NULL, true );
-
- // 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 && mDragMoveUndo ) )
- onPostEdit_callback( getSelectedSet() );
- //reset the mouse mode
- setFirstResponder();
- setMouseMode( Selecting );
- mSizingMode = sizingNone;
-
- // Clear snapping state.
-
- mSnapped[ SnapVertical ] = false;
- mSnapped[ SnapHorizontal ] = false;
-
- mSnapTargets[ SnapVertical ] = NULL;
- mSnapTargets[ SnapHorizontal ] = NULL;
-
- // Clear guide drag state.
-
- mDragGuide[ GuideVertical ] = false;
- mDragGuide[ GuideHorizontal ] = false;
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::onMouseDragged( const GuiEvent &event )
- {
- if( !mActive || !mContentControl || !getCurrentAddSet() )
- {
- Parent::onMouseDragged(event);
- return;
- }
- Point2I mousePoint = globalToLocalCoord( event.mousePoint );
- //find the control we clicked
- GuiControl *ctrl = mContentControl->findHitControl( mousePoint, getCurrentAddSet()->mLayer );
- bool handledEvent = ctrl->onMouseDraggedEditor( event, localToGlobalCoord( Point2I(0,0) ) );
- if( handledEvent == true )
- {
- // The Control handled the event and requested the edit ctrl
- // *NOT* act on it. The dude abides.
- return;
- }
-
- // If we're doing a drag clone, see if we have crossed the move threshold. If so,
- // clone the selection and switch to move mode.
-
- if( mMouseDownMode == DragClone )
- {
- // If we haven't yet crossed the mouse delta to actually start the
- // clone, check if we have now.
-
- S32 delta = mAbs( ( mousePoint - mDragBeginPoint ).len() );
- if( delta >= 4 )
- {
- cloneSelection();
- mLastMousePos = mDragBeginPoint;
- mDragMoveUndo = false;
-
- setMouseMode( MovingSelection );
- }
- }
-
- if( mMouseDownMode == DragGuide )
- {
- for( U32 axis = 0; axis < 2; ++ axis )
- if( mDragGuide[ axis ] )
- {
- // Set the guide to the coordinate of the mouse cursor
- // on the guide's axis.
-
- Point2I point = event.mousePoint;
- point -= localToGlobalCoord( Point2I( 0, 0 ) );
- point[ axis ] = mClamp( point[ axis ], 0, getExtent()[ axis ] - 1 );
-
- mGuides[ axis ][ mDragGuideIndex[ axis ] ] = point[ axis ];
- }
- }
- else if( mMouseDownMode == SizingSelection )
- {
- // Snap the mouse cursor to grid if active. Do this on the mouse cursor so that we handle
- // incremental drags correctly.
-
- Point2I dragPoint = event.mousePoint;
- snapToGrid(dragPoint);
-
- Point2I delta = dragPoint - mLastDragPos;
-
- // If CTRL is down, apply smart snapping.
-
- if( event.modifier & SI_CTRL )
- {
- RectI selectionBounds = getSelectionBounds();
-
- doSnapping( event, selectionBounds, delta );
- }
- else
- {
- mSnapped[ SnapVertical ] = false;
- mSnapped[ SnapHorizontal ] = false;
- }
-
- // If ALT is down, do a move instead of a resize on the control
- // knob's axis. Otherwise resize.
- if( event.modifier & SI_PRIMARY_ALT )
- {
- if( !( mSizingMode & sizingLeft ) && !( mSizingMode & sizingRight ) )
- {
- mSnapped[ SnapVertical ] = false;
- delta.x = 0;
- }
- if( !( mSizingMode & sizingTop ) && !( mSizingMode & sizingBottom ) )
- {
- mSnapped[ SnapHorizontal ] = false;
- delta.y = 0;
- }
-
- moveSelection( delta );
- }
- else
- resizeControlsInSelectionBy( delta, mSizingMode );
-
- // Remember drag point.
-
- mLastDragPos = dragPoint;
- }
- else if (mMouseDownMode == MovingSelection && mSelectedControls.size())
- {
- Point2I delta = mousePoint - mLastMousePos;
- RectI selectionBounds = getSelectionBounds();
-
- // Apply snaps.
-
- doSnapping( event, selectionBounds, delta );
-
- //RDTODO: to me seems to be in need of revision
- // Do we want to align this drag to the X and Y axes within a certain threshold?
- if( event.modifier & SI_SHIFT && !( event.modifier & SI_PRIMARY_ALT ) )
- {
- Point2I dragTotalDelta = event.mousePoint - localToGlobalCoord( mDragBeginPoint );
- if( dragTotalDelta.y < 10 && dragTotalDelta.y > -10 )
- {
- for(S32 i = 0; i < mSelectedControls.size(); i++)
- {
- Point2I selCtrlPos = mSelectedControls[i]->getPosition();
- Point2I snapBackPoint( selCtrlPos.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( selCtrlPos.y != mDragBeginPoints[i].y )
- mSelectedControls[i]->setPosition( snapBackPoint );
- }
- delta.y = 0;
- }
- if( dragTotalDelta.x < 10 && dragTotalDelta.x > -10 )
- {
- for(S32 i = 0; i < mSelectedControls.size(); i++)
- {
- Point2I selCtrlPos = mSelectedControls[i]->getPosition();
- Point2I snapBackPoint( mDragBeginPoints[i].x, selCtrlPos.y);
- // This is kind of nasty but we need to snap back if we're not at origin point with selection - JDD
- if( selCtrlPos.x != mDragBeginPoints[i].x )
- mSelectedControls[i]->setPosition( snapBackPoint );
- }
- delta.x = 0;
- }
- }
- if( delta.x || delta.y )
- moveSelection( delta, mDragMoveUndo );
- // find the current control under the mouse
- canHitSelectedControls( false );
- GuiControl *inCtrl = mContentControl->findHitControl(mousePoint, getCurrentAddSet()->mLayer);
- canHitSelectedControls( true );
- // 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, mDragMoveUndo );
- setCurrentAddSet( inCtrl, false );
- }
- mLastMousePos += delta;
- }
- else
- mLastMousePos = mousePoint;
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::onRightMouseDown(const GuiEvent &event)
- {
- if (! mActive || !mContentControl)
- {
- Parent::onRightMouseDown(event);
- return;
- }
- setFirstResponder();
- //search for the control hit in any layer below the edit layer
- GuiControl *hitCtrl = mContentControl->findHitControl(globalToLocalCoord(event.mousePoint), mLayer - 1);
- if (hitCtrl != getCurrentAddSet())
- {
- setCurrentAddSet( hitCtrl );
- }
- // select the parent if we right-click on the current add set
- else if( getCurrentAddSet() != mContentControl)
- {
- setCurrentAddSet( hitCtrl->getParent() );
- select(hitCtrl);
- }
- //Design time mouse events
- GuiEvent designEvent = event;
- designEvent.mousePoint = mLastMousePos;
- hitCtrl->onRightMouseDownEditor( designEvent, localToGlobalCoord( Point2I(0,0) ) );
- }
- //=============================================================================
- // Rendering.
- //=============================================================================
- // MARK: ---- Rendering ----
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::onPreRender()
- {
- setUpdate();
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::onRender(Point2I offset, const RectI &updateRect)
- {
- Point2I ctOffset;
- Point2I cext;
- bool keyFocused = isFirstResponder();
- GFXDrawUtil *drawer = GFX->getDrawUtil();
- if (mActive)
- {
- if( getCurrentAddSet() != getContentControl() )
- {
- // draw a white frame inset around the current add set.
- cext = getCurrentAddSet()->getExtent();
- ctOffset = getCurrentAddSet()->localToGlobalCoord(Point2I(0,0));
- RectI box(ctOffset.x, ctOffset.y, cext.x, cext.y);
- box.inset( -5, -5 );
- drawer->drawRect( box, ColorI( 50, 101, 152, 128 ) );
- box.inset( 1, 1 );
- drawer->drawRect( box, ColorI( 50, 101, 152, 128 ) );
- box.inset( 1, 1 );
- drawer->drawRect( box, ColorI( 50, 101, 152, 128 ) );
- box.inset( 1, 1 );
- drawer->drawRect( box, ColorI( 50, 101, 152, 128 ) );
- box.inset( 1, 1 );
- drawer->drawRect( box, ColorI( 50, 101, 152, 128 ) );
- }
- 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);
- ColorI nutColor = multisel ? ColorI( 255, 255, 255, 100 ) : ColorI( 0, 0, 0, 100 );
- ColorI outlineColor = multisel ? ColorI( 0, 0, 0, 100 ) : ColorI( 255, 255, 255, 100 );
- if(!keyFocused)
- nutColor.set( 128, 128, 128, 100 );
- drawNuts(box, outlineColor, nutColor);
- }
- }
- renderChildControls(offset, updateRect);
-
- // Draw selection rectangle.
-
- if( mActive && mMouseDownMode == DragSelecting )
- {
- RectI b;
- getDragRect(b);
- b.point += offset;
-
- // Draw outline.
-
- drawer->drawRect( b, ColorI( 100, 100, 100, 128 ) );
-
- // Draw fill.
-
- b.inset( 1, 1 );
- drawer->drawRectFill( b, ColorI( 150, 150, 150, 128 ) );
- }
- // Draw grid.
- if( mActive &&
- ( mMouseDownMode == MovingSelection || mMouseDownMode == SizingSelection ) &&
- ( mGridSnap.x || mGridSnap.y ) )
- {
- cext = getContentControl()->getExtent();
- Point2I coff = getContentControl()->localToGlobalCoord(Point2I(0,0));
-
- // create point-dots
- const Point2I& snap = mGridSnap;
- U32 maxdot = (U32)(mCeil(cext.x / (F32)snap.x) - 1) * (U32)(mCeil(cext.y / (F32)snap.y) - 1);
- if( mDots.isNull() || maxdot != mDots->mNumVerts)
- {
- mDots.set(GFX, maxdot, GFXBufferTypeStatic);
- U32 ndot = 0;
- mDots.lock();
- for(U32 ix = snap.x; ix < cext.x; ix += snap.x)
- {
- for(U32 iy = snap.y; ndot < maxdot && iy < cext.y; iy += snap.y)
- {
- mDots[ndot].color.set( 50, 50, 254, 100 );
- mDots[ndot].point.x = F32(ix + coff.x);
- mDots[ndot].point.y = F32(iy + coff.y);
- mDots[ndot].point.z = 0.0f;
- ndot++;
- }
- }
- mDots.unlock();
- AssertFatal(ndot <= maxdot, "dot overflow");
- AssertFatal(ndot == maxdot, "dot underflow");
- }
- if (!mDotSB)
- {
- GFXStateBlockDesc dotdesc;
- dotdesc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
- dotdesc.setCullMode( GFXCullNone );
- mDotSB = GFX->createStateBlock( dotdesc );
- }
- GFX->setStateBlock(mDotSB);
- // draw the points.
- GFX->setVertexBuffer( mDots );
- GFX->drawPrimitive( GFXPointList, 0, mDots->mNumVerts );
- }
- // Draw snapping lines.
-
- if( mActive && getContentControl() )
- {
- RectI bounds = getContentControl()->getGlobalBounds();
-
- // Draw guide lines.
- if( mDrawGuides )
- {
- for( U32 axis = 0; axis < 2; ++ axis )
- {
- for( U32 i = 0, num = mGuides[ axis ].size(); i < num; ++ i )
- drawCrossSection( axis, mGuides[ axis ][ i ] + bounds.point[ axis ],
- bounds, ColorI( 0, 255, 0, 100 ), drawer );
- }
- }
- // Draw smart snap lines.
-
- for( U32 axis = 0; axis < 2; ++ axis )
- {
- if( mSnapped[ axis ] )
- {
- // Draw the snap line.
-
- drawCrossSection( axis, mSnapOffset[ axis ],
- bounds, ColorI( 0, 0, 255, 100 ), drawer );
- // Draw a border around the snap target control.
-
- if( mSnapTargets[ axis ] )
- {
- RectI snapBounds = mSnapTargets[ axis ]->getGlobalBounds();
- drawer->drawRect(snapBounds, ColorI( 128, 128, 128, 128 ) );
- }
- }
- }
- }
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::drawNuts(RectI &box, ColorI &outlineColor, ColorI &nutColor)
- {
- GFXDrawUtil *drawer = GFX->getDrawUtil();
- 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;
- if( mDrawBorderLines )
- {
- ColorI lineColor( 179, 179, 179, 64 );
- ColorI lightLineColor( 128, 128, 128, 26);
-
- if(lx > 0 && ty > 0)
- {
- drawer->drawLine(0, ty, lx, ty, lineColor); // Left edge to top-left corner.
- drawer->drawLine(lx, 0, lx, ty, lineColor); // Top edge to top-left corner.
- }
- if(lx > 0 && by > 0)
- drawer->drawLine(0, by, lx, by, lineColor); // Left edge to bottom-left corner.
- if(rx > 0 && ty > 0)
- drawer->drawLine(rx, 0, rx, ty, lineColor); // Top edge to top-right corner.
- Point2I extent = localToGlobalCoord(getExtent());
- if(lx < extent.x && by < extent.y)
- drawer->drawLine(lx, by, lx, extent.y, lightLineColor); // Bottom-left corner to bottom edge.
- if(rx < extent.x && by < extent.y)
- {
- drawer->drawLine(rx, by, rx, extent.y, lightLineColor); // Bottom-right corner to bottom edge.
- drawer->drawLine(rx, by, extent.x, by, lightLineColor); // Bottom-right corner to right edge.
- }
- if(rx < extent.x && ty < extent.y)
- drawer->drawLine(rx, ty, extent.x, ty, lightLineColor); // Top-right corner to right edge.
- }
- // Adjust nuts, so they dont straddle the controls.
-
- lx -= NUT_SIZE + 1;
- ty -= NUT_SIZE + 1;
- rx += 1;
- by += 1;
-
- // Draw nuts.
- drawNut( Point2I( lx - NUT_SIZE, ty - NUT_SIZE ), outlineColor, nutColor ); // Top left
- drawNut( Point2I( lx - NUT_SIZE, cy - NUT_SIZE / 2 ), outlineColor, nutColor ); // Mid left
- drawNut( Point2I( lx - NUT_SIZE, by ), outlineColor, nutColor ); // Bottom left
- drawNut( Point2I( rx, ty - NUT_SIZE ), outlineColor, nutColor ); // Top right
- drawNut( Point2I( rx, cy - NUT_SIZE / 2 ), outlineColor, nutColor ); // Mid right
- drawNut( Point2I( rx, by ), outlineColor, nutColor ); // Bottom right
- drawNut( Point2I( cx - NUT_SIZE / 2, ty - NUT_SIZE ), outlineColor, nutColor ); // Mid top
- drawNut( Point2I( cx - NUT_SIZE / 2, by ), outlineColor, nutColor ); // Mid bottom
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::drawNut(const Point2I &nut, ColorI &outlineColor, ColorI &nutColor)
- {
- RectI r( nut.x, nut.y, NUT_SIZE * 2, NUT_SIZE * 2 );
- GFX->getDrawUtil()->drawRect( r, outlineColor );
- r.inset( 1, 1 );
- GFX->getDrawUtil()->drawRectFill( r, nutColor );
- }
- //=============================================================================
- // Selections.
- //=============================================================================
- // MARK: ---- Selections ----
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::clearSelection(void)
- {
- mSelectedControls.clear();
- onClearSelected_callback();
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::setSelection(GuiControl *ctrl, bool inclusive)
- {
- //sanity check
- if( !ctrl )
- return;
-
- if( mSelectedControls.size() == 1 && mSelectedControls[ 0 ] == ctrl )
- return;
-
- if( !inclusive )
- clearSelection();
- if( mContentControl == ctrl )
- setCurrentAddSet( ctrl, false );
- else
- addSelection( ctrl );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::addSelection(S32 id)
- {
- GuiControl * ctrl;
- if( Sim::findObject( id, ctrl ) )
- addSelection( ctrl );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::addSelection( GuiControl* ctrl )
- {
- // Only add if this isn't the content control and the
- // control isn't yet in the selection.
-
- if( ctrl != getContentControl() && !selectionContains( ctrl ) )
- {
- mSelectedControls.push_back( ctrl );
-
- if( mSelectedControls.size() == 1 )
- {
- // Update the add set.
-
- if( ctrl->mIsContainer )
- setCurrentAddSet( ctrl, false );
- else
- setCurrentAddSet( ctrl->getParent(), false );
-
- // Notify script.
- onSelect_callback( ctrl );
- }
- else
- {
- // Notify script.
-
- onAddSelected_callback( ctrl );
- }
- }
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::removeSelection( S32 id )
- {
- GuiControl * ctrl;
- if ( Sim::findObject( id, ctrl ) )
- removeSelection( ctrl );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::removeSelection( GuiControl* ctrl )
- {
- if( selectionContains( ctrl ) )
- {
- Vector< GuiControl* >::iterator i = T3D::find( mSelectedControls.begin(), mSelectedControls.end(), ctrl );
- if ( i != mSelectedControls.end() )
- mSelectedControls.erase( i );
- onRemoveSelected_callback( ctrl );
- }
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::canHitSelectedControls( bool state )
- {
- for( U32 i = 0, num = mSelectedControls.size(); i < num; ++ i )
- mSelectedControls[ i ]->setCanHit( state );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::moveSelectionToCtrl( GuiControl *newParent, bool callback )
- {
- for( U32 i = 0; i < mSelectedControls.size(); ++ i )
- {
- GuiControl* ctrl = mSelectedControls[i];
- if( ctrl->getParent() == newParent
- || ctrl->isLocked()
- || selectionContainsParentOf( ctrl ) )
- continue;
-
- Point2I globalpos = ctrl->localToGlobalCoord(Point2I(0,0));
- newParent->addObject(ctrl);
- Point2I newpos = ctrl->globalToLocalCoord(globalpos) + ctrl->getPosition();
- ctrl->setPosition(newpos);
- }
-
- onHierarchyChanged_callback();
-
- //TODO: undo
- }
- //-----------------------------------------------------------------------------
- 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, bool callback )
- {
- // move / nudge gets a special callback so that multiple small moves can be
- // coalesced into one large undo action.
- // undo
-
- if( callback )
- onPreSelectionNudged_callback( getSelectedSet() );
- Vector<GuiControl *>::iterator i;
- Point2I newPos;
- for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- {
- GuiControl* ctrl = *i;
- if( !ctrl->isLocked() && !selectionContainsParentOf( ctrl ) )
- {
- newPos = ctrl->getPosition() + delta;
- newPos = snapPoint( newPos, delta, mGridSnap );
- ctrl->setPosition( newPos );
- }
- }
- // undo
- if( callback )
- onPostSelectionNudged_callback( getSelectedSet() );
- // allow script to update the inspector
- if( callback && mSelectedControls.size() > 0 )
- onSelectionMoved_callback( mSelectedControls[ 0 ] );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::moveSelection( const Point2I &delta, bool callback )
- {
- Vector<GuiControl *>::iterator i;
- for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- {
- GuiControl* ctrl = *i;
- if( !ctrl->isLocked() && !selectionContainsParentOf( ctrl ) )
- ctrl->setPosition( ctrl->getPosition() + delta );
- }
- // allow script to update the inspector
- if( callback )
- onSelectionMoved_callback( mSelectedControls[ 0 ] );
- }
- //-----------------------------------------------------------------------------
- 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)->getLeft();
- maxX = minX + (*i)->getWidth();
- minY = (*i)->getTop();
- maxY = minY + (*i)->getHeight();
- extentX = (*i)->getWidth();
- extentY = (*i)->getHeight();
- i++;
- for(;i != mSelectedControls.end(); i++)
- {
- minX = getMin(minX, (*i)->getLeft());
- maxX = getMax(maxX, (*i)->getLeft() + (*i)->getWidth());
- minY = getMin(minY, (*i)->getTop());
- maxY = getMax(maxY, (*i)->getTop() + (*i)->getHeight());
- extentX += (*i)->getWidth();
- extentY += (*i)->getHeight();
- }
- S32 deltaX = maxX - minX;
- S32 deltaY = maxY - minY;
- switch(j)
- {
- case JUSTIFY_LEFT:
- for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- if( !( *i )->isLocked() )
- (*i)->setLeft( minX );
- break;
- case JUSTIFY_TOP:
- for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- if( !( *i )->isLocked() )
- (*i)->setTop( minY );
- break;
- case JUSTIFY_RIGHT:
- for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- if( !( *i )->isLocked() )
- (*i)->setLeft( maxX - (*i)->getWidth() + 1 );
- break;
- case JUSTIFY_BOTTOM:
- for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- if( !( *i )->isLocked() )
- (*i)->setTop( maxY - (*i)->getHeight() + 1 );
- break;
- case JUSTIFY_CENTER_VERTICAL:
- for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- if( !( *i )->isLocked() )
- (*i)->setLeft( minX + ((deltaX - (*i)->getWidth()) >> 1 ));
- break;
- case JUSTIFY_CENTER_HORIZONTAL:
- for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- if( !( *i )->isLocked() )
- (*i)->setTop( minY + ((deltaY - (*i)->getHeight()) >> 1 ));
- 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)->getTop() < (*k)->getTop())
- break;
- }
- sortedList.insert(k, *i);
- }
- S32 space = (deltaY - extentY) / (mSelectedControls.size() - 1);
- S32 curY = minY;
- for(k = sortedList.begin(); k != sortedList.end(); k++)
- {
- if( !( *k )->isLocked() )
- (*k)->setTop( curY );
- curY += (*k)->getHeight() + 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)->getLeft() < (*k)->getLeft())
- break;
- }
- sortedList.insert(k, *i);
- }
- S32 space = (deltaX - extentX) / (mSelectedControls.size() - 1);
- S32 curX = minX;
- for(k = sortedList.begin(); k != sortedList.end(); k++)
- {
- if( !( *k )->isLocked() )
- (*k)->setLeft( curX );
- curX += (*k)->getWidth() + space;
- }
- }
- break;
- }
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::cloneSelection()
- {
- Vector< GuiControl* > newSelection;
-
- // Clone the controls in the current selection.
-
- const U32 numOldControls = mSelectedControls.size();
- for( U32 i = 0; i < numOldControls; ++ i )
- {
- GuiControl* ctrl = mSelectedControls[ i ];
-
- // If parent is in selection, too, skip to prevent multiple clones.
-
- if( ctrl->getParent() && selectionContains( ctrl->getParent() ) )
- continue;
-
- // Clone and add to set.
-
- GuiControl* clone = dynamic_cast< GuiControl* >( ctrl->deepClone() );
- if( clone )
- newSelection.push_back( clone );
- }
-
- // Exchange the selection set.
-
- clearSelection();
- const U32 numNewControls = newSelection.size();
- for( U32 i = 0; i < numNewControls; ++ i )
- addSelection( newSelection[ i ] );
-
- // Callback for undo.
-
- onSelectionCloned_callback( getSelectedSet() );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::deleteSelection()
- {
- // Notify script for undo.
-
- onTrashSelection_callback( getSelectedSet() );
-
- // Move all objects in selection to trash.
- Vector< GuiControl* >::iterator i;
- for( i = mSelectedControls.begin(); i != mSelectedControls.end(); i ++ )
- {
- if( ( *i ) == getCurrentAddSet() )
- setCurrentAddSet( getContentControl(), false );
-
- mTrash->addObject( *i );
- }
-
- clearSelection();
-
- // Notify script it needs to update its views.
-
- onHierarchyChanged_callback();
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::loadSelection( const char* filename )
- {
- // Set redefine behavior to rename.
-
- const char* oldRedefineBehavior = Con::getVariable( "$Con::redefineBehavior" );
- Con::setVariable( "$Con::redefineBehavior", "renameNew" );
-
- // Exec the file or clipboard contents with the saved selection set.
- if( filename )
- Con::executef( "exec", filename );
- else
- Con::evaluate( Platform::getClipboard() );
-
- SimSet* set;
- if( !Sim::findObject( "guiClipboard", set ) )
- {
- if( filename )
- Con::errorf( "GuiEditCtrl::loadSelection() - could not find 'guiClipboard' in '%s'", filename );
- else
- Con::errorf( "GuiEditCtrl::loadSelection() - could not find 'guiClipboard'" );
- return;
- }
-
- // Restore redefine behavior.
-
- Con::setVariable( "$Con::redefineBehavior", oldRedefineBehavior );
-
- // Add the objects in the set.
- if( set->size() )
- {
- clearSelection();
- GuiControlVector ctrls;
- for( U32 i = 0, num = set->size(); i < num; ++ i )
- {
- GuiControl *ctrl = dynamic_cast< GuiControl* >( ( *set )[ i ] );
- if( ctrl )
- {
- getCurrentAddSet()->addObject( ctrl );
- ctrls.push_back( ctrl );
- }
- }
-
- // Select all controls. We need to perform this here rather than in the
- // loop above as addSelection() will modify the current add set.
- for( U32 i = 0; i < ctrls.size(); ++ i )
- {
- addSelection( ctrls[i] );
- }
- // Undo
- onAddNewCtrlSet_callback( getSelectedSet() );
- // Notify the script it needs to update its treeview.
- onHierarchyChanged_callback();
- }
- set->deleteObject();
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::saveSelection( const char* filename )
- {
- // If there are no selected objects, then don't save.
-
- if( mSelectedControls.size() == 0 )
- return;
-
- // Open the stream.
- Stream* stream;
- if( filename )
- {
- stream = FileStream::createAndOpen( filename, Torque::FS::File::Write );
- if( !stream )
- {
- Con::errorf( "GuiEditCtrl::saveSelection - could not open '%s' for writing", filename );
- return;
- }
- }
- else
- stream = new MemStream( 4096 );
-
- // Create a temporary SimSet.
-
- SimSet* clipboardSet = new SimSet;
- clipboardSet->registerObject();
- Sim::getRootGroup()->addObject( clipboardSet, "guiClipboard" );
-
- // Add the selected controls to the set.
- for( Vector< GuiControl* >::iterator i = mSelectedControls.begin();
- i != mSelectedControls.end(); ++ i )
- {
- GuiControl* ctrl = *i;
- if( !selectionContainsParentOf( ctrl ) )
- clipboardSet->addObject( ctrl );
- }
-
- // Write the SimSet. Use the IgnoreCanSave to ensure the controls
- // get actually written out (also disables the default parent inheritance
- // behavior for the flag).
- clipboardSet->write( *stream, 0, IgnoreCanSave );
- clipboardSet->deleteObject();
-
- // If we were writing to a memory stream, copy to clipboard
- // now.
-
- if( !filename )
- {
- MemStream* memStream = static_cast< MemStream* >( stream );
- memStream->write( U8( 0 ) );
- Platform::setClipboard( ( const char* ) memStream->getBuffer() );
- }
- delete stream;
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::selectAll()
- {
- GuiControl::iterator i;
-
- clearSelection();
- for(i = getCurrentAddSet()->begin(); i != getCurrentAddSet()->end(); i++)
- {
- GuiControl *ctrl = dynamic_cast<GuiControl *>(*i);
- addSelection( ctrl );
- }
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::bringToFront()
- {
- if( getNumSelected() != 1 )
- return;
- GuiControl* ctrl = mSelectedControls.first();
- ctrl->getParent()->pushObjectToBack( ctrl );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::pushToBack()
- {
- if( getNumSelected() != 1 )
- return;
- GuiControl* ctrl = mSelectedControls.first();
- ctrl->getParent()->bringObjectToFront( ctrl );
- }
- //-----------------------------------------------------------------------------
- RectI GuiEditCtrl::getSelectionBounds() const
- {
- Vector<GuiControl *>::const_iterator i = mSelectedControls.begin();
-
- Point2I minPos = (*i)->localToGlobalCoord( Point2I( 0, 0 ) );
- Point2I maxPos = minPos;
-
- for(; i != mSelectedControls.end(); i++)
- {
- Point2I iPos = (**i).localToGlobalCoord( Point2I( 0 , 0 ) );
-
- minPos.x = getMin( iPos.x, minPos.x );
- minPos.y = getMin( iPos.y, minPos.y );
-
- Point2I iExt = ( **i ).getExtent();
-
- iPos.x += iExt.x;
- iPos.y += iExt.y;
- maxPos.x = getMax( iPos.x, maxPos.x );
- maxPos.y = getMax( iPos.y, maxPos.y );
- }
-
- minPos = getContentControl()->globalToLocalCoord( minPos );
- maxPos = getContentControl()->globalToLocalCoord( maxPos );
-
- return RectI( minPos.x, minPos.y, ( maxPos.x - minPos.x ), ( maxPos.y - minPos.y ) );
- }
- //-----------------------------------------------------------------------------
- RectI GuiEditCtrl::getSelectionGlobalBounds() const
- {
- Point2I minb( S32_MAX, S32_MAX );
- Point2I maxb( S32_MIN, S32_MIN );
-
- for( U32 i = 0, num = mSelectedControls.size(); i < num; ++ i )
- {
- // Min.
- Point2I pos = mSelectedControls[ i ]->localToGlobalCoord( Point2I( 0, 0 ) );
-
- minb.x = getMin( minb.x, pos.x );
- minb.y = getMin( minb.y, pos.y );
-
- // Max.
-
- const Point2I extent = mSelectedControls[ i ]->getExtent();
-
- maxb.x = getMax( maxb.x, pos.x + extent.x );
- maxb.y = getMax( maxb.y, pos.y + extent.y );
- }
-
- RectI bounds( minb.x, minb.y, maxb.x - minb.x, maxb.y - minb.y );
- return bounds;
- }
- //-----------------------------------------------------------------------------
- bool GuiEditCtrl::selectionContains( GuiControl *ctrl )
- {
- Vector<GuiControl *>::iterator i;
- for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- if (ctrl == *i) return true;
- return false;
- }
- //-----------------------------------------------------------------------------
- bool GuiEditCtrl::selectionContainsParentOf( GuiControl* ctrl )
- {
- GuiControl* parent = ctrl->getParent();
- while( parent && parent != getContentControl() )
- {
- if( selectionContains( parent ) )
- return true;
-
- parent = parent->getParent();
- }
-
- return false;
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::select( GuiControl* ctrl )
- {
- clearSelection();
- addSelection( ctrl );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::updateSelectedSet()
- {
- mSelectedSet->clear();
- Vector<GuiControl*>::iterator i;
- for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
- {
- mSelectedSet->addObject(*i);
- }
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::addSelectControlsInRegion( const RectI& rect, U32 flags )
- {
- // Do a hit test on the content control.
-
- canHitSelectedControls( false );
- Vector< GuiControl* > hits;
-
- if( mFullBoxSelection )
- flags |= GuiControl::HIT_FullBoxOnly;
-
- getContentControl()->findHitControls( rect, hits, flags );
- canHitSelectedControls( true );
-
- // Add all controls that got hit.
-
- for( U32 i = 0, num = hits.size(); i < num; ++ i )
- addSelection( hits[ i ] );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::addSelectControlAt( const Point2I& pos )
- {
- // Run a hit test.
-
- canHitSelectedControls( false );
- GuiControl* hit = getContentControl()->findHitControl( pos );
- canHitSelectedControls( true );
-
- // Add to selection.
-
- if( hit )
- addSelection( hit );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::resizeControlsInSelectionBy( const Point2I& delta, U32 mode )
- {
- for( U32 i = 0, num = mSelectedControls.size(); i < num; ++ i )
- {
- GuiControl *ctrl = mSelectedControls[ i ];
- if( ctrl->isLocked() )
- continue;
-
- Point2I minExtent = ctrl->getMinExtent();
- Point2I newPosition = ctrl->getPosition();
- Point2I newExtent = ctrl->getExtent();
- if( mSizingMode & sizingLeft )
- {
- newPosition.x += delta.x;
- newExtent.x -= delta.x;
-
- if( newExtent.x < minExtent.x )
- {
- newPosition.x -= minExtent.x - newExtent.x;
- newExtent.x = minExtent.x;
- }
- }
- else if( mSizingMode & sizingRight )
- {
- newExtent.x += delta.x;
- if( newExtent.x < minExtent.x )
- newExtent.x = minExtent.x;
- }
- if( mSizingMode & sizingTop )
- {
- newPosition.y += delta.y;
- newExtent.y -= delta.y;
-
- if( newExtent.y < minExtent.y )
- {
- newPosition.y -= minExtent.y - newExtent.y;
- newExtent.y = minExtent.y;
- }
- }
- else if( mSizingMode & sizingBottom )
- {
- newExtent.y += delta.y;
-
- if( newExtent.y < minExtent.y )
- newExtent.y = minExtent.y;
- }
-
- ctrl->resize( newPosition, newExtent );
- }
-
- if( mSelectedControls.size() == 1 )
- onSelectionResized_callback( mSelectedControls[ 0 ] );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::fitIntoParents( bool width, bool height )
- {
- // Record undo.
-
- onFitIntoParent_callback( width, height );
-
- // Fit.
-
- for( U32 i = 0; i < mSelectedControls.size(); ++ i )
- {
- GuiControl* ctrl = mSelectedControls[ i ];
- GuiControl* parent = ctrl->getParent();
-
- Point2I position = ctrl->getPosition();
- if( width )
- position.x = 0;
- if( height )
- position.y = 0;
-
- Point2I extents = ctrl->getExtent();
- if( width )
- extents.x = parent->getWidth();
- if( height )
- extents.y = parent->getHeight();
-
- ctrl->resize( position, extents );
- }
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::selectParents( bool addToSelection )
- {
- Vector< GuiControl* > parents;
-
- // Collect all parents.
-
- for( U32 i = 0; i < mSelectedControls.size(); ++ i )
- {
- GuiControl* ctrl = mSelectedControls[ i ];
- if( ctrl != mContentControl && ctrl->getParent() != mContentControl )
- parents.push_back( mSelectedControls[ i ]->getParent() );
- }
-
- // If there's no parents to select, don't
- // change the selection.
-
- if( parents.empty() )
- return;
-
- // Blast selection if need be.
-
- if( !addToSelection )
- clearSelection();
-
- // Add the parents.
-
- for( U32 i = 0; i < parents.size(); ++ i )
- addSelection( parents[ i ] );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::selectChildren( bool addToSelection )
- {
- Vector< GuiControl* > children;
-
- // Collect all children.
-
- for( U32 i = 0; i < mSelectedControls.size(); ++ i )
- {
- GuiControl* parent = mSelectedControls[ i ];
- for( GuiControl::iterator iter = parent->begin(); iter != parent->end(); ++ iter )
- {
- GuiControl* child = dynamic_cast< GuiControl* >( *iter );
- if( child )
- children.push_back( child );
- }
- }
-
- // If there's no children to select, don't
- // change the selection.
-
- if( children.empty() )
- return;
- // Blast selection if need be.
-
- if( !addToSelection )
- clearSelection();
-
- // Add the children.
-
- for( U32 i = 0; i < children.size(); ++ i )
- addSelection( children[ i ] );
- }
- //=============================================================================
- // Guides.
- //=============================================================================
- // MARK: ---- Guides ----
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::readGuides( guideAxis axis, GuiControl* ctrl )
- {
- // Read the guide indices from the vector stored on the respective dynamic
- // property of the control.
-
- const char* guideIndices = ctrl->getDataField( smGuidesPropertyName[ axis ], NULL );
- if( guideIndices && guideIndices[ 0 ] )
- {
- U32 index = 0;
- while( true )
- {
- const char* posStr = StringUnit::getUnit( guideIndices, index, " \t" );
- if( !posStr[ 0 ] )
- break;
-
- mGuides[ axis ].push_back( dAtoi( posStr ) );
-
- index ++;
- }
- }
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::writeGuides( guideAxis axis, GuiControl* ctrl )
- {
- // Store the guide indices of the given axis in a vector on the respective
- // dynamic property of the control.
-
- StringBuilder str;
- bool isFirst = true;
- for( U32 i = 0, num = mGuides[ axis ].size(); i < num; ++ i )
- {
- if( !isFirst )
- str.append( ' ' );
-
- char buffer[ 32 ];
- dSprintf( buffer, sizeof( buffer ), "%i", mGuides[ axis ][ i ] );
-
- str.append( buffer );
-
- isFirst = false;
- }
-
- String value = str.end();
- ctrl->setDataField( smGuidesPropertyName[ axis ], NULL, value );
- }
- //-----------------------------------------------------------------------------
- S32 GuiEditCtrl::findGuide( guideAxis axis, const Point2I& point, U32 tolerance )
- {
- const S32 p = ( point - localToGlobalCoord( Point2I( 0, 0 ) ) )[ axis ];
-
- for( U32 i = 0, num = mGuides[ axis ].size(); i < num; ++ i )
- {
- const S32 g = mGuides[ axis ][ i ];
- if( p >= ( g - tolerance ) &&
- p <= ( g + tolerance ) )
- return i;
- }
-
- return -1;
- }
- //=============================================================================
- // Snapping.
- //=============================================================================
- // MARK: ---- Snapping ----
- //-----------------------------------------------------------------------------
- RectI GuiEditCtrl::getSnapRegion( snappingAxis axis, const Point2I& center ) const
- {
- RectI rootBounds = getContentControl()->getBounds();
-
- RectI rect;
- if( axis == SnapHorizontal )
- rect = RectI( rootBounds.point.x,
- center.y - mSnapSensitivity,
- rootBounds.extent.x,
- mSnapSensitivity * 2 );
- else // SnapVertical
- rect = RectI( center.x - mSnapSensitivity,
- rootBounds.point.y,
- mSnapSensitivity * 2,
- rootBounds.extent.y );
-
- // Clip against root bounds.
-
- rect.intersect( rootBounds );
-
- return rect;
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::registerSnap( snappingAxis axis, const Point2I& mousePoint, const Point2I& point, snappingEdges edge, GuiControl* ctrl )
- {
- bool takeNewSnap = false;
- const Point2I globalPoint = getContentControl()->localToGlobalCoord( point );
- // If we have no snap yet, just take this one.
-
- if( !mSnapped[ axis ] )
- takeNewSnap = true;
-
- // Otherwise see if this snap is the better one.
-
- else
- {
- // Compare deltas to pointer.
-
- S32 deltaCurrent = mAbs( mSnapOffset[ axis ] - mousePoint[ axis ] );
- S32 deltaNew = mAbs( globalPoint[ axis ] - mousePoint[ axis ] );
-
- if( deltaCurrent > deltaNew )
- takeNewSnap = true;
- }
- if( takeNewSnap )
- {
- mSnapped[ axis ] = true;
- mSnapOffset[ axis ] = globalPoint[ axis ];
- mSnapEdge[ axis ] = edge;
- mSnapTargets[ axis ] = ctrl;
- }
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::findSnaps( snappingAxis axis, const Point2I& mousePoint, const RectI& minRegion, const RectI& midRegion, const RectI& maxRegion )
- {
- // Find controls with edge in either minRegion, midRegion, or maxRegion
- // (depending on snap settings).
-
- for( U32 i = 0, num = mSnapHits[ axis ].size(); i < num; ++ i )
- {
- GuiControl* ctrl = mSnapHits[ axis ][ i ];
- if( ctrl == getContentControl() && !mSnapToCanvas )
- continue;
-
- RectI bounds = ctrl->getGlobalBounds();
- bounds.point = getContentControl()->globalToLocalCoord( bounds.point );
-
- // Compute points on min, mid, and max lines of control.
-
- Point2I min = bounds.point;
- Point2I max = min + bounds.extent - Point2I( 1, 1 );
- Point2I mid = min;
- mid.x += bounds.extent.x / 2;
- mid.y += bounds.extent.y / 2;
-
- // Test edge snap cases.
-
- if( mSnapToEdges )
- {
- // Min to min.
-
- if( minRegion.pointInRect( min ) )
- registerSnap( axis, mousePoint, min, SnapEdgeMin, ctrl );
-
- // Max to max.
-
- if( maxRegion.pointInRect( max ) )
- registerSnap( axis, mousePoint, max, SnapEdgeMax, ctrl );
-
- // Min to max.
-
- if( minRegion.pointInRect( max ) )
- registerSnap( axis, mousePoint, max, SnapEdgeMin, ctrl );
-
- // Max to min.
-
- if( maxRegion.pointInRect( min ) )
- registerSnap( axis, mousePoint, min, SnapEdgeMax, ctrl );
- }
-
- // Test center snap cases.
-
- if( mSnapToCenters )
- {
- // Mid to mid.
-
- if( midRegion.pointInRect( mid ) )
- registerSnap( axis, mousePoint, mid, SnapEdgeMid, ctrl );
- }
-
- // Test combined center+edge snap cases.
-
- if( mSnapToEdges && mSnapToCenters )
- {
- // Min to mid.
-
- if( minRegion.pointInRect( mid ) )
- registerSnap( axis, mousePoint, mid, SnapEdgeMin, ctrl );
-
- // Max to mid.
-
- if( maxRegion.pointInRect( mid ) )
- registerSnap( axis, mousePoint, mid, SnapEdgeMax, ctrl );
-
- // Mid to min.
-
- if( midRegion.pointInRect( min ) )
- registerSnap( axis, mousePoint, min, SnapEdgeMid, ctrl );
-
- // Mid to max.
-
- if( midRegion.pointInRect( max ) )
- registerSnap( axis, mousePoint, max, SnapEdgeMid, ctrl );
- }
- }
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::doControlSnap( const GuiEvent& event, const RectI& selectionBounds, const RectI& selectionBoundsGlobal, Point2I& delta )
- {
- if( !mSnapToControls || ( !mSnapToEdges && !mSnapToCenters ) )
- return;
-
- // Allow restricting to just vertical (ALT+SHIFT) or just horizontal (ALT+CTRL)
- // snaps.
-
- bool snapAxisEnabled[ 2 ];
-
- if( event.modifier & SI_PRIMARY_ALT && event.modifier & SI_SHIFT )
- snapAxisEnabled[ SnapHorizontal ] = false;
- else
- snapAxisEnabled[ SnapHorizontal ] = true;
-
- if( event.modifier & SI_PRIMARY_ALT && event.modifier & SI_CTRL )
- snapAxisEnabled[ SnapVertical ] = false;
- else
- snapAxisEnabled[ SnapVertical ] = true;
-
- // Compute snap regions. There is one region centered on and aligned with
- // each of the selection bounds edges plus two regions aligned on the selection
- // bounds center. For the selection bounds origin, we use the point that the
- // selection would be at, if we had already done the mouse drag.
-
- RectI snapRegions[ 2 ][ 3 ];
- Point2I projectedOrigin( selectionBounds.point + delta );
- dMemset( snapRegions, 0, sizeof( snapRegions ) );
-
- for( U32 axis = 0; axis < 2; ++ axis )
- {
- if( !snapAxisEnabled[ axis ] )
- continue;
-
- if( mSizingMode == sizingNone ||
- ( axis == 0 && mSizingMode & sizingLeft ) ||
- ( axis == 1 && mSizingMode & sizingTop ) )
- snapRegions[ axis ][ 0 ] = getSnapRegion( ( snappingAxis ) axis, projectedOrigin );
-
- if( mSizingMode == sizingNone )
- snapRegions[ axis ][ 1 ] = getSnapRegion( ( snappingAxis ) axis, projectedOrigin + Point2I( selectionBounds.extent.x / 2, selectionBounds.extent.y / 2 ) );
-
- if( mSizingMode == sizingNone ||
- ( axis == 0 && mSizingMode & sizingRight ) ||
- ( axis == 1 && mSizingMode & sizingBottom ) )
- snapRegions[ axis ][ 2 ] = getSnapRegion( ( snappingAxis ) axis, projectedOrigin + selectionBounds.extent - Point2I( 1, 1 ) );
- }
-
- // Find hit controls.
-
- canHitSelectedControls( false );
-
- if( mSnapToEdges )
- {
- for( U32 axis = 0; axis < 2; ++ axis )
- if( snapAxisEnabled[ axis ] )
- {
- getContentControl()->findHitControls( snapRegions[ axis ][ 0 ], mSnapHits[ axis ], HIT_NoCanHitNoRecurse );
- getContentControl()->findHitControls( snapRegions[ axis ][ 2 ], mSnapHits[ axis ], HIT_NoCanHitNoRecurse );
- }
- }
- if( mSnapToCenters && mSizingMode == sizingNone )
- {
- for( U32 axis = 0; axis < 2; ++ axis )
- if( snapAxisEnabled[ axis ] )
- getContentControl()->findHitControls( snapRegions[ axis ][ 1 ], mSnapHits[ axis ], HIT_NoCanHitNoRecurse );
- }
-
- canHitSelectedControls( true );
-
- // Add the content control itself to the hit controls
- // so we can always get a snap on it.
-
- if( mSnapToCanvas )
- {
- mSnapHits[ 0 ].push_back( mContentControl );
- mSnapHits[ 1 ].push_back( mContentControl );
- }
-
- // Find snaps.
-
- for( U32 i = 0; i < 2; ++ i )
- if( snapAxisEnabled[ i ] )
- findSnaps( ( snappingAxis ) i,
- event.mousePoint,
- snapRegions[ i ][ 0 ],
- snapRegions[ i ][ 1 ],
- snapRegions[ i ][ 2 ] );
-
- // Clean up.
-
- mSnapHits[ 0 ].clear();
- mSnapHits[ 1 ].clear();
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::doGridSnap( const GuiEvent& event, const RectI& selectionBounds, const RectI& selectionBoundsGlobal, Point2I& delta )
- {
- delta += selectionBounds.point;
-
- if( mGridSnap.x )
- delta.x -= delta.x % mGridSnap.x;
- if( mGridSnap.y )
- delta.y -= delta.y % mGridSnap.y;
- delta -= selectionBounds.point;
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::doGuideSnap( const GuiEvent& event, const RectI& selectionBounds, const RectI& selectionBoundsGlobal, Point2I& delta )
- {
- if( !mSnapToGuides )
- return;
-
- Point2I min = getContentControl()->localToGlobalCoord( selectionBounds.point + delta );
- Point2I mid = min + selectionBounds.extent / 2;
- Point2I max = min + selectionBounds.extent - Point2I( 1, 1 );
-
- for( U32 axis = 0; axis < 2; ++ axis )
- {
- if( mSnapToEdges )
- {
- S32 guideMin = -1;
- S32 guideMax = -1;
-
- if( mSizingMode == sizingNone ||
- ( axis == 0 && mSizingMode & sizingLeft ) ||
- ( axis == 1 && mSizingMode & sizingTop ) )
- guideMin = findGuide( ( guideAxis ) axis, min, mSnapSensitivity );
- if( mSizingMode == sizingNone ||
- ( axis == 0 && mSizingMode & sizingRight ) ||
- ( axis == 1 && mSizingMode & sizingBottom ) )
- guideMax = findGuide( ( guideAxis ) axis, max, mSnapSensitivity );
-
- Point2I pos( 0, 0 );
-
- if( guideMin != -1 )
- {
- pos[ axis ] = mGuides[ axis ][ guideMin ];
- registerSnap( ( snappingAxis ) axis, event.mousePoint, pos, SnapEdgeMin );
- }
-
- if( guideMax != -1 )
- {
- pos[ axis ] = mGuides[ axis ][ guideMax ];
- registerSnap( ( snappingAxis ) axis, event.mousePoint, pos, SnapEdgeMax );
- }
- }
-
- if( mSnapToCenters && mSizingMode == sizingNone )
- {
- const S32 guideMid = findGuide( ( guideAxis ) axis, mid, mSnapSensitivity );
- if( guideMid != -1 )
- {
- Point2I pos( 0, 0 );
- pos[ axis ] = mGuides[ axis ][ guideMid ];
- registerSnap( ( snappingAxis ) axis, event.mousePoint, pos, SnapEdgeMid );
- }
- }
- }
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::doSnapping( const GuiEvent& event, const RectI& selectionBounds, Point2I& delta )
- {
- // Clear snapping. If we have snapping on, we want to find a new best snap.
-
- mSnapped[ SnapVertical ] = false;
- mSnapped[ SnapHorizontal ] = false;
-
- // Compute global bounds.
-
- RectI selectionBoundsGlobal = selectionBounds;
- selectionBoundsGlobal.point = getContentControl()->localToGlobalCoord( selectionBoundsGlobal.point );
- // Apply the snaps.
-
- doGridSnap( event, selectionBounds, selectionBoundsGlobal, delta );
- doGuideSnap( event, selectionBounds, selectionBoundsGlobal, delta );
- doControlSnap( event, selectionBounds, selectionBoundsGlobal, delta );
- // If we have a horizontal snap, compute a delta.
- if( mSnapped[ SnapVertical ] )
- snapDelta( SnapVertical, mSnapEdge[ SnapVertical ], mSnapOffset[ SnapVertical ], selectionBoundsGlobal, delta );
-
- // If we have a vertical snap, compute a delta.
-
- if( mSnapped[ SnapHorizontal ] )
- snapDelta( SnapHorizontal, mSnapEdge[ SnapHorizontal ], mSnapOffset[ SnapHorizontal ], selectionBoundsGlobal, delta );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::snapToGrid( Point2I& point )
- {
- if( mGridSnap.x )
- point.x -= point.x % mGridSnap.x;
- if( mGridSnap.y )
- point.y -= point.y % mGridSnap.y;
- }
- //=============================================================================
- // Misc.
- //=============================================================================
- // MARK: ---- Misc ----
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::setContentControl(GuiControl *root)
- {
- mContentControl = root;
- if( root != NULL )
- root->mIsContainer = true;
-
- setCurrentAddSet( root );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::setEditMode(bool value)
- {
- mActive = value;
- clearSelection();
- if( mActive && mAwake )
- mCurrentAddSet = NULL;
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::setMouseMode( mouseModes mode )
- {
- if( mMouseDownMode != mode )
- {
- mMouseDownMode = mode;
- onMouseModeChange_callback();
- }
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::setCurrentAddSet(GuiControl *ctrl, bool doclearSelection)
- {
- if (ctrl != mCurrentAddSet)
- {
- if(doclearSelection)
- clearSelection();
- mCurrentAddSet = ctrl;
- }
- }
- //-----------------------------------------------------------------------------
- GuiControl* GuiEditCtrl::getCurrentAddSet()
- {
- if( !mCurrentAddSet )
- setCurrentAddSet( mContentControl, false );
-
- return mCurrentAddSet;
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::addNewControl(GuiControl *ctrl)
- {
- getCurrentAddSet()->addObject(ctrl);
- select( ctrl );
- // undo
- onAddNewCtrl_callback( ctrl );
- }
- //-----------------------------------------------------------------------------
- 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::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::getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent)
- {
- GuiCanvas *pRoot = getRoot();
- if( !pRoot )
- return;
- showCursor = false;
- cursor = NULL;
-
- Point2I ctOffset;
- Point2I cext;
- GuiControl *ctrl;
- Point2I mousePos = globalToLocalCoord(lastGuiEvent.mousePoint);
- PlatformWindow *pWindow = static_cast<GuiCanvas*>(getRoot())->getPlatformWindow();
- AssertFatal(pWindow != NULL,"GuiControl without owning platform window! This should not be possible.");
- PlatformCursorController *pController = pWindow->getCursorController();
- AssertFatal(pController != NULL,"PlatformWindow without an owned CursorController!");
- S32 desiredCursor = PlatformCursorController::curArrow;
- // 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);
- GuiEditCtrl::sizingModes sizeMode = (GuiEditCtrl::sizingModes)getSizingHitKnobs(mousePos, box);
- if( mMouseDownMode == SizingSelection )
- {
- if ( ( mSizingMode == ( sizingBottom | sizingRight ) ) || ( mSizingMode == ( sizingTop | sizingLeft ) ) )
- desiredCursor = PlatformCursorController::curResizeNWSE;
- else if ( ( mSizingMode == ( sizingBottom | sizingLeft ) ) || ( mSizingMode == ( sizingTop | sizingRight ) ) )
- desiredCursor = PlatformCursorController::curResizeNESW;
- else if ( mSizingMode == sizingLeft || mSizingMode == sizingRight )
- desiredCursor = PlatformCursorController::curResizeVert;
- else if (mSizingMode == sizingTop || mSizingMode == sizingBottom )
- desiredCursor = PlatformCursorController::curResizeHorz;
- }
- else
- {
- // Check for current mouse position after checking for actual sizing mode
- if ( ( sizeMode == ( sizingBottom | sizingRight ) ) || ( sizeMode == ( sizingTop | sizingLeft ) ) )
- desiredCursor = PlatformCursorController::curResizeNWSE;
- else if ( ( sizeMode == ( sizingBottom | sizingLeft ) ) || ( sizeMode == ( sizingTop | sizingRight ) ) )
- desiredCursor = PlatformCursorController::curResizeNESW;
- else if (sizeMode == sizingLeft || sizeMode == sizingRight )
- desiredCursor = PlatformCursorController::curResizeVert;
- else if (sizeMode == sizingTop || sizeMode == sizingBottom )
- desiredCursor = PlatformCursorController::curResizeHorz;
- }
- }
-
- if( mMouseDownMode == MovingSelection && cursor == NULL )
- desiredCursor = PlatformCursorController::curResizeAll;
- if( pRoot->mCursorChanged != desiredCursor )
- {
- // We've already changed the cursor,
- // so set it back before we change it again.
- if(pRoot->mCursorChanged != -1)
- pController->popCursor();
- // Now change the cursor shape
- pController->pushCursor(desiredCursor);
- pRoot->mCursorChanged = desiredCursor;
- }
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::setSnapToGrid(U32 gridsize)
- {
- if( gridsize != 0 )
- gridsize = getMax( gridsize, ( U32 ) MIN_GRID_SIZE );
- mGridSnap.set( gridsize, gridsize );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::controlInspectPreApply(GuiControl* object)
- {
- // undo
- onControlInspectPreApply_callback( object );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::controlInspectPostApply(GuiControl* object)
- {
- // undo
- onControlInspectPostApply_callback( object );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::startDragMove( const Point2I& startPoint )
- {
- mDragMoveUndo = true;
-
- // For calculating mouse delta
- mDragBeginPoint = globalToLocalCoord( startPoint );
- // 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)->getPosition() );
- // Set Mouse Mode
- setMouseMode( MovingSelection );
-
- // undo
- onPreEdit_callback( getSelectedSet() );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::startDragRectangle( const Point2I& startPoint )
- {
- mSelectionAnchor = globalToLocalCoord( startPoint );
- setMouseMode( DragSelecting );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::startDragClone( const Point2I& startPoint )
- {
- mDragBeginPoint = globalToLocalCoord( startPoint );
-
- setMouseMode( DragClone );
- }
- //-----------------------------------------------------------------------------
- void GuiEditCtrl::startMouseGuideDrag( guideAxis axis, U32 guideIndex, bool lockMouse )
- {
- mDragGuideIndex[ axis ] = guideIndex;
- mDragGuide[ axis ] = true;
-
- setMouseMode( DragGuide );
-
- // Grab the mouse.
-
- if( lockMouse )
- mouseLock();
- }
- //=============================================================================
- // Console Methods.
- //=============================================================================
- // MARK: ---- Console Methods ----
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, getContentControl, S32, (), , "() - Return the toplevel control edited inside the GUI editor." )
- {
- GuiControl* ctrl = object->getContentControl();
- if( ctrl )
- return ctrl->getId();
- else
- return 0;
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, setContentControl, void, (GuiControl *ctrl ), , "( GuiControl ctrl ) - Set the toplevel control to edit in the GUI editor." )
- {
- if (ctrl)
- object->setContentControl(ctrl);
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, addNewCtrl, void, (GuiControl *ctrl), , "(GuiControl ctrl)")
- {
- if (ctrl)
- object->addNewControl(ctrl);
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, addSelection, void, (S32 id), , "selects a control.")
- {
- object->addSelection(id);
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, removeSelection, void, (S32 id), , "deselects a control.")
- {
- object->removeSelection(id);
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, clearSelection, void, (), , "Clear selected controls list.")
- {
- object->clearSelection();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, select, void, (GuiControl *ctrl), , "(GuiControl ctrl)")
- {
- if (ctrl)
- object->setSelection(ctrl, false);
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, setCurrentAddSet, void, (GuiControl *addSet), , "(GuiControl ctrl)")
- {
- if (addSet)
- object->setCurrentAddSet(addSet);
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, getCurrentAddSet, S32, (), , "Returns the set to which new controls will be added")
- {
- const GuiControl* add = object->getCurrentAddSet();
- return add ? add->getId() : 0;
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, toggle, void, (), , "Toggle activation.")
- {
- object->setEditMode( !object->isActive() );
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, justify, void, (U32 mode), , "(int mode)" )
- {
- object->justifySelection( (GuiEditCtrl::Justification)mode );
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, bringToFront, void, (), , "")
- {
- object->bringToFront();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, pushToBack, void, (), , "")
- {
- object->pushToBack();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, deleteSelection, void, (), , "() - Delete the selected controls.")
- {
- object->deleteSelection();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, moveSelection, void, (S32 dx, S32 dy), , "Move all controls in the selection by (dx,dy) pixels.")
- {
- object->moveAndSnapSelection(Point2I(dx, dy));
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, saveSelection, void, (const char * filename), (nullAsType<const char*>()), "( string fileName=null ) - Save selection to file or clipboard.")
- {
-
- object->saveSelection( filename );
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, loadSelection, void, (const char * filename), (nullAsType<const char*>()), "( string fileName=null ) - Load selection from file or clipboard.")
- {
- object->loadSelection( filename );
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, selectAll, void, (), , "()")
- {
- object->selectAll();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, getSelection, SimSet*, (),,
- "Gets the set of GUI controls currently selected in the editor." )
- {
- return object->getSelectedSet();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, getNumSelected, S32, (), , "() - Return the number of controls currently selected." )
- {
- return object->getNumSelected();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, getSelectionGlobalBounds, const char*, (), , "() - Returns global bounds of current selection as vector 'x y width height'." )
- {
- RectI bounds = object->getSelectionGlobalBounds();
- String str = String::ToString( "%i %i %i %i", bounds.point.x, bounds.point.y, bounds.extent.x, bounds.extent.y );
-
- char* buffer = Con::getReturnBuffer( str.size() );
- dStrcpy( buffer, str.c_str(), str.size() );
-
- return buffer;
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, selectParents, void, ( bool addToSelection ), (false), "( bool addToSelection=false ) - Select parents of currently selected controls." )
- {
-
- object->selectParents( addToSelection );
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, selectChildren, void, ( bool addToSelection ), (false), "( bool addToSelection=false ) - Select children of currently selected controls." )
- {
-
- object->selectChildren( addToSelection );
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, getTrash, SimGroup*, (),,
- "Gets the GUI controls(s) that are currently in the trash.")
- {
- return object->getTrash();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod(GuiEditCtrl, setSnapToGrid, void, (U32 gridsize), , "GuiEditCtrl.setSnapToGrid(gridsize)")
- {
- object->setSnapToGrid(gridsize);
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, readGuides, void, ( GuiControl* ctrl, S32 axis ), (-1), "( GuiControl ctrl [, int axis ] ) - Read the guides from the given control." )
- {
- // Find the control.
-
- if( !ctrl )
- {
- return;
- }
-
- // Read the guides.
-
- if( axis != -1 )
- {
- if( axis < 0 || axis > 1 )
- {
- Con::errorf( "GuiEditCtrl::readGuides - invalid axis '%s'", axis );
- return;
- }
-
- object->readGuides( ( GuiEditCtrl::guideAxis ) axis, ctrl );
- }
- else
- {
- object->readGuides( GuiEditCtrl::GuideHorizontal, ctrl );
- object->readGuides( GuiEditCtrl::GuideVertical, ctrl );
- }
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, writeGuides, void, ( GuiControl* ctrl, S32 axis ), ( -1), "( GuiControl ctrl [, int axis ] ) - Write the guides to the given control." )
- {
- // Find the control.
-
- if( ! ctrl )
- {
- return;
- }
-
- // Write the guides.
-
- if( axis != -1 )
- {
- if( axis < 0 || axis > 1 )
- {
- Con::errorf( "GuiEditCtrl::writeGuides - invalid axis '%s'", axis );
- return;
- }
-
- object->writeGuides( ( GuiEditCtrl::guideAxis ) axis, ctrl );
- }
- else
- {
- object->writeGuides( GuiEditCtrl::GuideHorizontal, ctrl );
- object->writeGuides( GuiEditCtrl::GuideVertical, ctrl );
- }
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, clearGuides, void, ( S32 axis ), (-1), "( [ int axis ] ) - Clear all currently set guide lines." )
- {
- if( axis != -1 )
- {
- if( axis < 0 || axis > 1 )
- {
- Con::errorf( "GuiEditCtrl::clearGuides - invalid axis '%i'", axis );
- return;
- }
-
- object->clearGuides( ( GuiEditCtrl::guideAxis ) axis );
- }
- else
- {
- object->clearGuides( GuiEditCtrl::GuideHorizontal );
- object->clearGuides( GuiEditCtrl::GuideVertical );
- }
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, fitIntoParents, void, (bool width, bool height), (true, true), "( bool width=true, bool height=true ) - Fit selected controls into their parents." )
- {
-
- object->fitIntoParents( width, height );
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiEditCtrl, getMouseMode, const char*, (), , "() - Return the current mouse mode." )
- {
- switch( object->getMouseMode() )
- {
- case GuiEditCtrl::Selecting:
- return "Selecting";
-
- case GuiEditCtrl::DragSelecting:
- return "DragSelecting";
- case GuiEditCtrl::MovingSelection:
- return "MovingSelection";
-
- case GuiEditCtrl::SizingSelection:
- return "SizingSelection";
-
- case GuiEditCtrl::DragGuide:
- return "DragGuide";
-
- case GuiEditCtrl::DragClone:
- return "DragClone";
-
- default:
- return "";
- }
- }
- //=============================================================================
- // GuiEditorRuler.
- //=============================================================================
- class GuiEditorRuler : public GuiControl
- {
- public:
-
- typedef GuiControl Parent;
-
- protected:
-
- String mRefCtrlName;
- String mEditCtrlName;
-
- GuiScrollCtrl* mRefCtrl;
- GuiEditCtrl* mEditCtrl;
- public:
- enum EOrientation
- {
- ORIENTATION_Horizontal,
- ORIENTATION_Vertical
- };
-
- GuiEditorRuler()
- : mRefCtrl( 0 ),
- mEditCtrl( 0 )
- {
- }
-
- EOrientation getOrientation() const
- {
- if( getWidth() > getHeight() )
- return ORIENTATION_Horizontal;
- else
- return ORIENTATION_Vertical;
- }
-
- bool onWake()
- {
- if( !Parent::onWake() )
- return false;
-
- if( !mEditCtrlName.isEmpty() && !Sim::findObject( mEditCtrlName, mEditCtrl ) )
- Con::errorf( "GuiEditorRuler::onWake() - no GuiEditCtrl '%s'", mEditCtrlName.c_str() );
-
- if( !mRefCtrlName.isEmpty() && !Sim::findObject( mRefCtrlName, mRefCtrl ) )
- Con::errorf( "GuiEditorRuler::onWake() - no GuiScrollCtrl '%s'", mRefCtrlName.c_str() );
-
- return true;
- }
- void onPreRender()
- {
- setUpdate();
- }
-
- void onMouseDown( const GuiEvent& event )
- {
- if( !mEditCtrl )
- return;
-
- // Determine the guide axis.
-
- GuiEditCtrl::guideAxis axis;
- if( getOrientation() == ORIENTATION_Horizontal )
- axis = GuiEditCtrl::GuideHorizontal;
- else
- axis = GuiEditCtrl::GuideVertical;
-
- // Start dragging a new guide out in the editor.
-
- U32 guideIndex = mEditCtrl->addGuide( axis, 0 );
- mEditCtrl->startMouseGuideDrag( axis, guideIndex );
- }
-
- void onRender(Point2I offset, const RectI &updateRect)
- {
- GFX->getDrawUtil()->drawRectFill(updateRect, ColorI::WHITE);
-
- Point2I choffset(0,0);
- if( mRefCtrl != NULL )
- choffset = mRefCtrl->getChildPos();
- if( getOrientation() == ORIENTATION_Horizontal )
- {
- // it's horizontal.
- for(U32 i = 0; i < getWidth(); 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;
- GFX->getDrawUtil()->drawLine(x, offset.y + start, x, offset.y + 10, ColorI::BLACK);
- }
- }
- }
- else
- {
- // it's vertical.
- for(U32 i = 0; i < getHeight(); 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;
- GFX->getDrawUtil()->drawLine(offset.x + start, y, offset.x + 10, y, ColorI::BLACK);
- }
- }
- }
- }
- static void initPersistFields()
- {
- addField( "refCtrl", TypeRealString, Offset( mRefCtrlName, GuiEditorRuler ) );
- addField( "editCtrl", TypeRealString, Offset( mEditCtrlName, GuiEditorRuler ) );
-
- Parent::initPersistFields();
- }
-
- DECLARE_CONOBJECT(GuiEditorRuler);
- DECLARE_CATEGORY( "Gui Editor" );
- };
- IMPLEMENT_CONOBJECT(GuiEditorRuler);
- ConsoleDocClass( GuiEditorRuler,
- "@brief Visual representation of markers on top and left sides of GUI Editor\n\n"
- "Editor use only.\n\n"
- "@internal"
- );
|