guiEditCtrl.cpp
Engine/source/gui/editor/guiEditCtrl.cpp
Classes:
class
Public Variables
Public Functions
ConsoleDocClass(GuiEditCtrl , "@brief Native side of the GUI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">editor.\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
ConsoleDocClass(GuiEditorRuler , "@brief Visual representation of markers on top and left sides of GUI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Editor\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
DefineConsoleMethod(GuiEditCtrl , addNewCtrl , void , (GuiControl *ctrl) , "(GuiControl ctrl)" )
DefineConsoleMethod(GuiEditCtrl , addSelection , void , (S32 id) , "selects a control." )
DefineConsoleMethod(GuiEditCtrl , bringToFront , void , () , "" )
DefineConsoleMethod(GuiEditCtrl , clearGuides , void , (S32 axis) , (-1) , "( [ int axis ] ) - Clear all currently set guide lines." )
DefineConsoleMethod(GuiEditCtrl , clearSelection , void , () , "Clear selected controls list." )
DefineConsoleMethod(GuiEditCtrl , deleteSelection , void , () , "() - Delete the selected controls." )
DefineConsoleMethod(GuiEditCtrl , fitIntoParents , void , (bool width, bool height) , (true, true) , "( bool width=true, bool height=true ) - Fit selected controls into their parents." )
DefineConsoleMethod(GuiEditCtrl , getContentControl , S32 , () , "() - Return the toplevel <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> edited inside the GUI editor." )
DefineConsoleMethod(GuiEditCtrl , getCurrentAddSet , S32 , () , "Returns the set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> which <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> controls will be added" )
DefineConsoleMethod(GuiEditCtrl , getMouseMode , const char * , () , "() - Return the current mouse mode." )
DefineConsoleMethod(GuiEditCtrl , getNumSelected , S32 , () , "() - Return the number of controls currently selected." )
DefineConsoleMethod(GuiEditCtrl , getSelectionGlobalBounds , const char * , () , "() - Returns global bounds of current selection as vector 'x y width height'." )
DefineConsoleMethod(GuiEditCtrl , justify , void , (U32 mode) , "(int <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a>)" )
DefineConsoleMethod(GuiEditCtrl , loadSelection , void , (const char *filename) , (NULL) , "( string fileName=null ) - Load selection from <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> or clipboard." )
DefineConsoleMethod(GuiEditCtrl , moveSelection , void , (S32 dx, S32 dy) , "Move all controls in the selection by (dx,dy) pixels." )
DefineConsoleMethod(GuiEditCtrl , pushToBack , void , () , "" )
DefineConsoleMethod(GuiEditCtrl , readGuides , void , (GuiControl *ctrl, S32 axis) , (-1) , "( GuiControl ctrl [, int axis ] ) - Read the guides from the given control." )
DefineConsoleMethod(GuiEditCtrl , removeSelection , void , (S32 id) , "deselects a control." )
DefineConsoleMethod(GuiEditCtrl , saveSelection , void , (const char *filename) , (NULL) , "( string fileName=null ) - Save selection <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> or clipboard." )
DefineConsoleMethod(GuiEditCtrl , select , void , (GuiControl *ctrl) , "(GuiControl ctrl)" )
DefineConsoleMethod(GuiEditCtrl , selectAll , void , () , "()" )
DefineConsoleMethod(GuiEditCtrl , selectChildren , void , (bool addToSelection) , (false) , "( bool addToSelection=false ) - Select children of currently selected controls." )
DefineConsoleMethod(GuiEditCtrl , selectParents , void , (bool addToSelection) , (false) , "( bool addToSelection=false ) - Select parents of currently selected controls." )
DefineConsoleMethod(GuiEditCtrl , setContentControl , void , (GuiControl *ctrl) , "( GuiControl ctrl ) - Set the toplevel <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> edit in the GUI editor." )
DefineConsoleMethod(GuiEditCtrl , setCurrentAddSet , void , (GuiControl *addSet) , "(GuiControl ctrl)" )
DefineConsoleMethod(GuiEditCtrl , setSnapToGrid , void , (U32 gridsize) , "GuiEditCtrl.setSnapToGrid(gridsize)" )
DefineConsoleMethod(GuiEditCtrl , toggle , void , () , "Toggle activation." )
DefineConsoleMethod(GuiEditCtrl , writeGuides , void , (GuiControl *ctrl, S32 axis) , (-1) , "( GuiControl ctrl [, int axis ] ) - Write the guides <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the given control." )
DefineEngineMethod(GuiEditCtrl , getSelection , SimSet * , () , "Gets the set of GUI controls currently selected in the editor." )
DefineEngineMethod(GuiEditCtrl , getTrash , SimGroup * , () , "Gets the GUI controls(s) that are currently in the trash." )
IMPLEMENT_CALLBACK(GuiEditCtrl , onAddNewCtrl , void , (GuiControl *control) , (control) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onAddNewCtrlSet , void , (SimSet *set) , (set) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onAddSelected , void , (GuiControl *control) , (control) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onClearSelected , void , () , () , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onControlInspectPostApply , void , (GuiControl *control) , (control) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onControlInspectPreApply , void , (GuiControl *control) , (control) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onDelete , void , () , () , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onFitIntoParent , void , (bool width, bool height) , (width, height) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onHierarchyChanged , void , () , () , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onMouseModeChange , void , () , () , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onPostEdit , void , (SimSet *selection) , (selection) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onPostSelectionNudged , void , (SimSet *selection) , (selection) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onPreEdit , void , (SimSet *selection) , (selection) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onPreSelectionNudged , void , (SimSet *selection) , (selection) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onRemoveSelected , void , (GuiControl *control) , (control) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onSelectionCloned , void , (SimSet *selection) , (selection) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onSelectionMoved , void , (GuiControl *control) , (control) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onSelectionResized , void , (GuiControl *control) , (control) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onTrashSelection , void , (SimSet *selection) , (selection) , "" )
Detailed Description
Public Variables
GuiControl * control
onSelect
void
Public Functions
ConsoleDocClass(GuiEditCtrl , "@brief Native side of the GUI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">editor.\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
ConsoleDocClass(GuiEditorRuler , "@brief Visual representation of markers on top and left sides of GUI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Editor\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
DefineConsoleMethod(GuiEditCtrl , addNewCtrl , void , (GuiControl *ctrl) , "(GuiControl ctrl)" )
DefineConsoleMethod(GuiEditCtrl , addSelection , void , (S32 id) , "selects a control." )
DefineConsoleMethod(GuiEditCtrl , bringToFront , void , () , "" )
DefineConsoleMethod(GuiEditCtrl , clearGuides , void , (S32 axis) , (-1) , "( [ int axis ] ) - Clear all currently set guide lines." )
DefineConsoleMethod(GuiEditCtrl , clearSelection , void , () , "Clear selected controls list." )
DefineConsoleMethod(GuiEditCtrl , deleteSelection , void , () , "() - Delete the selected controls." )
DefineConsoleMethod(GuiEditCtrl , fitIntoParents , void , (bool width, bool height) , (true, true) , "( bool width=true, bool height=true ) - Fit selected controls into their parents." )
DefineConsoleMethod(GuiEditCtrl , getContentControl , S32 , () , "() - Return the toplevel <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> edited inside the GUI editor." )
DefineConsoleMethod(GuiEditCtrl , getCurrentAddSet , S32 , () , "Returns the set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> which <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> controls will be added" )
DefineConsoleMethod(GuiEditCtrl , getMouseMode , const char * , () , "() - Return the current mouse mode." )
DefineConsoleMethod(GuiEditCtrl , getNumSelected , S32 , () , "() - Return the number of controls currently selected." )
DefineConsoleMethod(GuiEditCtrl , getSelectionGlobalBounds , const char * , () , "() - Returns global bounds of current selection as vector 'x y width height'." )
DefineConsoleMethod(GuiEditCtrl , justify , void , (U32 mode) , "(int <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a>)" )
DefineConsoleMethod(GuiEditCtrl , loadSelection , void , (const char *filename) , (NULL) , "( string fileName=null ) - Load selection from <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> or clipboard." )
DefineConsoleMethod(GuiEditCtrl , moveSelection , void , (S32 dx, S32 dy) , "Move all controls in the selection by (dx,dy) pixels." )
DefineConsoleMethod(GuiEditCtrl , pushToBack , void , () , "" )
DefineConsoleMethod(GuiEditCtrl , readGuides , void , (GuiControl *ctrl, S32 axis) , (-1) , "( GuiControl ctrl [, int axis ] ) - Read the guides from the given control." )
DefineConsoleMethod(GuiEditCtrl , removeSelection , void , (S32 id) , "deselects a control." )
DefineConsoleMethod(GuiEditCtrl , saveSelection , void , (const char *filename) , (NULL) , "( string fileName=null ) - Save selection <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> or clipboard." )
DefineConsoleMethod(GuiEditCtrl , select , void , (GuiControl *ctrl) , "(GuiControl ctrl)" )
DefineConsoleMethod(GuiEditCtrl , selectAll , void , () , "()" )
DefineConsoleMethod(GuiEditCtrl , selectChildren , void , (bool addToSelection) , (false) , "( bool addToSelection=false ) - Select children of currently selected controls." )
DefineConsoleMethod(GuiEditCtrl , selectParents , void , (bool addToSelection) , (false) , "( bool addToSelection=false ) - Select parents of currently selected controls." )
DefineConsoleMethod(GuiEditCtrl , setContentControl , void , (GuiControl *ctrl) , "( GuiControl ctrl ) - Set the toplevel <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> edit in the GUI editor." )
DefineConsoleMethod(GuiEditCtrl , setCurrentAddSet , void , (GuiControl *addSet) , "(GuiControl ctrl)" )
DefineConsoleMethod(GuiEditCtrl , setSnapToGrid , void , (U32 gridsize) , "GuiEditCtrl.setSnapToGrid(gridsize)" )
DefineConsoleMethod(GuiEditCtrl , toggle , void , () , "Toggle activation." )
DefineConsoleMethod(GuiEditCtrl , writeGuides , void , (GuiControl *ctrl, S32 axis) , (-1) , "( GuiControl ctrl [, int axis ] ) - Write the guides <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the given control." )
DefineEngineMethod(GuiEditCtrl , getSelection , SimSet * , () , "Gets the set of GUI controls currently selected in the editor." )
DefineEngineMethod(GuiEditCtrl , getTrash , SimGroup * , () , "Gets the GUI controls(s) that are currently in the trash." )
IMPLEMENT_CALLBACK(GuiEditCtrl , onAddNewCtrl , void , (GuiControl *control) , (control) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onAddNewCtrlSet , void , (SimSet *set) , (set) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onAddSelected , void , (GuiControl *control) , (control) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onClearSelected , void , () , () , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onControlInspectPostApply , void , (GuiControl *control) , (control) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onControlInspectPreApply , void , (GuiControl *control) , (control) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onDelete , void , () , () , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onFitIntoParent , void , (bool width, bool height) , (width, height) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onHierarchyChanged , void , () , () , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onMouseModeChange , void , () , () , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onPostEdit , void , (SimSet *selection) , (selection) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onPostSelectionNudged , void , (SimSet *selection) , (selection) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onPreEdit , void , (SimSet *selection) , (selection) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onPreSelectionNudged , void , (SimSet *selection) , (selection) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onRemoveSelected , void , (GuiControl *control) , (control) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onSelectionCloned , void , (SimSet *selection) , (selection) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onSelectionMoved , void , (GuiControl *control) , (control) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onSelectionResized , void , (GuiControl *control) , (control) , "" )
IMPLEMENT_CALLBACK(GuiEditCtrl , onTrashSelection , void , (SimSet *selection) , (selection) , "" )
IMPLEMENT_CONOBJECT(GuiEditCtrl )
IMPLEMENT_CONOBJECT(GuiEditorRuler )
snapPoint(Point2I point, Point2I delta, Point2I gridSnap)
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "gui/editor/guiEditCtrl.h" 26 27#include "core/frameAllocator.h" 28#include "core/stream/fileStream.h" 29#include "core/stream/memStream.h" 30#include "console/consoleTypes.h" 31#include "gui/core/guiCanvas.h" 32#include "gui/containers/guiScrollCtrl.h" 33#include "core/strings/stringUnit.h" 34#include "console/engineAPI.h" 35 36 37IMPLEMENT_CONOBJECT( GuiEditCtrl ); 38 39ConsoleDocClass( GuiEditCtrl, 40 "@brief Native side of the GUI editor.\n\n" 41 "Editor use only.\n\n" 42 "@internal" 43); 44 45IMPLEMENT_CALLBACK( GuiEditCtrl, onHierarchyChanged, void, (), (), 46 "" ); 47IMPLEMENT_CALLBACK( GuiEditCtrl, onDelete, void, (), (), 48 "" ); 49IMPLEMENT_CALLBACK( GuiEditCtrl, onPreEdit, void, ( SimSet* selection ), ( selection ), 50 "" ); 51IMPLEMENT_CALLBACK( GuiEditCtrl, onPostEdit, void, ( SimSet* selection ), ( selection ), 52 "" ); 53IMPLEMENT_CALLBACK( GuiEditCtrl, onClearSelected, void, (), (), 54 "" ) 55IMPLEMENT_CALLBACK( GuiEditCtrl, onSelect, void, ( GuiControl* control ), ( control ), 56 "" ); 57IMPLEMENT_CALLBACK( GuiEditCtrl, onAddSelected, void, ( GuiControl* control ), ( control ), 58 "" ); 59IMPLEMENT_CALLBACK( GuiEditCtrl, onRemoveSelected, void, ( GuiControl* control ), ( control ), 60 "" ); 61IMPLEMENT_CALLBACK( GuiEditCtrl, onPreSelectionNudged, void, ( SimSet* selection ), ( selection ), 62 "" ); 63IMPLEMENT_CALLBACK( GuiEditCtrl, onPostSelectionNudged, void, ( SimSet* selection ), ( selection ), 64 "" ); 65IMPLEMENT_CALLBACK( GuiEditCtrl, onSelectionMoved, void, ( GuiControl* control ), ( control ), 66 "" ); 67IMPLEMENT_CALLBACK( GuiEditCtrl, onSelectionCloned, void, ( SimSet* selection ), ( selection ), 68 "" ); 69IMPLEMENT_CALLBACK( GuiEditCtrl, onTrashSelection, void, ( SimSet* selection ), ( selection ), 70 "" ); 71IMPLEMENT_CALLBACK( GuiEditCtrl, onAddNewCtrl, void, ( GuiControl* control ), ( control ), 72 "" ); 73IMPLEMENT_CALLBACK( GuiEditCtrl, onAddNewCtrlSet, void, ( SimSet* set ), ( set ), 74 "" ); 75IMPLEMENT_CALLBACK( GuiEditCtrl, onSelectionResized, void, ( GuiControl* control ), ( control ), 76 "" ); 77IMPLEMENT_CALLBACK( GuiEditCtrl, onFitIntoParent, void, ( bool width, bool height ), ( width, height ), 78 "" ); 79IMPLEMENT_CALLBACK( GuiEditCtrl, onMouseModeChange, void, (), (), 80 "" ); 81IMPLEMENT_CALLBACK( GuiEditCtrl, onControlInspectPreApply, void, ( GuiControl* control ), ( control ), 82 "" ); 83IMPLEMENT_CALLBACK( GuiEditCtrl, onControlInspectPostApply, void, ( GuiControl* control ), ( control ), 84 "" ); 85 86 87StringTableEntry GuiEditCtrl::smGuidesPropertyName[ 2 ]; 88 89 90//----------------------------------------------------------------------------- 91 92GuiEditCtrl::GuiEditCtrl() 93 : mCurrentAddSet( NULL ), 94 mContentControl( NULL ), 95 mGridSnap( 0, 0 ), 96 mDragBeginPoint( -1, -1 ), 97 mSnapToControls( true ), 98 mSnapToEdges( true ), 99 mSnapToCenters( true ), 100 mSnapToGuides( true ), 101 mSnapToCanvas( true ), 102 mSnapSensitivity( 2 ), 103 mFullBoxSelection( false ), 104 mDrawBorderLines( true ), 105 mDrawGuides( true ) 106{ 107 VECTOR_SET_ASSOCIATION( mSelectedControls ); 108 VECTOR_SET_ASSOCIATION( mDragBeginPoints ); 109 VECTOR_SET_ASSOCIATION( mSnapHits[ 0 ] ); 110 VECTOR_SET_ASSOCIATION( mSnapHits[ 1 ] ); 111 112 mActive = true; 113 mDotSB = NULL; 114 115 mSnapped[ SnapVertical ] = false; 116 mSnapped[ SnapHorizontal ] = false; 117 118 mDragGuide[ GuideVertical ] = false; 119 mDragGuide[ GuideHorizontal ] = false; 120 121 if( !smGuidesPropertyName[ GuideVertical ] ) 122 smGuidesPropertyName[ GuideVertical ] = StringTable->insert( "guidesVertical" ); 123 if( !smGuidesPropertyName[ GuideHorizontal ] ) 124 smGuidesPropertyName[ GuideHorizontal ] = StringTable->insert( "guidesHorizontal" ); 125} 126 127//----------------------------------------------------------------------------- 128 129void GuiEditCtrl::initPersistFields() 130{ 131 addGroup( "Snapping" ); 132 addField( "snapToControls", TypeBool, Offset( mSnapToControls, GuiEditCtrl ), 133 "If true, edge and center snapping will work against controls." ); 134 addField( "snapToGuides", TypeBool, Offset( mSnapToGuides, GuiEditCtrl ), 135 "If true, edge and center snapping will work against guides." ); 136 addField( "snapToCanvas", TypeBool, Offset( mSnapToCanvas, GuiEditCtrl ), 137 "If true, edge and center snapping will work against canvas (toplevel control)." ); 138 addField( "snapToEdges", TypeBool, Offset( mSnapToEdges, GuiEditCtrl ), 139 "If true, selection edges will snap into alignment when moved or resized." ); 140 addField( "snapToCenters", TypeBool, Offset( mSnapToCenters, GuiEditCtrl ), 141 "If true, selection centers will snap into alignment when moved or resized." ); 142 addField( "snapSensitivity", TypeS32, Offset( mSnapSensitivity, GuiEditCtrl ), 143 "Distance in pixels that edge and center snapping will work across." ); 144 endGroup( "Snapping" ); 145 146 addGroup( "Selection" ); 147 addField( "fullBoxSelection", TypeBool, Offset( mFullBoxSelection, GuiEditCtrl ), 148 "If true, rectangle selection will only select controls fully inside the drag rectangle." ); 149 endGroup( "Selection" ); 150 151 addGroup( "Rendering" ); 152 addField( "drawBorderLines", TypeBool, Offset( mDrawBorderLines, GuiEditCtrl ), 153 "If true, lines will be drawn extending along the edges of selected objects." ); 154 addField( "drawGuides", TypeBool, Offset( mDrawGuides, GuiEditCtrl ), 155 "If true, guides will be included in rendering." ); 156 endGroup( "Rendering" ); 157 158 Parent::initPersistFields(); 159} 160 161//============================================================================= 162// Events. 163//============================================================================= 164// MARK: ---- Events ---- 165 166//----------------------------------------------------------------------------- 167 168bool GuiEditCtrl::onAdd() 169{ 170 if( !Parent::onAdd() ) 171 return false; 172 173 mTrash = new SimGroup(); 174 mSelectedSet = new SimSet(); 175 176 if( !mTrash->registerObject() ) 177 return false; 178 if( !mSelectedSet->registerObject() ) 179 return false; 180 181 return true; 182} 183 184//----------------------------------------------------------------------------- 185 186void GuiEditCtrl::onRemove() 187{ 188 Parent::onRemove(); 189 190 mDotSB = NULL; 191 192 mTrash->deleteObject(); 193 mSelectedSet->deleteObject(); 194 195 mTrash = NULL; 196 mSelectedSet = NULL; 197} 198 199//----------------------------------------------------------------------------- 200 201bool GuiEditCtrl::onWake() 202{ 203 if (! Parent::onWake()) 204 return false; 205 206 // Set GUI Controls to DesignTime mode 207 GuiControl::smDesignTime = true; 208 GuiControl::smEditorHandle = this; 209 210 setEditMode(true); 211 212 return true; 213} 214 215//----------------------------------------------------------------------------- 216 217void GuiEditCtrl::onSleep() 218{ 219 // Set GUI Controls to run time mode 220 GuiControl::smDesignTime = false; 221 GuiControl::smEditorHandle = NULL; 222 223 Parent::onSleep(); 224} 225 226//----------------------------------------------------------------------------- 227 228bool GuiEditCtrl::onKeyDown(const GuiEvent &event) 229{ 230 if (! mActive) 231 return Parent::onKeyDown(event); 232 233 if (!(event.modifier & SI_PRIMARY_CTRL)) 234 { 235 switch(event.keyCode) 236 { 237 case KEY_BACKSPACE: 238 case KEY_DELETE: 239 deleteSelection(); 240 onDelete_callback(); 241 return true; 242 default: 243 break; 244 } 245 } 246 return false; 247} 248 249//----------------------------------------------------------------------------- 250 251void GuiEditCtrl::onMouseDown(const GuiEvent &event) 252{ 253 if (! mActive) 254 { 255 Parent::onMouseDown(event); 256 return; 257 } 258 if(!mContentControl) 259 return; 260 261 setFirstResponder(); 262 mouseLock(); 263 264 mLastMousePos = globalToLocalCoord( event.mousePoint ); 265 266 // Check whether we've hit a guide. If so, start a guide drag. 267 // Don't do this if SHIFT is down. 268 269 if( !( event.modifier & SI_SHIFT ) ) 270 { 271 for( U32 axis = 0; axis < 2; ++ axis ) 272 { 273 const S32 guide = findGuide( ( guideAxis ) axis, event.mousePoint, 1 ); 274 if( guide != -1 ) 275 { 276 setMouseMode( DragGuide ); 277 278 mDragGuide[ axis ] = true; 279 mDragGuideIndex[ axis ] = guide; 280 } 281 } 282 283 if( mMouseDownMode == DragGuide ) 284 return; 285 } 286 287 // Check whether we have hit a sizing knob on any of the currently selected 288 // controls. 289 290 for( U32 i = 0, num = mSelectedControls.size(); i < num; ++ i ) 291 { 292 GuiControl* ctrl = mSelectedControls[ i ]; 293 294 Point2I cext = ctrl->getExtent(); 295 Point2I ctOffset = globalToLocalCoord( ctrl->localToGlobalCoord( Point2I( 0, 0 ) ) ); 296 297 RectI box( ctOffset.x, ctOffset.y, cext.x, cext.y ); 298 299 if( ( mSizingMode = ( GuiEditCtrl::sizingModes ) getSizingHitKnobs( mLastMousePos, box ) ) != 0 ) 300 { 301 setMouseMode( SizingSelection ); 302 mLastDragPos = event.mousePoint; 303 304 // undo 305 onPreEdit_callback( getSelectedSet() ); 306 return; 307 } 308 } 309 310 // Find the control we have hit. 311 312 GuiControl* ctrl = mContentControl->findHitControl( mLastMousePos, getCurrentAddSet()->mLayer ); 313 314 // Give the control itself the opportunity to handle the event 315 // to implement custom editing logic. 316 317 bool handledEvent = ctrl->onMouseDownEditor( event, localToGlobalCoord( Point2I(0,0) ) ); 318 if( handledEvent == true ) 319 { 320 // The Control handled the event and requested the edit ctrl 321 // *NOT* act on it. 322 return; 323 } 324 else if( event.modifier & SI_SHIFT ) 325 { 326 // Shift is down. Start rectangle selection in add mode 327 // no matter what we have hit. 328 329 startDragRectangle( event.mousePoint ); 330 mDragAddSelection = true; 331 } 332 else if( selectionContains( ctrl ) ) 333 { 334 // We hit a selected control. If the multiselect key is pressed, 335 // deselect the control. Otherwise start a drag move. 336 337 if( event.modifier & SI_MULTISELECT ) 338 { 339 removeSelection( ctrl ); 340 341 //set the mode 342 setMouseMode( Selecting ); 343 } 344 else if( event.modifier & SI_PRIMARY_ALT ) 345 { 346 // Alt is down. Start a drag clone. 347 348 startDragClone( event.mousePoint ); 349 } 350 else 351 { 352 startDragMove( event.mousePoint ); 353 } 354 } 355 else 356 { 357 // We clicked an unselected control. 358 359 if( ctrl == getContentControl() ) 360 { 361 // Clicked in toplevel control. Start a rectangle selection. 362 363 startDragRectangle( event.mousePoint ); 364 mDragAddSelection = false; 365 } 366 else if( event.modifier & SI_PRIMARY_ALT && ctrl != getContentControl() ) 367 { 368 // Alt is down. Start a drag clone. 369 370 clearSelection(); 371 addSelection( ctrl ); 372 373 startDragClone( event.mousePoint ); 374 } 375 else if( event.modifier & SI_MULTISELECT ) 376 addSelection( ctrl ); 377 else 378 { 379 // Clicked on child control. Start move. 380 381 clearSelection(); 382 addSelection( ctrl ); 383 384 startDragMove( event.mousePoint ); 385 } 386 } 387} 388 389//----------------------------------------------------------------------------- 390 391void GuiEditCtrl::onMouseUp(const GuiEvent &event) 392{ 393 if (! mActive || !mContentControl || !getCurrentAddSet() ) 394 { 395 Parent::onMouseUp(event); 396 return; 397 } 398 399 //find the control we clicked 400 GuiControl *ctrl = mContentControl->findHitControl(mLastMousePos, getCurrentAddSet()->mLayer); 401 402 bool handledEvent = ctrl->onMouseUpEditor( event, localToGlobalCoord( Point2I(0,0) ) ); 403 if( handledEvent == true ) 404 { 405 // The Control handled the event and requested the edit ctrl 406 // *NOT* act on it. The dude abides. 407 return; 408 } 409 410 //unlock the mouse 411 mouseUnlock(); 412 413 // Reset Drag Axis Alignment Information 414 mDragBeginPoint.set(-1,-1); 415 mDragBeginPoints.clear(); 416 417 mLastMousePos = globalToLocalCoord(event.mousePoint); 418 if( mMouseDownMode == DragGuide ) 419 { 420 // Check to see if the mouse has moved off the canvas. If so, 421 // remove the guides being dragged. 422 423 for( U32 axis = 0; axis < 2; ++ axis ) 424 if( mDragGuide[ axis ] && !getContentControl()->getGlobalBounds().pointInRect( event.mousePoint ) ) 425 mGuides[ axis ].erase( mDragGuideIndex[ axis ] ); 426 } 427 else if( mMouseDownMode == DragSelecting ) 428 { 429 // If not multiselecting, clear the current selection. 430 431 if( !( event.modifier & SI_MULTISELECT ) && !mDragAddSelection ) 432 clearSelection(); 433 434 RectI rect; 435 getDragRect( rect ); 436 437 // If the region is somewhere less than at least 2x2, count this as a 438 // normal, non-rectangular selection. 439 440 if( rect.extent.x <= 2 && rect.extent.y <= 2 ) 441 addSelectControlAt( rect.point ); 442 else 443 { 444 // Use HIT_AddParentHits by default except if ALT is pressed. 445 // Use HIT_ParentPreventsChildHit if ALT+CTRL is pressed. 446 447 U32 hitFlags = 0; 448 if( !( event.modifier & SI_PRIMARY_ALT ) ) 449 hitFlags |= HIT_AddParentHits; 450 if( event.modifier & SI_PRIMARY_ALT && event.modifier & SI_CTRL ) 451 hitFlags |= HIT_ParentPreventsChildHit; 452 453 addSelectControlsInRegion( rect, hitFlags ); 454 } 455 } 456 else if( ctrl == getContentControl() && mMouseDownMode == Selecting ) 457 setCurrentAddSet( NULL, true ); 458 459 // deliver post edit event if we've been editing 460 // note: paxorr: this may need to be moved earlier, if the selection has changed. 461 // undo 462 if( mMouseDownMode == SizingSelection || ( mMouseDownMode == MovingSelection && mDragMoveUndo ) ) 463 onPostEdit_callback( getSelectedSet() ); 464 465 //reset the mouse mode 466 setFirstResponder(); 467 setMouseMode( Selecting ); 468 mSizingMode = sizingNone; 469 470 // Clear snapping state. 471 472 mSnapped[ SnapVertical ] = false; 473 mSnapped[ SnapHorizontal ] = false; 474 475 mSnapTargets[ SnapVertical ] = NULL; 476 mSnapTargets[ SnapHorizontal ] = NULL; 477 478 // Clear guide drag state. 479 480 mDragGuide[ GuideVertical ] = false; 481 mDragGuide[ GuideHorizontal ] = false; 482} 483 484//----------------------------------------------------------------------------- 485 486void GuiEditCtrl::onMouseDragged( const GuiEvent &event ) 487{ 488 if( !mActive || !mContentControl || !getCurrentAddSet() ) 489 { 490 Parent::onMouseDragged(event); 491 return; 492 } 493 494 Point2I mousePoint = globalToLocalCoord( event.mousePoint ); 495 496 //find the control we clicked 497 GuiControl *ctrl = mContentControl->findHitControl( mousePoint, getCurrentAddSet()->mLayer ); 498 499 bool handledEvent = ctrl->onMouseDraggedEditor( event, localToGlobalCoord( Point2I(0,0) ) ); 500 if( handledEvent == true ) 501 { 502 // The Control handled the event and requested the edit ctrl 503 // *NOT* act on it. The dude abides. 504 return; 505 } 506 507 // If we're doing a drag clone, see if we have crossed the move threshold. If so, 508 // clone the selection and switch to move mode. 509 510 if( mMouseDownMode == DragClone ) 511 { 512 // If we haven't yet crossed the mouse delta to actually start the 513 // clone, check if we have now. 514 515 S32 delta = mAbs( ( mousePoint - mDragBeginPoint ).len() ); 516 if( delta >= 4 ) 517 { 518 cloneSelection(); 519 mLastMousePos = mDragBeginPoint; 520 mDragMoveUndo = false; 521 522 setMouseMode( MovingSelection ); 523 } 524 } 525 526 if( mMouseDownMode == DragGuide ) 527 { 528 for( U32 axis = 0; axis < 2; ++ axis ) 529 if( mDragGuide[ axis ] ) 530 { 531 // Set the guide to the coordinate of the mouse cursor 532 // on the guide's axis. 533 534 Point2I point = event.mousePoint; 535 point -= localToGlobalCoord( Point2I( 0, 0 ) ); 536 point[ axis ] = mClamp( point[ axis ], 0, getExtent()[ axis ] - 1 ); 537 538 mGuides[ axis ][ mDragGuideIndex[ axis ] ] = point[ axis ]; 539 } 540 } 541 else if( mMouseDownMode == SizingSelection ) 542 { 543 // Snap the mouse cursor to grid if active. Do this on the mouse cursor so that we handle 544 // incremental drags correctly. 545 546 Point2I mousePoint = event.mousePoint; 547 snapToGrid( mousePoint ); 548 549 Point2I delta = mousePoint - mLastDragPos; 550 551 // If CTRL is down, apply smart snapping. 552 553 if( event.modifier & SI_CTRL ) 554 { 555 RectI selectionBounds = getSelectionBounds(); 556 557 doSnapping( event, selectionBounds, delta ); 558 } 559 else 560 { 561 mSnapped[ SnapVertical ] = false; 562 mSnapped[ SnapHorizontal ] = false; 563 } 564 565 // If ALT is down, do a move instead of a resize on the control 566 // knob's axis. Otherwise resize. 567 568 if( event.modifier & SI_PRIMARY_ALT ) 569 { 570 if( !( mSizingMode & sizingLeft ) && !( mSizingMode & sizingRight ) ) 571 { 572 mSnapped[ SnapVertical ] = false; 573 delta.x = 0; 574 } 575 if( !( mSizingMode & sizingTop ) && !( mSizingMode & sizingBottom ) ) 576 { 577 mSnapped[ SnapHorizontal ] = false; 578 delta.y = 0; 579 } 580 581 moveSelection( delta ); 582 } 583 else 584 resizeControlsInSelectionBy( delta, mSizingMode ); 585 586 // Remember drag point. 587 588 mLastDragPos = mousePoint; 589 } 590 else if (mMouseDownMode == MovingSelection && mSelectedControls.size()) 591 { 592 Point2I delta = mousePoint - mLastMousePos; 593 RectI selectionBounds = getSelectionBounds(); 594 595 // Apply snaps. 596 597 doSnapping( event, selectionBounds, delta ); 598 599 //RDTODO: to me seems to be in need of revision 600 // Do we want to align this drag to the X and Y axes within a certain threshold? 601 if( event.modifier & SI_SHIFT && !( event.modifier & SI_PRIMARY_ALT ) ) 602 { 603 Point2I dragTotalDelta = event.mousePoint - localToGlobalCoord( mDragBeginPoint ); 604 if( dragTotalDelta.y < 10 && dragTotalDelta.y > -10 ) 605 { 606 for(S32 i = 0; i < mSelectedControls.size(); i++) 607 { 608 Point2I selCtrlPos = mSelectedControls[i]->getPosition(); 609 Point2I snapBackPoint( selCtrlPos.x, mDragBeginPoints[i].y); 610 // This is kind of nasty but we need to snap back if we're not at origin point with selection - JDD 611 if( selCtrlPos.y != mDragBeginPoints[i].y ) 612 mSelectedControls[i]->setPosition( snapBackPoint ); 613 } 614 delta.y = 0; 615 } 616 if( dragTotalDelta.x < 10 && dragTotalDelta.x > -10 ) 617 { 618 for(S32 i = 0; i < mSelectedControls.size(); i++) 619 { 620 Point2I selCtrlPos = mSelectedControls[i]->getPosition(); 621 Point2I snapBackPoint( mDragBeginPoints[i].x, selCtrlPos.y); 622 // This is kind of nasty but we need to snap back if we're not at origin point with selection - JDD 623 if( selCtrlPos.x != mDragBeginPoints[i].x ) 624 mSelectedControls[i]->setPosition( snapBackPoint ); 625 } 626 delta.x = 0; 627 } 628 } 629 630 if( delta.x || delta.y ) 631 moveSelection( delta, mDragMoveUndo ); 632 633 // find the current control under the mouse 634 635 canHitSelectedControls( false ); 636 GuiControl *inCtrl = mContentControl->findHitControl(mousePoint, getCurrentAddSet()->mLayer); 637 canHitSelectedControls( true ); 638 639 // find the nearest control up the heirarchy from the control the mouse is in 640 // that is flagged as a container. 641 while( !inCtrl->mIsContainer ) 642 inCtrl = inCtrl->getParent(); 643 644 // if the control under the mouse is not our parent, move the selected controls 645 // into the new parent. 646 if(mSelectedControls[0]->getParent() != inCtrl && inCtrl->mIsContainer) 647 { 648 moveSelectionToCtrl( inCtrl, mDragMoveUndo ); 649 setCurrentAddSet( inCtrl, false ); 650 } 651 652 mLastMousePos += delta; 653 } 654 else 655 mLastMousePos = mousePoint; 656} 657 658//----------------------------------------------------------------------------- 659 660void GuiEditCtrl::onRightMouseDown(const GuiEvent &event) 661{ 662 if (! mActive || !mContentControl) 663 { 664 Parent::onRightMouseDown(event); 665 return; 666 } 667 setFirstResponder(); 668 669 //search for the control hit in any layer below the edit layer 670 GuiControl *hitCtrl = mContentControl->findHitControl(globalToLocalCoord(event.mousePoint), mLayer - 1); 671 if (hitCtrl != getCurrentAddSet()) 672 { 673 setCurrentAddSet( hitCtrl ); 674 } 675 // select the parent if we right-click on the current add set 676 else if( getCurrentAddSet() != mContentControl) 677 { 678 setCurrentAddSet( hitCtrl->getParent() ); 679 select(hitCtrl); 680 } 681 682 //Design time mouse events 683 GuiEvent designEvent = event; 684 designEvent.mousePoint = mLastMousePos; 685 hitCtrl->onRightMouseDownEditor( designEvent, localToGlobalCoord( Point2I(0,0) ) ); 686 687} 688 689//============================================================================= 690// Rendering. 691//============================================================================= 692// MARK: ---- Rendering ---- 693 694//----------------------------------------------------------------------------- 695 696void GuiEditCtrl::onPreRender() 697{ 698 setUpdate(); 699} 700 701//----------------------------------------------------------------------------- 702 703void GuiEditCtrl::onRender(Point2I offset, const RectI &updateRect) 704{ 705 Point2I ctOffset; 706 Point2I cext; 707 bool keyFocused = isFirstResponder(); 708 709 GFXDrawUtil *drawer = GFX->getDrawUtil(); 710 711 if (mActive) 712 { 713 if( getCurrentAddSet() != getContentControl() ) 714 { 715 // draw a white frame inset around the current add set. 716 cext = getCurrentAddSet()->getExtent(); 717 ctOffset = getCurrentAddSet()->localToGlobalCoord(Point2I(0,0)); 718 RectI box(ctOffset.x, ctOffset.y, cext.x, cext.y); 719 720 box.inset( -5, -5 ); 721 drawer->drawRect( box, ColorI( 50, 101, 152, 128 ) ); 722 box.inset( 1, 1 ); 723 drawer->drawRect( box, ColorI( 50, 101, 152, 128 ) ); 724 box.inset( 1, 1 ); 725 drawer->drawRect( box, ColorI( 50, 101, 152, 128 ) ); 726 box.inset( 1, 1 ); 727 drawer->drawRect( box, ColorI( 50, 101, 152, 128 ) ); 728 box.inset( 1, 1 ); 729 drawer->drawRect( box, ColorI( 50, 101, 152, 128 ) ); 730 } 731 Vector<GuiControl *>::iterator i; 732 bool multisel = mSelectedControls.size() > 1; 733 for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++) 734 { 735 GuiControl *ctrl = (*i); 736 cext = ctrl->getExtent(); 737 ctOffset = ctrl->localToGlobalCoord(Point2I(0,0)); 738 RectI box(ctOffset.x,ctOffset.y, cext.x, cext.y); 739 ColorI nutColor = multisel ? ColorI( 255, 255, 255, 100 ) : ColorI( 0, 0, 0, 100 ); 740 ColorI outlineColor = multisel ? ColorI( 0, 0, 0, 100 ) : ColorI( 255, 255, 255, 100 ); 741 if(!keyFocused) 742 nutColor.set( 128, 128, 128, 100 ); 743 744 drawNuts(box, outlineColor, nutColor); 745 } 746 } 747 748 renderChildControls(offset, updateRect); 749 750 // Draw selection rectangle. 751 752 if( mActive && mMouseDownMode == DragSelecting ) 753 { 754 RectI b; 755 getDragRect(b); 756 b.point += offset; 757 758 // Draw outline. 759 760 drawer->drawRect( b, ColorI( 100, 100, 100, 128 ) ); 761 762 // Draw fill. 763 764 b.inset( 1, 1 ); 765 drawer->drawRectFill( b, ColorI( 150, 150, 150, 128 ) ); 766 } 767 768 // Draw grid. 769 770 if( mActive && 771 ( mMouseDownMode == MovingSelection || mMouseDownMode == SizingSelection ) && 772 ( mGridSnap.x || mGridSnap.y ) ) 773 { 774 Point2I cext = getContentControl()->getExtent(); 775 Point2I coff = getContentControl()->localToGlobalCoord(Point2I(0,0)); 776 777 // create point-dots 778 const Point2I& snap = mGridSnap; 779 U32 maxdot = (U32)(mCeil(cext.x / (F32)snap.x) - 1) * (U32)(mCeil(cext.y / (F32)snap.y) - 1); 780 781 if( mDots.isNull() || maxdot != mDots->mNumVerts) 782 { 783 mDots.set(GFX, maxdot, GFXBufferTypeStatic); 784 785 U32 ndot = 0; 786 mDots.lock(); 787 for(U32 ix = snap.x; ix < cext.x; ix += snap.x) 788 { 789 for(U32 iy = snap.y; ndot < maxdot && iy < cext.y; iy += snap.y) 790 { 791 mDots[ndot].color.set( 50, 50, 254, 100 ); 792 mDots[ndot].point.x = F32(ix + coff.x); 793 mDots[ndot].point.y = F32(iy + coff.y); 794 mDots[ndot].point.z = 0.0f; 795 ndot++; 796 } 797 } 798 mDots.unlock(); 799 AssertFatal(ndot <= maxdot, "dot overflow"); 800 AssertFatal(ndot == maxdot, "dot underflow"); 801 } 802 803 if (!mDotSB) 804 { 805 GFXStateBlockDesc dotdesc; 806 dotdesc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha); 807 dotdesc.setCullMode( GFXCullNone ); 808 mDotSB = GFX->createStateBlock( dotdesc ); 809 } 810 811 GFX->setStateBlock(mDotSB); 812 813 // draw the points. 814 GFX->setVertexBuffer( mDots ); 815 GFX->drawPrimitive( GFXPointList, 0, mDots->mNumVerts ); 816 } 817 818 // Draw snapping lines. 819 820 if( mActive && getContentControl() ) 821 { 822 RectI bounds = getContentControl()->getGlobalBounds(); 823 824 // Draw guide lines. 825 826 if( mDrawGuides ) 827 { 828 for( U32 axis = 0; axis < 2; ++ axis ) 829 { 830 for( U32 i = 0, num = mGuides[ axis ].size(); i < num; ++ i ) 831 drawCrossSection( axis, mGuides[ axis ][ i ] + bounds.point[ axis ], 832 bounds, ColorI( 0, 255, 0, 100 ), drawer ); 833 } 834 } 835 836 // Draw smart snap lines. 837 838 for( U32 axis = 0; axis < 2; ++ axis ) 839 { 840 if( mSnapped[ axis ] ) 841 { 842 // Draw the snap line. 843 844 drawCrossSection( axis, mSnapOffset[ axis ], 845 bounds, ColorI( 0, 0, 255, 100 ), drawer ); 846 847 // Draw a border around the snap target control. 848 849 if( mSnapTargets[ axis ] ) 850 { 851 RectI bounds = mSnapTargets[ axis ]->getGlobalBounds(); 852 drawer->drawRect( bounds, ColorF( .5, .5, .5, .5 ) ); 853 } 854 } 855 } 856 } 857} 858 859//----------------------------------------------------------------------------- 860 861void GuiEditCtrl::drawNuts(RectI &box, ColorI &outlineColor, ColorI &nutColor) 862{ 863 GFXDrawUtil *drawer = GFX->getDrawUtil(); 864 865 S32 lx = box.point.x, rx = box.point.x + box.extent.x - 1; 866 S32 cx = (lx + rx) >> 1; 867 S32 ty = box.point.y, by = box.point.y + box.extent.y - 1; 868 S32 cy = (ty + by) >> 1; 869 870 if( mDrawBorderLines ) 871 { 872 ColorF lineColor( 0.7f, 0.7f, 0.7f, 0.25f ); 873 ColorF lightLineColor( 0.5f, 0.5f, 0.5f, 0.1f ); 874 875 if(lx > 0 && ty > 0) 876 { 877 drawer->drawLine(0, ty, lx, ty, lineColor); // Left edge to top-left corner. 878 drawer->drawLine(lx, 0, lx, ty, lineColor); // Top edge to top-left corner. 879 } 880 881 if(lx > 0 && by > 0) 882 drawer->drawLine(0, by, lx, by, lineColor); // Left edge to bottom-left corner. 883 884 if(rx > 0 && ty > 0) 885 drawer->drawLine(rx, 0, rx, ty, lineColor); // Top edge to top-right corner. 886 887 Point2I extent = localToGlobalCoord(getExtent()); 888 889 if(lx < extent.x && by < extent.y) 890 drawer->drawLine(lx, by, lx, extent.y, lightLineColor); // Bottom-left corner to bottom edge. 891 if(rx < extent.x && by < extent.y) 892 { 893 drawer->drawLine(rx, by, rx, extent.y, lightLineColor); // Bottom-right corner to bottom edge. 894 drawer->drawLine(rx, by, extent.x, by, lightLineColor); // Bottom-right corner to right edge. 895 } 896 if(rx < extent.x && ty < extent.y) 897 drawer->drawLine(rx, ty, extent.x, ty, lightLineColor); // Top-right corner to right edge. 898 } 899 900 // Adjust nuts, so they dont straddle the controls. 901 902 lx -= NUT_SIZE + 1; 903 ty -= NUT_SIZE + 1; 904 rx += 1; 905 by += 1; 906 907 // Draw nuts. 908 909 drawNut( Point2I( lx - NUT_SIZE, ty - NUT_SIZE ), outlineColor, nutColor ); // Top left 910 drawNut( Point2I( lx - NUT_SIZE, cy - NUT_SIZE / 2 ), outlineColor, nutColor ); // Mid left 911 drawNut( Point2I( lx - NUT_SIZE, by ), outlineColor, nutColor ); // Bottom left 912 drawNut( Point2I( rx, ty - NUT_SIZE ), outlineColor, nutColor ); // Top right 913 drawNut( Point2I( rx, cy - NUT_SIZE / 2 ), outlineColor, nutColor ); // Mid right 914 drawNut( Point2I( rx, by ), outlineColor, nutColor ); // Bottom right 915 drawNut( Point2I( cx - NUT_SIZE / 2, ty - NUT_SIZE ), outlineColor, nutColor ); // Mid top 916 drawNut( Point2I( cx - NUT_SIZE / 2, by ), outlineColor, nutColor ); // Mid bottom 917} 918 919//----------------------------------------------------------------------------- 920 921void GuiEditCtrl::drawNut(const Point2I &nut, ColorI &outlineColor, ColorI &nutColor) 922{ 923 RectI r( nut.x, nut.y, NUT_SIZE * 2, NUT_SIZE * 2 ); 924 GFX->getDrawUtil()->drawRect( r, outlineColor ); 925 r.inset( 1, 1 ); 926 GFX->getDrawUtil()->drawRectFill( r, nutColor ); 927} 928 929//============================================================================= 930// Selections. 931//============================================================================= 932// MARK: ---- Selections ---- 933 934//----------------------------------------------------------------------------- 935 936void GuiEditCtrl::clearSelection(void) 937{ 938 mSelectedControls.clear(); 939 onClearSelected_callback(); 940} 941 942//----------------------------------------------------------------------------- 943 944void GuiEditCtrl::setSelection(GuiControl *ctrl, bool inclusive) 945{ 946 //sanity check 947 if( !ctrl ) 948 return; 949 950 if( mSelectedControls.size() == 1 && mSelectedControls[ 0 ] == ctrl ) 951 return; 952 953 if( !inclusive ) 954 clearSelection(); 955 956 if( mContentControl == ctrl ) 957 setCurrentAddSet( ctrl, false ); 958 else 959 addSelection( ctrl ); 960} 961 962//----------------------------------------------------------------------------- 963 964void GuiEditCtrl::addSelection(S32 id) 965{ 966 GuiControl * ctrl; 967 if( Sim::findObject( id, ctrl ) ) 968 addSelection( ctrl ); 969} 970 971//----------------------------------------------------------------------------- 972 973void GuiEditCtrl::addSelection( GuiControl* ctrl ) 974{ 975 // Only add if this isn't the content control and the 976 // control isn't yet in the selection. 977 978 if( ctrl != getContentControl() && !selectionContains( ctrl ) ) 979 { 980 mSelectedControls.push_back( ctrl ); 981 982 if( mSelectedControls.size() == 1 ) 983 { 984 // Update the add set. 985 986 if( ctrl->mIsContainer ) 987 setCurrentAddSet( ctrl, false ); 988 else 989 setCurrentAddSet( ctrl->getParent(), false ); 990 991 // Notify script. 992 993 onSelect_callback( ctrl ); 994 } 995 else 996 { 997 // Notify script. 998 999 onAddSelected_callback( ctrl ); 1000 } 1001 } 1002} 1003 1004//----------------------------------------------------------------------------- 1005 1006void GuiEditCtrl::removeSelection( S32 id ) 1007{ 1008 GuiControl * ctrl; 1009 if ( Sim::findObject( id, ctrl ) ) 1010 removeSelection( ctrl ); 1011} 1012 1013//----------------------------------------------------------------------------- 1014 1015void GuiEditCtrl::removeSelection( GuiControl* ctrl ) 1016{ 1017 if( selectionContains( ctrl ) ) 1018 { 1019 Vector< GuiControl* >::iterator i = ::find( mSelectedControls.begin(), mSelectedControls.end(), ctrl ); 1020 if ( i != mSelectedControls.end() ) 1021 mSelectedControls.erase( i ); 1022 1023 onRemoveSelected_callback( ctrl ); 1024 } 1025} 1026 1027//----------------------------------------------------------------------------- 1028 1029void GuiEditCtrl::canHitSelectedControls( bool state ) 1030{ 1031 for( U32 i = 0, num = mSelectedControls.size(); i < num; ++ i ) 1032 mSelectedControls[ i ]->setCanHit( state ); 1033} 1034 1035//----------------------------------------------------------------------------- 1036 1037void GuiEditCtrl::moveSelectionToCtrl( GuiControl *newParent, bool callback ) 1038{ 1039 for( U32 i = 0; i < mSelectedControls.size(); ++ i ) 1040 { 1041 GuiControl* ctrl = mSelectedControls[i]; 1042 if( ctrl->getParent() == newParent 1043 || ctrl->isLocked() 1044 || selectionContainsParentOf( ctrl ) ) 1045 continue; 1046 1047 Point2I globalpos = ctrl->localToGlobalCoord(Point2I(0,0)); 1048 newParent->addObject(ctrl); 1049 Point2I newpos = ctrl->globalToLocalCoord(globalpos) + ctrl->getPosition(); 1050 ctrl->setPosition(newpos); 1051 } 1052 1053 onHierarchyChanged_callback(); 1054 1055 //TODO: undo 1056} 1057 1058//----------------------------------------------------------------------------- 1059 1060static Point2I snapPoint(Point2I point, Point2I delta, Point2I gridSnap) 1061{ 1062 S32 snap; 1063 if(gridSnap.x && delta.x) 1064 { 1065 snap = point.x % gridSnap.x; 1066 point.x -= snap; 1067 if(delta.x > 0 && snap != 0) 1068 point.x += gridSnap.x; 1069 } 1070 if(gridSnap.y && delta.y) 1071 { 1072 snap = point.y % gridSnap.y; 1073 point.y -= snap; 1074 if(delta.y > 0 && snap != 0) 1075 point.y += gridSnap.y; 1076 } 1077 return point; 1078} 1079 1080void GuiEditCtrl::moveAndSnapSelection( const Point2I &delta, bool callback ) 1081{ 1082 // move / nudge gets a special callback so that multiple small moves can be 1083 // coalesced into one large undo action. 1084 // undo 1085 1086 if( callback ) 1087 onPreSelectionNudged_callback( getSelectedSet() ); 1088 1089 Vector<GuiControl *>::iterator i; 1090 Point2I newPos; 1091 for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++) 1092 { 1093 GuiControl* ctrl = *i; 1094 if( !ctrl->isLocked() && !selectionContainsParentOf( ctrl ) ) 1095 { 1096 newPos = ctrl->getPosition() + delta; 1097 newPos = snapPoint( newPos, delta, mGridSnap ); 1098 ctrl->setPosition( newPos ); 1099 } 1100 } 1101 1102 // undo 1103 if( callback ) 1104 onPostSelectionNudged_callback( getSelectedSet() ); 1105 1106 // allow script to update the inspector 1107 if( callback && mSelectedControls.size() > 0 ) 1108 onSelectionMoved_callback( mSelectedControls[ 0 ] ); 1109} 1110 1111//----------------------------------------------------------------------------- 1112 1113void GuiEditCtrl::moveSelection( const Point2I &delta, bool callback ) 1114{ 1115 Vector<GuiControl *>::iterator i; 1116 for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++) 1117 { 1118 GuiControl* ctrl = *i; 1119 if( !ctrl->isLocked() && !selectionContainsParentOf( ctrl ) ) 1120 ctrl->setPosition( ctrl->getPosition() + delta ); 1121 } 1122 1123 // allow script to update the inspector 1124 if( callback ) 1125 onSelectionMoved_callback( mSelectedControls[ 0 ] ); 1126} 1127 1128//----------------------------------------------------------------------------- 1129 1130void GuiEditCtrl::justifySelection( Justification j ) 1131{ 1132 S32 minX, maxX; 1133 S32 minY, maxY; 1134 S32 extentX, extentY; 1135 1136 if (mSelectedControls.size() < 2) 1137 return; 1138 1139 Vector<GuiControl *>::iterator i = mSelectedControls.begin(); 1140 minX = (*i)->getLeft(); 1141 maxX = minX + (*i)->getWidth(); 1142 minY = (*i)->getTop(); 1143 maxY = minY + (*i)->getHeight(); 1144 extentX = (*i)->getWidth(); 1145 extentY = (*i)->getHeight(); 1146 i++; 1147 for(;i != mSelectedControls.end(); i++) 1148 { 1149 minX = getMin(minX, (*i)->getLeft()); 1150 maxX = getMax(maxX, (*i)->getLeft() + (*i)->getWidth()); 1151 minY = getMin(minY, (*i)->getTop()); 1152 maxY = getMax(maxY, (*i)->getTop() + (*i)->getHeight()); 1153 extentX += (*i)->getWidth(); 1154 extentY += (*i)->getHeight(); 1155 } 1156 S32 deltaX = maxX - minX; 1157 S32 deltaY = maxY - minY; 1158 switch(j) 1159 { 1160 case JUSTIFY_LEFT: 1161 for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++) 1162 if( !( *i )->isLocked() ) 1163 (*i)->setLeft( minX ); 1164 break; 1165 case JUSTIFY_TOP: 1166 for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++) 1167 if( !( *i )->isLocked() ) 1168 (*i)->setTop( minY ); 1169 break; 1170 case JUSTIFY_RIGHT: 1171 for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++) 1172 if( !( *i )->isLocked() ) 1173 (*i)->setLeft( maxX - (*i)->getWidth() + 1 ); 1174 break; 1175 case JUSTIFY_BOTTOM: 1176 for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++) 1177 if( !( *i )->isLocked() ) 1178 (*i)->setTop( maxY - (*i)->getHeight() + 1 ); 1179 break; 1180 case JUSTIFY_CENTER_VERTICAL: 1181 for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++) 1182 if( !( *i )->isLocked() ) 1183 (*i)->setLeft( minX + ((deltaX - (*i)->getWidth()) >> 1 )); 1184 break; 1185 case JUSTIFY_CENTER_HORIZONTAL: 1186 for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++) 1187 if( !( *i )->isLocked() ) 1188 (*i)->setTop( minY + ((deltaY - (*i)->getHeight()) >> 1 )); 1189 break; 1190 case SPACING_VERTICAL: 1191 { 1192 Vector<GuiControl*> sortedList; 1193 Vector<GuiControl *>::iterator k; 1194 for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++) 1195 { 1196 for(k = sortedList.begin(); k != sortedList.end(); k++) 1197 { 1198 if ((*i)->getTop() < (*k)->getTop()) 1199 break; 1200 } 1201 sortedList.insert(k, *i); 1202 } 1203 S32 space = (deltaY - extentY) / (mSelectedControls.size() - 1); 1204 S32 curY = minY; 1205 for(k = sortedList.begin(); k != sortedList.end(); k++) 1206 { 1207 if( !( *k )->isLocked() ) 1208 (*k)->setTop( curY ); 1209 curY += (*k)->getHeight() + space; 1210 } 1211 } 1212 break; 1213 case SPACING_HORIZONTAL: 1214 { 1215 Vector<GuiControl*> sortedList; 1216 Vector<GuiControl *>::iterator k; 1217 for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++) 1218 { 1219 for(k = sortedList.begin(); k != sortedList.end(); k++) 1220 { 1221 if ((*i)->getLeft() < (*k)->getLeft()) 1222 break; 1223 } 1224 sortedList.insert(k, *i); 1225 } 1226 S32 space = (deltaX - extentX) / (mSelectedControls.size() - 1); 1227 S32 curX = minX; 1228 for(k = sortedList.begin(); k != sortedList.end(); k++) 1229 { 1230 if( !( *k )->isLocked() ) 1231 (*k)->setLeft( curX ); 1232 curX += (*k)->getWidth() + space; 1233 } 1234 } 1235 break; 1236 } 1237} 1238 1239//----------------------------------------------------------------------------- 1240 1241void GuiEditCtrl::cloneSelection() 1242{ 1243 Vector< GuiControl*> newSelection; 1244 1245 // Clone the controls in the current selection. 1246 1247 const U32 numOldControls = mSelectedControls.size(); 1248 for( U32 i = 0; i < numOldControls; ++ i ) 1249 { 1250 GuiControl* ctrl = mSelectedControls[ i ]; 1251 1252 // If parent is in selection, too, skip to prevent multiple clones. 1253 1254 if( ctrl->getParent() && selectionContains( ctrl->getParent() ) ) 1255 continue; 1256 1257 // Clone and add to set. 1258 1259 GuiControl* clone = dynamic_cast< GuiControl* >( ctrl->deepClone() ); 1260 if( clone ) 1261 newSelection.push_back( clone ); 1262 } 1263 1264 // Exchange the selection set. 1265 1266 clearSelection(); 1267 const U32 numNewControls = newSelection.size(); 1268 for( U32 i = 0; i < numNewControls; ++ i ) 1269 addSelection( newSelection[ i ] ); 1270 1271 // Callback for undo. 1272 1273 onSelectionCloned_callback( getSelectedSet() ); 1274} 1275 1276//----------------------------------------------------------------------------- 1277 1278void GuiEditCtrl::deleteSelection() 1279{ 1280 // Notify script for undo. 1281 1282 onTrashSelection_callback( getSelectedSet() ); 1283 1284 // Move all objects in selection to trash. 1285 1286 Vector< GuiControl* >::iterator i; 1287 for( i = mSelectedControls.begin(); i != mSelectedControls.end(); i ++ ) 1288 { 1289 if( ( *i ) == getCurrentAddSet() ) 1290 setCurrentAddSet( getContentControl(), false ); 1291 1292 mTrash->addObject( *i ); 1293 } 1294 1295 clearSelection(); 1296 1297 // Notify script it needs to update its views. 1298 1299 onHierarchyChanged_callback(); 1300} 1301 1302//----------------------------------------------------------------------------- 1303 1304void GuiEditCtrl::loadSelection( const char* filename ) 1305{ 1306 // Set redefine behavior to rename. 1307 1308 const char* oldRedefineBehavior = Con::getVariable( "$Con::redefineBehavior" ); 1309 Con::setVariable( "$Con::redefineBehavior", "renameNew" ); 1310 1311 // Exec the file or clipboard contents with the saved selection set. 1312 1313 if( filename ) 1314 Con::executef( "exec", filename ); 1315 else 1316 Con::evaluate( Platform::getClipboard() ); 1317 1318 SimSet* set; 1319 if( !Sim::findObject( "guiClipboard", set ) ) 1320 { 1321 if( filename ) 1322 Con::errorf( "GuiEditCtrl::loadSelection() - could not find 'guiClipboard' in '%s'", filename ); 1323 else 1324 Con::errorf( "GuiEditCtrl::loadSelection() - could not find 'guiClipboard'" ); 1325 return; 1326 } 1327 1328 // Restore redefine behavior. 1329 1330 Con::setVariable( "$Con::redefineBehavior", oldRedefineBehavior ); 1331 1332 // Add the objects in the set. 1333 1334 if( set->size() ) 1335 { 1336 clearSelection(); 1337 1338 GuiControlVector ctrls; 1339 for( U32 i = 0, num = set->size(); i < num; ++ i ) 1340 { 1341 GuiControl *ctrl = dynamic_cast< GuiControl* >( ( *set )[ i ] ); 1342 if( ctrl ) 1343 { 1344 getCurrentAddSet()->addObject( ctrl ); 1345 ctrls.push_back( ctrl ); 1346 } 1347 } 1348 1349 // Select all controls. We need to perform this here rather than in the 1350 // loop above as addSelection() will modify the current add set. 1351 for( U32 i = 0; i < ctrls.size(); ++ i ) 1352 { 1353 addSelection( ctrls[i] ); 1354 } 1355 1356 // Undo 1357 onAddNewCtrlSet_callback( getSelectedSet() ); 1358 1359 // Notify the script it needs to update its treeview. 1360 1361 onHierarchyChanged_callback(); 1362 } 1363 set->deleteObject(); 1364} 1365 1366//----------------------------------------------------------------------------- 1367 1368void GuiEditCtrl::saveSelection( const char* filename ) 1369{ 1370 // If there are no selected objects, then don't save. 1371 1372 if( mSelectedControls.size() == 0 ) 1373 return; 1374 1375 // Open the stream. 1376 1377 Stream* stream; 1378 if( filename ) 1379 { 1380 stream = FileStream::createAndOpen( filename, Torque::FS::File::Write ); 1381 if( !stream ) 1382 { 1383 Con::errorf( "GuiEditCtrl::saveSelection - could not open '%s' for writing", filename ); 1384 return; 1385 } 1386 } 1387 else 1388 stream = new MemStream( 4096 ); 1389 1390 // Create a temporary SimSet. 1391 1392 SimSet* clipboardSet = new SimSet; 1393 clipboardSet->registerObject(); 1394 Sim::getRootGroup()->addObject( clipboardSet, "guiClipboard" ); 1395 1396 // Add the selected controls to the set. 1397 1398 for( Vector< GuiControl* >::iterator i = mSelectedControls.begin(); 1399 i != mSelectedControls.end(); ++ i ) 1400 { 1401 GuiControl* ctrl = *i; 1402 if( !selectionContainsParentOf( ctrl ) ) 1403 clipboardSet->addObject( ctrl ); 1404 } 1405 1406 // Write the SimSet. Use the IgnoreCanSave to ensure the controls 1407 // get actually written out (also disables the default parent inheritance 1408 // behavior for the flag). 1409 1410 clipboardSet->write( *stream, 0, IgnoreCanSave ); 1411 clipboardSet->deleteObject(); 1412 1413 // If we were writing to a memory stream, copy to clipboard 1414 // now. 1415 1416 if( !filename ) 1417 { 1418 MemStream* memStream = static_cast< MemStream* >( stream ); 1419 memStream->write( U8( 0 ) ); 1420 Platform::setClipboard( ( const char* ) memStream->getBuffer() ); 1421 } 1422 1423 delete stream; 1424} 1425 1426//----------------------------------------------------------------------------- 1427 1428void GuiEditCtrl::selectAll() 1429{ 1430 GuiControl::iterator i; 1431 1432 clearSelection(); 1433 for(i = getCurrentAddSet()->begin(); i != getCurrentAddSet()->end(); i++) 1434 { 1435 GuiControl *ctrl = dynamic_cast<GuiControl *>(*i); 1436 addSelection( ctrl ); 1437 } 1438} 1439 1440//----------------------------------------------------------------------------- 1441 1442void GuiEditCtrl::bringToFront() 1443{ 1444 if( getNumSelected() != 1 ) 1445 return; 1446 1447 GuiControl* ctrl = mSelectedControls.first(); 1448 ctrl->getParent()->pushObjectToBack( ctrl ); 1449} 1450 1451//----------------------------------------------------------------------------- 1452 1453void GuiEditCtrl::pushToBack() 1454{ 1455 if( getNumSelected() != 1 ) 1456 return; 1457 1458 GuiControl* ctrl = mSelectedControls.first(); 1459 ctrl->getParent()->bringObjectToFront( ctrl ); 1460} 1461 1462//----------------------------------------------------------------------------- 1463 1464RectI GuiEditCtrl::getSelectionBounds() const 1465{ 1466 Vector<GuiControl *>::const_iterator i = mSelectedControls.begin(); 1467 1468 Point2I minPos = (*i)->localToGlobalCoord( Point2I( 0, 0 ) ); 1469 Point2I maxPos = minPos; 1470 1471 for(; i != mSelectedControls.end(); i++) 1472 { 1473 Point2I iPos = (**i).localToGlobalCoord( Point2I( 0 , 0 ) ); 1474 1475 minPos.x = getMin( iPos.x, minPos.x ); 1476 minPos.y = getMin( iPos.y, minPos.y ); 1477 1478 Point2I iExt = ( **i ).getExtent(); 1479 1480 iPos.x += iExt.x; 1481 iPos.y += iExt.y; 1482 1483 maxPos.x = getMax( iPos.x, maxPos.x ); 1484 maxPos.y = getMax( iPos.y, maxPos.y ); 1485 } 1486 1487 minPos = getContentControl()->globalToLocalCoord( minPos ); 1488 maxPos = getContentControl()->globalToLocalCoord( maxPos ); 1489 1490 return RectI( minPos.x, minPos.y, ( maxPos.x - minPos.x ), ( maxPos.y - minPos.y ) ); 1491} 1492 1493//----------------------------------------------------------------------------- 1494 1495RectI GuiEditCtrl::getSelectionGlobalBounds() const 1496{ 1497 Point2I minb( S32_MAX, S32_MAX ); 1498 Point2I maxb( S32_MIN, S32_MIN ); 1499 1500 for( U32 i = 0, num = mSelectedControls.size(); i < num; ++ i ) 1501 { 1502 // Min. 1503 1504 Point2I pos = mSelectedControls[ i ]->localToGlobalCoord( Point2I( 0, 0 ) ); 1505 1506 minb.x = getMin( minb.x, pos.x ); 1507 minb.y = getMin( minb.y, pos.y ); 1508 1509 // Max. 1510 1511 const Point2I extent = mSelectedControls[ i ]->getExtent(); 1512 1513 maxb.x = getMax( maxb.x, pos.x + extent.x ); 1514 maxb.y = getMax( maxb.y, pos.y + extent.y ); 1515 } 1516 1517 RectI bounds( minb.x, minb.y, maxb.x - minb.x, maxb.y - minb.y ); 1518 return bounds; 1519} 1520 1521//----------------------------------------------------------------------------- 1522 1523bool GuiEditCtrl::selectionContains( GuiControl *ctrl ) 1524{ 1525 Vector<GuiControl *>::iterator i; 1526 for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++) 1527 if (ctrl == *i) return true; 1528 return false; 1529} 1530 1531//----------------------------------------------------------------------------- 1532 1533bool GuiEditCtrl::selectionContainsParentOf( GuiControl* ctrl ) 1534{ 1535 GuiControl* parent = ctrl->getParent(); 1536 while( parent && parent != getContentControl() ) 1537 { 1538 if( selectionContains( parent ) ) 1539 return true; 1540 1541 parent = parent->getParent(); 1542 } 1543 1544 return false; 1545} 1546 1547//----------------------------------------------------------------------------- 1548 1549void GuiEditCtrl::select( GuiControl* ctrl ) 1550{ 1551 clearSelection(); 1552 addSelection( ctrl ); 1553} 1554 1555//----------------------------------------------------------------------------- 1556 1557void GuiEditCtrl::updateSelectedSet() 1558{ 1559 mSelectedSet->clear(); 1560 Vector<GuiControl*>::iterator i; 1561 for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++) 1562 { 1563 mSelectedSet->addObject(*i); 1564 } 1565} 1566 1567//----------------------------------------------------------------------------- 1568 1569void GuiEditCtrl::addSelectControlsInRegion( const RectI& rect, U32 flags ) 1570{ 1571 // Do a hit test on the content control. 1572 1573 canHitSelectedControls( false ); 1574 Vector< GuiControl*> hits; 1575 1576 if( mFullBoxSelection ) 1577 flags |= GuiControl::HIT_FullBoxOnly; 1578 1579 getContentControl()->findHitControls( rect, hits, flags ); 1580 canHitSelectedControls( true ); 1581 1582 // Add all controls that got hit. 1583 1584 for( U32 i = 0, num = hits.size(); i < num; ++ i ) 1585 addSelection( hits[ i ] ); 1586} 1587 1588//----------------------------------------------------------------------------- 1589 1590void GuiEditCtrl::addSelectControlAt( const Point2I& pos ) 1591{ 1592 // Run a hit test. 1593 1594 canHitSelectedControls( false ); 1595 GuiControl* hit = getContentControl()->findHitControl( pos ); 1596 canHitSelectedControls( true ); 1597 1598 // Add to selection. 1599 1600 if( hit ) 1601 addSelection( hit ); 1602} 1603 1604//----------------------------------------------------------------------------- 1605 1606void GuiEditCtrl::resizeControlsInSelectionBy( const Point2I& delta, U32 mode ) 1607{ 1608 for( U32 i = 0, num = mSelectedControls.size(); i < num; ++ i ) 1609 { 1610 GuiControl *ctrl = mSelectedControls[ i ]; 1611 if( ctrl->isLocked() ) 1612 continue; 1613 1614 Point2I minExtent = ctrl->getMinExtent(); 1615 Point2I newPosition = ctrl->getPosition(); 1616 Point2I newExtent = ctrl->getExtent(); 1617 1618 if( mSizingMode & sizingLeft ) 1619 { 1620 newPosition.x += delta.x; 1621 newExtent.x -= delta.x; 1622 1623 if( newExtent.x < minExtent.x ) 1624 { 1625 newPosition.x -= minExtent.x - newExtent.x; 1626 newExtent.x = minExtent.x; 1627 } 1628 } 1629 else if( mSizingMode & sizingRight ) 1630 { 1631 newExtent.x += delta.x; 1632 1633 if( newExtent.x < minExtent.x ) 1634 newExtent.x = minExtent.x; 1635 } 1636 1637 if( mSizingMode & sizingTop ) 1638 { 1639 newPosition.y += delta.y; 1640 newExtent.y -= delta.y; 1641 1642 if( newExtent.y < minExtent.y ) 1643 { 1644 newPosition.y -= minExtent.y - newExtent.y; 1645 newExtent.y = minExtent.y; 1646 } 1647 } 1648 else if( mSizingMode & sizingBottom ) 1649 { 1650 newExtent.y += delta.y; 1651 1652 if( newExtent.y < minExtent.y ) 1653 newExtent.y = minExtent.y; 1654 } 1655 1656 ctrl->resize( newPosition, newExtent ); 1657 } 1658 1659 if( mSelectedControls.size() == 1 ) 1660 onSelectionResized_callback( mSelectedControls[ 0 ] ); 1661} 1662 1663//----------------------------------------------------------------------------- 1664 1665void GuiEditCtrl::fitIntoParents( bool width, bool height ) 1666{ 1667 // Record undo. 1668 1669 onFitIntoParent_callback( width, height ); 1670 1671 // Fit. 1672 1673 for( U32 i = 0; i < mSelectedControls.size(); ++ i ) 1674 { 1675 GuiControl* ctrl = mSelectedControls[ i ]; 1676 GuiControl* parent = ctrl->getParent(); 1677 1678 Point2I position = ctrl->getPosition(); 1679 if( width ) 1680 position.x = 0; 1681 if( height ) 1682 position.y = 0; 1683 1684 Point2I extents = ctrl->getExtent(); 1685 if( width ) 1686 extents.x = parent->getWidth(); 1687 if( height ) 1688 extents.y = parent->getHeight(); 1689 1690 ctrl->resize( position, extents ); 1691 } 1692} 1693 1694//----------------------------------------------------------------------------- 1695 1696void GuiEditCtrl::selectParents( bool addToSelection ) 1697{ 1698 Vector< GuiControl*> parents; 1699 1700 // Collect all parents. 1701 1702 for( U32 i = 0; i < mSelectedControls.size(); ++ i ) 1703 { 1704 GuiControl* ctrl = mSelectedControls[ i ]; 1705 if( ctrl != mContentControl && ctrl->getParent() != mContentControl ) 1706 parents.push_back( mSelectedControls[ i ]->getParent() ); 1707 } 1708 1709 // If there's no parents to select, don't 1710 // change the selection. 1711 1712 if( parents.empty() ) 1713 return; 1714 1715 // Blast selection if need be. 1716 1717 if( !addToSelection ) 1718 clearSelection(); 1719 1720 // Add the parents. 1721 1722 for( U32 i = 0; i < parents.size(); ++ i ) 1723 addSelection( parents[ i ] ); 1724} 1725 1726//----------------------------------------------------------------------------- 1727 1728void GuiEditCtrl::selectChildren( bool addToSelection ) 1729{ 1730 Vector< GuiControl*> children; 1731 1732 // Collect all children. 1733 1734 for( U32 i = 0; i < mSelectedControls.size(); ++ i ) 1735 { 1736 GuiControl* parent = mSelectedControls[ i ]; 1737 for( GuiControl::iterator iter = parent->begin(); iter != parent->end(); ++ iter ) 1738 { 1739 GuiControl* child = dynamic_cast< GuiControl* >( *iter ); 1740 if( child ) 1741 children.push_back( child ); 1742 } 1743 } 1744 1745 // If there's no children to select, don't 1746 // change the selection. 1747 1748 if( children.empty() ) 1749 return; 1750 1751 // Blast selection if need be. 1752 1753 if( !addToSelection ) 1754 clearSelection(); 1755 1756 // Add the children. 1757 1758 for( U32 i = 0; i < children.size(); ++ i ) 1759 addSelection( children[ i ] ); 1760} 1761 1762//============================================================================= 1763// Guides. 1764//============================================================================= 1765// MARK: ---- Guides ---- 1766 1767//----------------------------------------------------------------------------- 1768 1769void GuiEditCtrl::readGuides( guideAxis axis, GuiControl* ctrl ) 1770{ 1771 // Read the guide indices from the vector stored on the respective dynamic 1772 // property of the control. 1773 1774 const char* guideIndices = ctrl->getDataField( smGuidesPropertyName[ axis ], NULL ); 1775 if( guideIndices && guideIndices[ 0 ] ) 1776 { 1777 U32 index = 0; 1778 while( true ) 1779 { 1780 const char* posStr = StringUnit::getUnit( guideIndices, index, " \t" ); 1781 if( !posStr[ 0 ] ) 1782 break; 1783 1784 mGuides[ axis ].push_back( dAtoi( posStr ) ); 1785 1786 index ++; 1787 } 1788 } 1789} 1790 1791//----------------------------------------------------------------------------- 1792 1793void GuiEditCtrl::writeGuides( guideAxis axis, GuiControl* ctrl ) 1794{ 1795 // Store the guide indices of the given axis in a vector on the respective 1796 // dynamic property of the control. 1797 1798 StringBuilder str; 1799 bool isFirst = true; 1800 for( U32 i = 0, num = mGuides[ axis ].size(); i < num; ++ i ) 1801 { 1802 if( !isFirst ) 1803 str.append( ' ' ); 1804 1805 char buffer[ 32 ]; 1806 dSprintf( buffer, sizeof( buffer ), "%i", mGuides[ axis ][ i ] ); 1807 1808 str.append( buffer ); 1809 1810 isFirst = false; 1811 } 1812 1813 String value = str.end(); 1814 ctrl->setDataField( smGuidesPropertyName[ axis ], NULL, value ); 1815} 1816 1817//----------------------------------------------------------------------------- 1818 1819S32 GuiEditCtrl::findGuide( guideAxis axis, const Point2I& point, U32 tolerance ) 1820{ 1821 const S32 p = ( point - localToGlobalCoord( Point2I( 0, 0 ) ) )[ axis ]; 1822 1823 for( U32 i = 0, num = mGuides[ axis ].size(); i < num; ++ i ) 1824 { 1825 const S32 g = mGuides[ axis ][ i ]; 1826 if( p >= ( g - tolerance ) && 1827 p <= ( g + tolerance ) ) 1828 return i; 1829 } 1830 1831 return -1; 1832} 1833 1834//============================================================================= 1835// Snapping. 1836//============================================================================= 1837// MARK: ---- Snapping ---- 1838 1839//----------------------------------------------------------------------------- 1840 1841RectI GuiEditCtrl::getSnapRegion( snappingAxis axis, const Point2I& center ) const 1842{ 1843 RectI rootBounds = getContentControl()->getBounds(); 1844 1845 RectI rect; 1846 if( axis == SnapHorizontal ) 1847 rect = RectI( rootBounds.point.x, 1848 center.y - mSnapSensitivity, 1849 rootBounds.extent.x, 1850 mSnapSensitivity * 2 ); 1851 else // SnapVertical 1852 rect = RectI( center.x - mSnapSensitivity, 1853 rootBounds.point.y, 1854 mSnapSensitivity * 2, 1855 rootBounds.extent.y ); 1856 1857 // Clip against root bounds. 1858 1859 rect.intersect( rootBounds ); 1860 1861 return rect; 1862} 1863 1864//----------------------------------------------------------------------------- 1865 1866void GuiEditCtrl::registerSnap( snappingAxis axis, const Point2I& mousePoint, const Point2I& point, snappingEdges edge, GuiControl* ctrl ) 1867{ 1868 bool takeNewSnap = false; 1869 const Point2I globalPoint = getContentControl()->localToGlobalCoord( point ); 1870 1871 // If we have no snap yet, just take this one. 1872 1873 if( !mSnapped[ axis ] ) 1874 takeNewSnap = true; 1875 1876 // Otherwise see if this snap is the better one. 1877 1878 else 1879 { 1880 // Compare deltas to pointer. 1881 1882 S32 deltaCurrent = mAbs( mSnapOffset[ axis ] - mousePoint[ axis ] ); 1883 S32 deltaNew = mAbs( globalPoint[ axis ] - mousePoint[ axis ] ); 1884 1885 if( deltaCurrent > deltaNew ) 1886 takeNewSnap = true; 1887 } 1888 1889 if( takeNewSnap ) 1890 { 1891 mSnapped[ axis ] = true; 1892 mSnapOffset[ axis ] = globalPoint[ axis ]; 1893 mSnapEdge[ axis ] = edge; 1894 mSnapTargets[ axis ] = ctrl; 1895 } 1896} 1897 1898//----------------------------------------------------------------------------- 1899 1900void GuiEditCtrl::findSnaps( snappingAxis axis, const Point2I& mousePoint, const RectI& minRegion, const RectI& midRegion, const RectI& maxRegion ) 1901{ 1902 // Find controls with edge in either minRegion, midRegion, or maxRegion 1903 // (depending on snap settings). 1904 1905 for( U32 i = 0, num = mSnapHits[ axis ].size(); i < num; ++ i ) 1906 { 1907 GuiControl* ctrl = mSnapHits[ axis ][ i ]; 1908 if( ctrl == getContentControl() && !mSnapToCanvas ) 1909 continue; 1910 1911 RectI bounds = ctrl->getGlobalBounds(); 1912 bounds.point = getContentControl()->globalToLocalCoord( bounds.point ); 1913 1914 // Compute points on min, mid, and max lines of control. 1915 1916 Point2I min = bounds.point; 1917 Point2I max = min + bounds.extent - Point2I( 1, 1 ); 1918 1919 Point2I mid = min; 1920 mid.x += bounds.extent.x / 2; 1921 mid.y += bounds.extent.y / 2; 1922 1923 // Test edge snap cases. 1924 1925 if( mSnapToEdges ) 1926 { 1927 // Min to min. 1928 1929 if( minRegion.pointInRect( min ) ) 1930 registerSnap( axis, mousePoint, min, SnapEdgeMin, ctrl ); 1931 1932 // Max to max. 1933 1934 if( maxRegion.pointInRect( max ) ) 1935 registerSnap( axis, mousePoint, max, SnapEdgeMax, ctrl ); 1936 1937 // Min to max. 1938 1939 if( minRegion.pointInRect( max ) ) 1940 registerSnap( axis, mousePoint, max, SnapEdgeMin, ctrl ); 1941 1942 // Max to min. 1943 1944 if( maxRegion.pointInRect( min ) ) 1945 registerSnap( axis, mousePoint, min, SnapEdgeMax, ctrl ); 1946 } 1947 1948 // Test center snap cases. 1949 1950 if( mSnapToCenters ) 1951 { 1952 // Mid to mid. 1953 1954 if( midRegion.pointInRect( mid ) ) 1955 registerSnap( axis, mousePoint, mid, SnapEdgeMid, ctrl ); 1956 } 1957 1958 // Test combined center+edge snap cases. 1959 1960 if( mSnapToEdges && mSnapToCenters ) 1961 { 1962 // Min to mid. 1963 1964 if( minRegion.pointInRect( mid ) ) 1965 registerSnap( axis, mousePoint, mid, SnapEdgeMin, ctrl ); 1966 1967 // Max to mid. 1968 1969 if( maxRegion.pointInRect( mid ) ) 1970 registerSnap( axis, mousePoint, mid, SnapEdgeMax, ctrl ); 1971 1972 // Mid to min. 1973 1974 if( midRegion.pointInRect( min ) ) 1975 registerSnap( axis, mousePoint, min, SnapEdgeMid, ctrl ); 1976 1977 // Mid to max. 1978 1979 if( midRegion.pointInRect( max ) ) 1980 registerSnap( axis, mousePoint, max, SnapEdgeMid, ctrl ); 1981 } 1982 } 1983} 1984 1985//----------------------------------------------------------------------------- 1986 1987void GuiEditCtrl::doControlSnap( const GuiEvent& event, const RectI& selectionBounds, const RectI& selectionBoundsGlobal, Point2I& delta ) 1988{ 1989 if( !mSnapToControls || ( !mSnapToEdges && !mSnapToCenters ) ) 1990 return; 1991 1992 // Allow restricting to just vertical (ALT+SHIFT) or just horizontal (ALT+CTRL) 1993 // snaps. 1994 1995 bool snapAxisEnabled[ 2 ]; 1996 1997 if( event.modifier & SI_PRIMARY_ALT && event.modifier & SI_SHIFT ) 1998 snapAxisEnabled[ SnapHorizontal ] = false; 1999 else 2000 snapAxisEnabled[ SnapHorizontal ] = true; 2001 2002 if( event.modifier & SI_PRIMARY_ALT && event.modifier & SI_CTRL ) 2003 snapAxisEnabled[ SnapVertical ] = false; 2004 else 2005 snapAxisEnabled[ SnapVertical ] = true; 2006 2007 // Compute snap regions. There is one region centered on and aligned with 2008 // each of the selection bounds edges plus two regions aligned on the selection 2009 // bounds center. For the selection bounds origin, we use the point that the 2010 // selection would be at, if we had already done the mouse drag. 2011 2012 RectI snapRegions[ 2 ][ 3 ]; 2013 Point2I projectedOrigin( selectionBounds.point + delta ); 2014 dMemset( snapRegions, 0, sizeof( snapRegions ) ); 2015 2016 for( U32 axis = 0; axis < 2; ++ axis ) 2017 { 2018 if( !snapAxisEnabled[ axis ] ) 2019 continue; 2020 2021 if( mSizingMode == sizingNone || 2022 ( axis == 0 && mSizingMode & sizingLeft ) || 2023 ( axis == 1 && mSizingMode & sizingTop ) ) 2024 snapRegions[ axis ][ 0 ] = getSnapRegion( ( snappingAxis ) axis, projectedOrigin ); 2025 2026 if( mSizingMode == sizingNone ) 2027 snapRegions[ axis ][ 1 ] = getSnapRegion( ( snappingAxis ) axis, projectedOrigin + Point2I( selectionBounds.extent.x / 2, selectionBounds.extent.y / 2 ) ); 2028 2029 if( mSizingMode == sizingNone || 2030 ( axis == 0 && mSizingMode & sizingRight ) || 2031 ( axis == 1 && mSizingMode & sizingBottom ) ) 2032 snapRegions[ axis ][ 2 ] = getSnapRegion( ( snappingAxis ) axis, projectedOrigin + selectionBounds.extent - Point2I( 1, 1 ) ); 2033 } 2034 2035 // Find hit controls. 2036 2037 canHitSelectedControls( false ); 2038 2039 if( mSnapToEdges ) 2040 { 2041 for( U32 axis = 0; axis < 2; ++ axis ) 2042 if( snapAxisEnabled[ axis ] ) 2043 { 2044 getContentControl()->findHitControls( snapRegions[ axis ][ 0 ], mSnapHits[ axis ], HIT_NoCanHitNoRecurse ); 2045 getContentControl()->findHitControls( snapRegions[ axis ][ 2 ], mSnapHits[ axis ], HIT_NoCanHitNoRecurse ); 2046 } 2047 } 2048 if( mSnapToCenters && mSizingMode == sizingNone ) 2049 { 2050 for( U32 axis = 0; axis < 2; ++ axis ) 2051 if( snapAxisEnabled[ axis ] ) 2052 getContentControl()->findHitControls( snapRegions[ axis ][ 1 ], mSnapHits[ axis ], HIT_NoCanHitNoRecurse ); 2053 } 2054 2055 canHitSelectedControls( true ); 2056 2057 // Add the content control itself to the hit controls 2058 // so we can always get a snap on it. 2059 2060 if( mSnapToCanvas ) 2061 { 2062 mSnapHits[ 0 ].push_back( mContentControl ); 2063 mSnapHits[ 1 ].push_back( mContentControl ); 2064 } 2065 2066 // Find snaps. 2067 2068 for( U32 i = 0; i < 2; ++ i ) 2069 if( snapAxisEnabled[ i ] ) 2070 findSnaps( ( snappingAxis ) i, 2071 event.mousePoint, 2072 snapRegions[ i ][ 0 ], 2073 snapRegions[ i ][ 1 ], 2074 snapRegions[ i ][ 2 ] ); 2075 2076 // Clean up. 2077 2078 mSnapHits[ 0 ].clear(); 2079 mSnapHits[ 1 ].clear(); 2080} 2081 2082//----------------------------------------------------------------------------- 2083 2084void GuiEditCtrl::doGridSnap( const GuiEvent& event, const RectI& selectionBounds, const RectI& selectionBoundsGlobal, Point2I& delta ) 2085{ 2086 delta += selectionBounds.point; 2087 2088 if( mGridSnap.x ) 2089 delta.x -= delta.x % mGridSnap.x; 2090 if( mGridSnap.y ) 2091 delta.y -= delta.y % mGridSnap.y; 2092 2093 delta -= selectionBounds.point; 2094} 2095 2096//----------------------------------------------------------------------------- 2097 2098void GuiEditCtrl::doGuideSnap( const GuiEvent& event, const RectI& selectionBounds, const RectI& selectionBoundsGlobal, Point2I& delta ) 2099{ 2100 if( !mSnapToGuides ) 2101 return; 2102 2103 Point2I min = getContentControl()->localToGlobalCoord( selectionBounds.point + delta ); 2104 Point2I mid = min + selectionBounds.extent / 2; 2105 Point2I max = min + selectionBounds.extent - Point2I( 1, 1 ); 2106 2107 for( U32 axis = 0; axis < 2; ++ axis ) 2108 { 2109 if( mSnapToEdges ) 2110 { 2111 S32 guideMin = -1; 2112 S32 guideMax = -1; 2113 2114 if( mSizingMode == sizingNone || 2115 ( axis == 0 && mSizingMode & sizingLeft ) || 2116 ( axis == 1 && mSizingMode & sizingTop ) ) 2117 guideMin = findGuide( ( guideAxis ) axis, min, mSnapSensitivity ); 2118 if( mSizingMode == sizingNone || 2119 ( axis == 0 && mSizingMode & sizingRight ) || 2120 ( axis == 1 && mSizingMode & sizingBottom ) ) 2121 guideMax = findGuide( ( guideAxis ) axis, max, mSnapSensitivity ); 2122 2123 Point2I pos( 0, 0 ); 2124 2125 if( guideMin != -1 ) 2126 { 2127 pos[ axis ] = mGuides[ axis ][ guideMin ]; 2128 registerSnap( ( snappingAxis ) axis, event.mousePoint, pos, SnapEdgeMin ); 2129 } 2130 2131 if( guideMax != -1 ) 2132 { 2133 pos[ axis ] = mGuides[ axis ][ guideMax ]; 2134 registerSnap( ( snappingAxis ) axis, event.mousePoint, pos, SnapEdgeMax ); 2135 } 2136 } 2137 2138 if( mSnapToCenters && mSizingMode == sizingNone ) 2139 { 2140 const S32 guideMid = findGuide( ( guideAxis ) axis, mid, mSnapSensitivity ); 2141 if( guideMid != -1 ) 2142 { 2143 Point2I pos( 0, 0 ); 2144 pos[ axis ] = mGuides[ axis ][ guideMid ]; 2145 registerSnap( ( snappingAxis ) axis, event.mousePoint, pos, SnapEdgeMid ); 2146 } 2147 } 2148 } 2149} 2150 2151//----------------------------------------------------------------------------- 2152 2153void GuiEditCtrl::doSnapping( const GuiEvent& event, const RectI& selectionBounds, Point2I& delta ) 2154{ 2155 // Clear snapping. If we have snapping on, we want to find a new best snap. 2156 2157 mSnapped[ SnapVertical ] = false; 2158 mSnapped[ SnapHorizontal ] = false; 2159 2160 // Compute global bounds. 2161 2162 RectI selectionBoundsGlobal = selectionBounds; 2163 selectionBoundsGlobal.point = getContentControl()->localToGlobalCoord( selectionBoundsGlobal.point ); 2164 2165 // Apply the snaps. 2166 2167 doGridSnap( event, selectionBounds, selectionBoundsGlobal, delta ); 2168 doGuideSnap( event, selectionBounds, selectionBoundsGlobal, delta ); 2169 doControlSnap( event, selectionBounds, selectionBoundsGlobal, delta ); 2170 2171 // If we have a horizontal snap, compute a delta. 2172 2173 if( mSnapped[ SnapVertical ] ) 2174 snapDelta( SnapVertical, mSnapEdge[ SnapVertical ], mSnapOffset[ SnapVertical ], selectionBoundsGlobal, delta ); 2175 2176 // If we have a vertical snap, compute a delta. 2177 2178 if( mSnapped[ SnapHorizontal ] ) 2179 snapDelta( SnapHorizontal, mSnapEdge[ SnapHorizontal ], mSnapOffset[ SnapHorizontal ], selectionBoundsGlobal, delta ); 2180} 2181 2182//----------------------------------------------------------------------------- 2183 2184void GuiEditCtrl::snapToGrid( Point2I& point ) 2185{ 2186 if( mGridSnap.x ) 2187 point.x -= point.x % mGridSnap.x; 2188 if( mGridSnap.y ) 2189 point.y -= point.y % mGridSnap.y; 2190} 2191 2192//============================================================================= 2193// Misc. 2194//============================================================================= 2195// MARK: ---- Misc ---- 2196 2197//----------------------------------------------------------------------------- 2198 2199void GuiEditCtrl::setContentControl(GuiControl *root) 2200{ 2201 mContentControl = root; 2202 if( root != NULL ) 2203 root->mIsContainer = true; 2204 2205 setCurrentAddSet( root ); 2206} 2207 2208//----------------------------------------------------------------------------- 2209 2210void GuiEditCtrl::setEditMode(bool value) 2211{ 2212 mActive = value; 2213 2214 clearSelection(); 2215 if( mActive && mAwake ) 2216 mCurrentAddSet = NULL; 2217} 2218 2219//----------------------------------------------------------------------------- 2220 2221void GuiEditCtrl::setMouseMode( mouseModes mode ) 2222{ 2223 if( mMouseDownMode != mode ) 2224 { 2225 mMouseDownMode = mode; 2226 2227 onMouseModeChange_callback(); 2228 } 2229} 2230 2231//----------------------------------------------------------------------------- 2232 2233void GuiEditCtrl::setCurrentAddSet(GuiControl *ctrl, bool doclearSelection) 2234{ 2235 if (ctrl != mCurrentAddSet) 2236 { 2237 if(doclearSelection) 2238 clearSelection(); 2239 2240 mCurrentAddSet = ctrl; 2241 } 2242} 2243 2244//----------------------------------------------------------------------------- 2245 2246GuiControl* GuiEditCtrl::getCurrentAddSet() 2247{ 2248 if( !mCurrentAddSet ) 2249 setCurrentAddSet( mContentControl, false ); 2250 2251 return mCurrentAddSet; 2252} 2253 2254//----------------------------------------------------------------------------- 2255 2256void GuiEditCtrl::addNewControl(GuiControl *ctrl) 2257{ 2258 getCurrentAddSet()->addObject(ctrl); 2259 select( ctrl ); 2260 2261 // undo 2262 onAddNewCtrl_callback( ctrl ); 2263} 2264 2265//----------------------------------------------------------------------------- 2266 2267S32 GuiEditCtrl::getSizingHitKnobs(const Point2I &pt, const RectI &box) 2268{ 2269 S32 lx = box.point.x, rx = box.point.x + box.extent.x - 1; 2270 S32 cx = (lx + rx) >> 1; 2271 S32 ty = box.point.y, by = box.point.y + box.extent.y - 1; 2272 S32 cy = (ty + by) >> 1; 2273 2274 // adjust nuts, so they dont straddle the controls 2275 lx -= NUT_SIZE; 2276 ty -= NUT_SIZE; 2277 rx += NUT_SIZE; 2278 by += NUT_SIZE; 2279 2280 if (inNut(pt, lx, ty)) 2281 return sizingLeft | sizingTop; 2282 if (inNut(pt, cx, ty)) 2283 return sizingTop; 2284 if (inNut(pt, rx, ty)) 2285 return sizingRight | sizingTop; 2286 if (inNut(pt, lx, by)) 2287 return sizingLeft | sizingBottom; 2288 if (inNut(pt, cx, by)) 2289 return sizingBottom; 2290 if (inNut(pt, rx, by)) 2291 return sizingRight | sizingBottom; 2292 if (inNut(pt, lx, cy)) 2293 return sizingLeft; 2294 if (inNut(pt, rx, cy)) 2295 return sizingRight; 2296 return sizingNone; 2297} 2298 2299//----------------------------------------------------------------------------- 2300 2301void GuiEditCtrl::getDragRect(RectI &box) 2302{ 2303 box.point.x = getMin(mLastMousePos.x, mSelectionAnchor.x); 2304 box.extent.x = getMax(mLastMousePos.x, mSelectionAnchor.x) - box.point.x + 1; 2305 box.point.y = getMin(mLastMousePos.y, mSelectionAnchor.y); 2306 box.extent.y = getMax(mLastMousePos.y, mSelectionAnchor.y) - box.point.y + 1; 2307} 2308 2309//----------------------------------------------------------------------------- 2310 2311void GuiEditCtrl::getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent) 2312{ 2313 GuiCanvas *pRoot = getRoot(); 2314 if( !pRoot ) 2315 return; 2316 2317 showCursor = false; 2318 cursor = NULL; 2319 2320 Point2I ctOffset; 2321 Point2I cext; 2322 GuiControl *ctrl; 2323 2324 Point2I mousePos = globalToLocalCoord(lastGuiEvent.mousePoint); 2325 2326 PlatformWindow *pWindow = static_cast<GuiCanvas*>(getRoot())->getPlatformWindow(); 2327 AssertFatal(pWindow != NULL,"GuiControl without owning platform window! This should not be possible."); 2328 PlatformCursorController *pController = pWindow->getCursorController(); 2329 AssertFatal(pController != NULL,"PlatformWindow without an owned CursorController!"); 2330 2331 S32 desiredCursor = PlatformCursorController::curArrow; 2332 2333 // first see if we hit a sizing knob on the currently selected control... 2334 if (mSelectedControls.size() == 1 ) 2335 { 2336 ctrl = mSelectedControls.first(); 2337 cext = ctrl->getExtent(); 2338 ctOffset = globalToLocalCoord(ctrl->localToGlobalCoord(Point2I(0,0))); 2339 RectI box(ctOffset.x,ctOffset.y,cext.x, cext.y); 2340 2341 GuiEditCtrl::sizingModes sizeMode = (GuiEditCtrl::sizingModes)getSizingHitKnobs(mousePos, box); 2342 2343 if( mMouseDownMode == SizingSelection ) 2344 { 2345 if ( ( mSizingMode == ( sizingBottom | sizingRight ) ) || ( mSizingMode == ( sizingTop | sizingLeft ) ) ) 2346 desiredCursor = PlatformCursorController::curResizeNWSE; 2347 else if ( ( mSizingMode == ( sizingBottom | sizingLeft ) ) || ( mSizingMode == ( sizingTop | sizingRight ) ) ) 2348 desiredCursor = PlatformCursorController::curResizeNESW; 2349 else if ( mSizingMode == sizingLeft || mSizingMode == sizingRight ) 2350 desiredCursor = PlatformCursorController::curResizeVert; 2351 else if (mSizingMode == sizingTop || mSizingMode == sizingBottom ) 2352 desiredCursor = PlatformCursorController::curResizeHorz; 2353 } 2354 else 2355 { 2356 // Check for current mouse position after checking for actual sizing mode 2357 if ( ( sizeMode == ( sizingBottom | sizingRight ) ) || ( sizeMode == ( sizingTop | sizingLeft ) ) ) 2358 desiredCursor = PlatformCursorController::curResizeNWSE; 2359 else if ( ( sizeMode == ( sizingBottom | sizingLeft ) ) || ( sizeMode == ( sizingTop | sizingRight ) ) ) 2360 desiredCursor = PlatformCursorController::curResizeNESW; 2361 else if (sizeMode == sizingLeft || sizeMode == sizingRight ) 2362 desiredCursor = PlatformCursorController::curResizeVert; 2363 else if (sizeMode == sizingTop || sizeMode == sizingBottom ) 2364 desiredCursor = PlatformCursorController::curResizeHorz; 2365 } 2366 } 2367 2368 if( mMouseDownMode == MovingSelection && cursor == NULL ) 2369 desiredCursor = PlatformCursorController::curResizeAll; 2370 2371 if( pRoot->mCursorChanged != desiredCursor ) 2372 { 2373 // We've already changed the cursor, 2374 // so set it back before we change it again. 2375 if(pRoot->mCursorChanged != -1) 2376 pController->popCursor(); 2377 2378 // Now change the cursor shape 2379 pController->pushCursor(desiredCursor); 2380 pRoot->mCursorChanged = desiredCursor; 2381 } 2382} 2383 2384//----------------------------------------------------------------------------- 2385 2386void GuiEditCtrl::setSnapToGrid(U32 gridsize) 2387{ 2388 if( gridsize != 0 ) 2389 gridsize = getMax( gridsize, ( U32 ) MIN_GRID_SIZE ); 2390 mGridSnap.set( gridsize, gridsize ); 2391} 2392 2393//----------------------------------------------------------------------------- 2394 2395void GuiEditCtrl::controlInspectPreApply(GuiControl* object) 2396{ 2397 // undo 2398 onControlInspectPreApply_callback( object ); 2399} 2400 2401//----------------------------------------------------------------------------- 2402 2403void GuiEditCtrl::controlInspectPostApply(GuiControl* object) 2404{ 2405 // undo 2406 onControlInspectPostApply_callback( object ); 2407} 2408 2409//----------------------------------------------------------------------------- 2410 2411void GuiEditCtrl::startDragMove( const Point2I& startPoint ) 2412{ 2413 mDragMoveUndo = true; 2414 2415 // For calculating mouse delta 2416 mDragBeginPoint = globalToLocalCoord( startPoint ); 2417 2418 // Allocate enough space for our selected controls 2419 mDragBeginPoints.reserve( mSelectedControls.size() ); 2420 2421 // For snapping to origin 2422 Vector<GuiControl *>::iterator i; 2423 for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++) 2424 mDragBeginPoints.push_back( (*i)->getPosition() ); 2425 2426 // Set Mouse Mode 2427 setMouseMode( MovingSelection ); 2428 2429 // undo 2430 onPreEdit_callback( getSelectedSet() ); 2431} 2432 2433//----------------------------------------------------------------------------- 2434 2435void GuiEditCtrl::startDragRectangle( const Point2I& startPoint ) 2436{ 2437 mSelectionAnchor = globalToLocalCoord( startPoint ); 2438 setMouseMode( DragSelecting ); 2439} 2440 2441//----------------------------------------------------------------------------- 2442 2443void GuiEditCtrl::startDragClone( const Point2I& startPoint ) 2444{ 2445 mDragBeginPoint = globalToLocalCoord( startPoint ); 2446 2447 setMouseMode( DragClone ); 2448} 2449 2450//----------------------------------------------------------------------------- 2451 2452void GuiEditCtrl::startMouseGuideDrag( guideAxis axis, U32 guideIndex, bool lockMouse ) 2453{ 2454 mDragGuideIndex[ axis ] = guideIndex; 2455 mDragGuide[ axis ] = true; 2456 2457 setMouseMode( DragGuide ); 2458 2459 // Grab the mouse. 2460 2461 if( lockMouse ) 2462 mouseLock(); 2463} 2464 2465//============================================================================= 2466// Console Methods. 2467//============================================================================= 2468// MARK: ---- Console Methods ---- 2469 2470//----------------------------------------------------------------------------- 2471 2472DefineConsoleMethod( GuiEditCtrl, getContentControl, S32, (), , "() - Return the toplevel control edited inside the GUI editor." ) 2473{ 2474 GuiControl* ctrl = object->getContentControl(); 2475 if( ctrl ) 2476 return ctrl->getId(); 2477 else 2478 return 0; 2479} 2480 2481//----------------------------------------------------------------------------- 2482 2483DefineConsoleMethod( GuiEditCtrl, setContentControl, void, (GuiControl *ctrl ), , "( GuiControl ctrl ) - Set the toplevel control to edit in the GUI editor." ) 2484{ 2485 if (ctrl) 2486 object->setContentControl(ctrl); 2487} 2488 2489//----------------------------------------------------------------------------- 2490 2491DefineConsoleMethod( GuiEditCtrl, addNewCtrl, void, (GuiControl *ctrl), , "(GuiControl ctrl)") 2492{ 2493 if (ctrl) 2494 object->addNewControl(ctrl); 2495} 2496 2497//----------------------------------------------------------------------------- 2498 2499DefineConsoleMethod( GuiEditCtrl, addSelection, void, (S32 id), , "selects a control.") 2500{ 2501 object->addSelection(id); 2502} 2503 2504//----------------------------------------------------------------------------- 2505 2506DefineConsoleMethod( GuiEditCtrl, removeSelection, void, (S32 id), , "deselects a control.") 2507{ 2508 object->removeSelection(id); 2509} 2510 2511//----------------------------------------------------------------------------- 2512 2513DefineConsoleMethod( GuiEditCtrl, clearSelection, void, (), , "Clear selected controls list.") 2514{ 2515 object->clearSelection(); 2516} 2517 2518//----------------------------------------------------------------------------- 2519 2520DefineConsoleMethod( GuiEditCtrl, select, void, (GuiControl *ctrl), , "(GuiControl ctrl)") 2521{ 2522 if (ctrl) 2523 object->setSelection(ctrl, false); 2524} 2525 2526//----------------------------------------------------------------------------- 2527 2528DefineConsoleMethod( GuiEditCtrl, setCurrentAddSet, void, (GuiControl *addSet), , "(GuiControl ctrl)") 2529{ 2530 if (addSet) 2531 object->setCurrentAddSet(addSet); 2532} 2533 2534//----------------------------------------------------------------------------- 2535 2536DefineConsoleMethod( GuiEditCtrl, getCurrentAddSet, S32, (), , "Returns the set to which new controls will be added") 2537{ 2538 const GuiControl* add = object->getCurrentAddSet(); 2539 return add ? add->getId() : 0; 2540} 2541 2542//----------------------------------------------------------------------------- 2543 2544DefineConsoleMethod( GuiEditCtrl, toggle, void, (), , "Toggle activation.") 2545{ 2546 object->setEditMode( !object->isActive() ); 2547} 2548 2549//----------------------------------------------------------------------------- 2550 2551DefineConsoleMethod( GuiEditCtrl, justify, void, (U32 mode), , "(int mode)" ) 2552{ 2553 object->justifySelection( (GuiEditCtrl::Justification)mode ); 2554} 2555 2556//----------------------------------------------------------------------------- 2557 2558DefineConsoleMethod( GuiEditCtrl, bringToFront, void, (), , "") 2559{ 2560 object->bringToFront(); 2561} 2562 2563//----------------------------------------------------------------------------- 2564 2565DefineConsoleMethod( GuiEditCtrl, pushToBack, void, (), , "") 2566{ 2567 object->pushToBack(); 2568} 2569 2570//----------------------------------------------------------------------------- 2571 2572DefineConsoleMethod( GuiEditCtrl, deleteSelection, void, (), , "() - Delete the selected controls.") 2573{ 2574 object->deleteSelection(); 2575} 2576 2577//----------------------------------------------------------------------------- 2578 2579DefineConsoleMethod( GuiEditCtrl, moveSelection, void, (S32 dx, S32 dy), , "Move all controls in the selection by (dx,dy) pixels.") 2580{ 2581 object->moveAndSnapSelection(Point2I(dx, dy)); 2582} 2583 2584//----------------------------------------------------------------------------- 2585 2586DefineConsoleMethod( GuiEditCtrl, saveSelection, void, (const char * filename), (NULL), "( string fileName=null ) - Save selection to file or clipboard.") 2587{ 2588 2589 object->saveSelection( filename ); 2590} 2591 2592//----------------------------------------------------------------------------- 2593 2594DefineConsoleMethod( GuiEditCtrl, loadSelection, void, (const char * filename), (NULL), "( string fileName=null ) - Load selection from file or clipboard.") 2595{ 2596 2597 object->loadSelection( filename ); 2598} 2599 2600//----------------------------------------------------------------------------- 2601 2602DefineConsoleMethod( GuiEditCtrl, selectAll, void, (), , "()") 2603{ 2604 object->selectAll(); 2605} 2606 2607//----------------------------------------------------------------------------- 2608 2609DefineEngineMethod( GuiEditCtrl, getSelection, SimSet*, (),, 2610 "Gets the set of GUI controls currently selected in the editor." ) 2611{ 2612 return object->getSelectedSet(); 2613} 2614 2615//----------------------------------------------------------------------------- 2616 2617DefineConsoleMethod( GuiEditCtrl, getNumSelected, S32, (), , "() - Return the number of controls currently selected." ) 2618{ 2619 return object->getNumSelected(); 2620} 2621 2622//----------------------------------------------------------------------------- 2623 2624DefineConsoleMethod( GuiEditCtrl, getSelectionGlobalBounds, const char*, (), , "() - Returns global bounds of current selection as vector 'x y width height'." ) 2625{ 2626 RectI bounds = object->getSelectionGlobalBounds(); 2627 String str = String::ToString( "%i %i %i %i", bounds.point.x, bounds.point.y, bounds.extent.x, bounds.extent.y ); 2628 2629 char* buffer = Con::getReturnBuffer( str.length() ); 2630 dStrcpy( buffer, str.c_str() ); 2631 2632 return buffer; 2633} 2634 2635//----------------------------------------------------------------------------- 2636 2637DefineConsoleMethod( GuiEditCtrl, selectParents, void, ( bool addToSelection ), (false), "( bool addToSelection=false ) - Select parents of currently selected controls." ) 2638{ 2639 2640 object->selectParents( addToSelection ); 2641} 2642 2643//----------------------------------------------------------------------------- 2644 2645DefineConsoleMethod( GuiEditCtrl, selectChildren, void, ( bool addToSelection ), (false), "( bool addToSelection=false ) - Select children of currently selected controls." ) 2646{ 2647 2648 object->selectChildren( addToSelection ); 2649} 2650 2651//----------------------------------------------------------------------------- 2652 2653DefineEngineMethod( GuiEditCtrl, getTrash, SimGroup*, (),, 2654 "Gets the GUI controls(s) that are currently in the trash.") 2655{ 2656 return object->getTrash(); 2657} 2658 2659//----------------------------------------------------------------------------- 2660 2661DefineConsoleMethod(GuiEditCtrl, setSnapToGrid, void, (U32 gridsize), , "GuiEditCtrl.setSnapToGrid(gridsize)") 2662{ 2663 object->setSnapToGrid(gridsize); 2664} 2665 2666//----------------------------------------------------------------------------- 2667 2668DefineConsoleMethod( GuiEditCtrl, readGuides, void, ( GuiControl* ctrl, S32 axis ), (-1), "( GuiControl ctrl [, int axis ] ) - Read the guides from the given control." ) 2669{ 2670 // Find the control. 2671 2672 if( !ctrl ) 2673 { 2674 return; 2675 } 2676 2677 // Read the guides. 2678 2679 if( axis != -1 ) 2680 { 2681 if( axis < 0 || axis > 1 ) 2682 { 2683 Con::errorf( "GuiEditCtrl::readGuides - invalid axis '%s'", axis ); 2684 return; 2685 } 2686 2687 object->readGuides( ( GuiEditCtrl::guideAxis ) axis, ctrl ); 2688 } 2689 else 2690 { 2691 object->readGuides( GuiEditCtrl::GuideHorizontal, ctrl ); 2692 object->readGuides( GuiEditCtrl::GuideVertical, ctrl ); 2693 } 2694} 2695 2696//----------------------------------------------------------------------------- 2697 2698DefineConsoleMethod( GuiEditCtrl, writeGuides, void, ( GuiControl* ctrl, S32 axis ), ( -1), "( GuiControl ctrl [, int axis ] ) - Write the guides to the given control." ) 2699{ 2700 // Find the control. 2701 2702 if( ! ctrl ) 2703 { 2704 return; 2705 } 2706 2707 // Write the guides. 2708 2709 if( axis != -1 ) 2710 { 2711 if( axis < 0 || axis > 1 ) 2712 { 2713 Con::errorf( "GuiEditCtrl::writeGuides - invalid axis '%s'", axis ); 2714 return; 2715 } 2716 2717 object->writeGuides( ( GuiEditCtrl::guideAxis ) axis, ctrl ); 2718 } 2719 else 2720 { 2721 object->writeGuides( GuiEditCtrl::GuideHorizontal, ctrl ); 2722 object->writeGuides( GuiEditCtrl::GuideVertical, ctrl ); 2723 } 2724} 2725 2726//----------------------------------------------------------------------------- 2727 2728DefineConsoleMethod( GuiEditCtrl, clearGuides, void, ( S32 axis ), (-1), "( [ int axis ] ) - Clear all currently set guide lines." ) 2729{ 2730 if( axis != -1 ) 2731 { 2732 if( axis < 0 || axis > 1 ) 2733 { 2734 Con::errorf( "GuiEditCtrl::clearGuides - invalid axis '%i'", axis ); 2735 return; 2736 } 2737 2738 object->clearGuides( ( GuiEditCtrl::guideAxis ) axis ); 2739 } 2740 else 2741 { 2742 object->clearGuides( GuiEditCtrl::GuideHorizontal ); 2743 object->clearGuides( GuiEditCtrl::GuideVertical ); 2744 } 2745} 2746 2747//----------------------------------------------------------------------------- 2748 2749DefineConsoleMethod( GuiEditCtrl, fitIntoParents, void, (bool width, bool height), (true, true), "( bool width=true, bool height=true ) - Fit selected controls into their parents." ) 2750{ 2751 2752 object->fitIntoParents( width, height ); 2753} 2754 2755//----------------------------------------------------------------------------- 2756 2757DefineConsoleMethod( GuiEditCtrl, getMouseMode, const char*, (), , "() - Return the current mouse mode." ) 2758{ 2759 switch( object->getMouseMode() ) 2760 { 2761 case GuiEditCtrl::Selecting: 2762 return "Selecting"; 2763 2764 case GuiEditCtrl::DragSelecting: 2765 return "DragSelecting"; 2766 2767 case GuiEditCtrl::MovingSelection: 2768 return "MovingSelection"; 2769 2770 case GuiEditCtrl::SizingSelection: 2771 return "SizingSelection"; 2772 2773 case GuiEditCtrl::DragGuide: 2774 return "DragGuide"; 2775 2776 case GuiEditCtrl::DragClone: 2777 return "DragClone"; 2778 2779 default: 2780 return ""; 2781 } 2782} 2783 2784//============================================================================= 2785// GuiEditorRuler. 2786//============================================================================= 2787 2788class GuiEditorRuler : public GuiControl 2789{ 2790 public: 2791 2792 typedef GuiControl Parent; 2793 2794 protected: 2795 2796 String mRefCtrlName; 2797 String mEditCtrlName; 2798 2799 GuiScrollCtrl* mRefCtrl; 2800 GuiEditCtrl* mEditCtrl; 2801 2802 public: 2803 2804 enum EOrientation 2805 { 2806 ORIENTATION_Horizontal, 2807 ORIENTATION_Vertical 2808 }; 2809 2810 GuiEditorRuler() 2811 : mRefCtrl( 0 ), 2812 mEditCtrl( 0 ) 2813 { 2814 } 2815 2816 EOrientation getOrientation() const 2817 { 2818 if( getWidth() > getHeight() ) 2819 return ORIENTATION_Horizontal; 2820 else 2821 return ORIENTATION_Vertical; 2822 } 2823 2824 bool onWake() 2825 { 2826 if( !Parent::onWake() ) 2827 return false; 2828 2829 if( !mEditCtrlName.isEmpty() && !Sim::findObject( mEditCtrlName, mEditCtrl ) ) 2830 Con::errorf( "GuiEditorRuler::onWake() - no GuiEditCtrl '%s'", mEditCtrlName.c_str() ); 2831 2832 if( !mRefCtrlName.isEmpty() && !Sim::findObject( mRefCtrlName, mRefCtrl ) ) 2833 Con::errorf( "GuiEditorRuler::onWake() - no GuiScrollCtrl '%s'", mRefCtrlName.c_str() ); 2834 2835 return true; 2836 } 2837 2838 void onPreRender() 2839 { 2840 setUpdate(); 2841 } 2842 2843 void onMouseDown( const GuiEvent& event ) 2844 { 2845 if( !mEditCtrl ) 2846 return; 2847 2848 // Determine the guide axis. 2849 2850 GuiEditCtrl::guideAxis axis; 2851 if( getOrientation() == ORIENTATION_Horizontal ) 2852 axis = GuiEditCtrl::GuideHorizontal; 2853 else 2854 axis = GuiEditCtrl::GuideVertical; 2855 2856 // Start dragging a new guide out in the editor. 2857 2858 U32 guideIndex = mEditCtrl->addGuide( axis, 0 ); 2859 mEditCtrl->startMouseGuideDrag( axis, guideIndex ); 2860 } 2861 2862 void onRender(Point2I offset, const RectI &updateRect) 2863 { 2864 GFX->getDrawUtil()->drawRectFill(updateRect, ColorF(1,1,1,1)); 2865 2866 Point2I choffset(0,0); 2867 if( mRefCtrl != NULL ) 2868 choffset = mRefCtrl->getChildPos(); 2869 2870 if( getOrientation() == ORIENTATION_Horizontal ) 2871 { 2872 // it's horizontal. 2873 for(U32 i = 0; i < getWidth(); i++) 2874 { 2875 S32 x = offset.x + i; 2876 S32 pos = i - choffset.x; 2877 if(!(pos % 10)) 2878 { 2879 S32 start = 6; 2880 if(!(pos %20)) 2881 start = 4; 2882 if(!(pos % 100)) 2883 start = 1; 2884 GFX->getDrawUtil()->drawLine(x, offset.y + start, x, offset.y + 10, ColorF(0,0,0,1)); 2885 } 2886 } 2887 } 2888 else 2889 { 2890 // it's vertical. 2891 for(U32 i = 0; i < getHeight(); i++) 2892 { 2893 S32 y = offset.y + i; 2894 S32 pos = i - choffset.y; 2895 if(!(pos % 10)) 2896 { 2897 S32 start = 6; 2898 if(!(pos %20)) 2899 start = 4; 2900 if(!(pos % 100)) 2901 start = 1; 2902 GFX->getDrawUtil()->drawLine(offset.x + start, y, offset.x + 10, y, ColorF(0,0,0,1)); 2903 } 2904 } 2905 } 2906 } 2907 static void initPersistFields() 2908 { 2909 addField( "refCtrl", TypeRealString, Offset( mRefCtrlName, GuiEditorRuler ) ); 2910 addField( "editCtrl", TypeRealString, Offset( mEditCtrlName, GuiEditorRuler ) ); 2911 2912 Parent::initPersistFields(); 2913 } 2914 2915 DECLARE_CONOBJECT(GuiEditorRuler); 2916 DECLARE_CATEGORY( "Gui Editor" ); 2917}; 2918 2919IMPLEMENT_CONOBJECT(GuiEditorRuler); 2920 2921ConsoleDocClass( GuiEditorRuler, 2922 "@brief Visual representation of markers on top and left sides of GUI Editor\n\n" 2923 "Editor use only.\n\n" 2924 "@internal" 2925); 2926
