12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936 |
- //-----------------------------------------------------------------------------
- // 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()
- {
- 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"
- );
|