guiEditCtrl.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #ifndef _GUIEDITCTRL_H_
  23. #define _GUIEDITCTRL_H_
  24. #ifndef _GUICONTROL_H_
  25. #include "gui/core/guiControl.h"
  26. #endif
  27. #ifndef _UNDO_H_
  28. #include "util/undo.h"
  29. #endif
  30. #ifndef _GFX_GFXDRAWER_H_
  31. #include "gfx/gfxDrawUtil.h"
  32. #endif
  33. /// Native side of the GUI editor.
  34. class GuiEditCtrl : public GuiControl
  35. {
  36. public:
  37. typedef GuiControl Parent;
  38. friend class GuiEditorRuler;
  39. enum Justification
  40. {
  41. JUSTIFY_LEFT,
  42. JUSTIFY_CENTER_VERTICAL,
  43. JUSTIFY_RIGHT,
  44. JUSTIFY_TOP,
  45. JUSTIFY_BOTTOM,
  46. SPACING_VERTICAL,
  47. SPACING_HORIZONTAL,
  48. JUSTIFY_CENTER_HORIZONTAL,
  49. };
  50. enum guideAxis { GuideVertical, GuideHorizontal };
  51. enum mouseModes { Selecting, MovingSelection, SizingSelection, DragSelecting, DragGuide, DragClone };
  52. enum sizingModes { sizingNone = 0, sizingLeft = 1, sizingRight = 2, sizingTop = 4, sizingBottom = 8 };
  53. enum snappingAxis { SnapVertical, SnapHorizontal };
  54. enum snappingEdges { SnapEdgeMin, SnapEdgeMid, SnapEdgeMax };
  55. protected:
  56. enum
  57. {
  58. NUT_SIZE = 4,
  59. MIN_GRID_SIZE = 3
  60. };
  61. typedef Vector< GuiControl* > GuiControlVector;
  62. typedef SimObjectPtr< GuiControl > GuiControlPtr;
  63. bool mDrawBorderLines;
  64. bool mDrawGuides;
  65. bool mFullBoxSelection;
  66. GuiControlVector mSelectedControls;
  67. GuiControlPtr mCurrentAddSet;
  68. GuiControlPtr mContentControl;
  69. Point2I mLastMousePos;
  70. Point2I mLastDragPos;
  71. Point2I mSelectionAnchor;
  72. Point2I mGridSnap;
  73. Point2I mDragBeginPoint;
  74. Vector<Point2I> mDragBeginPoints;
  75. bool mDragAddSelection;
  76. bool mDragMoveUndo;
  77. // Guides.
  78. bool mSnapToGuides; ///< If true, edge and center snapping will work against guides.
  79. bool mDragGuide[ 2 ];
  80. U32 mDragGuideIndex[ 2 ];///< Indices of the guide's being dragged in DragGuide mouse mode.
  81. Vector< U32 > mGuides[ 2 ]; ///< The guides defined on the current content control.
  82. // Snapping
  83. bool mSnapToControls; ///< If true, edge and center snapping will work against controls.
  84. bool mSnapToCanvas; ///< If true, edge and center snapping will work against canvas (= content control).
  85. bool mSnapToEdges; ///< If true, selection edges will snap to other control edges.
  86. bool mSnapToCenters; ///< If true, selection centers will snap to other control centers.
  87. S32 mSnapSensitivity; ///< Snap distance in pixels.
  88. bool mSnapped[ 2 ]; ///< Snap flag for each axis. If true, we are currently snapped in a drag.
  89. S32 mSnapOffset[ 2 ]; ///< Reference point on snap line for each axis.
  90. GuiControlVector mSnapHits[ 2 ]; ///< Hit testing lists for each axis.
  91. snappingEdges mSnapEdge[ 2 ]; ///< Identification of edge being snapped for each axis.
  92. GuiControlPtr mSnapTargets[ 2 ]; ///< Controls providing the snap reference lines on each axis.
  93. // Undo
  94. SimGroup* mTrash;
  95. SimSet* mSelectedSet;
  96. // grid drawing
  97. GFXVertexBufferHandle<GFXVertexPCT> mDots;
  98. GFXStateBlockRef mDotSB;
  99. mouseModes mMouseDownMode;
  100. sizingModes mSizingMode;
  101. static StringTableEntry smGuidesPropertyName[ 2 ];
  102. // private methods
  103. void updateSelectedSet();
  104. S32 findGuide( guideAxis axis, const Point2I& point, U32 tolerance = 0 );
  105. RectI getSnapRegion( snappingAxis axis, const Point2I& center ) const;
  106. void findSnaps( snappingAxis axis, const Point2I& mousePoint, const RectI& minRegion, const RectI& midRegion, const RectI& maxRegion );
  107. void registerSnap( snappingAxis axis, const Point2I& mousePoint, const Point2I& point, snappingEdges edge, GuiControl* ctrl = NULL );
  108. void doSnapping( const GuiEvent& event, const RectI& selectionBounds, Point2I& delta );
  109. void doGuideSnap( const GuiEvent& event, const RectI& selectionBounds, const RectI& selectionBoundsGlobal, Point2I& delta );
  110. void doControlSnap( const GuiEvent& event, const RectI& selectionBounds, const RectI& selectionBoundsGlobal, Point2I& delta );
  111. void doGridSnap( const GuiEvent& event, const RectI& selectionBounds, const RectI& selectionBoundsGlobal, Point2I& delta );
  112. void snapToGrid( Point2I& point );
  113. void startDragMove( const Point2I& startPoint );
  114. void startDragRectangle( const Point2I& startPoint );
  115. void startDragClone( const Point2I& startPoint );
  116. void startMouseGuideDrag( guideAxis axis, U32 index, bool lockMouse = true );
  117. void setMouseMode( mouseModes mode );
  118. /// @name Callbacks
  119. /// @{
  120. DECLARE_CALLBACK( void, onHierarchyChanged, () );
  121. DECLARE_CALLBACK( void, onDelete, () );
  122. DECLARE_CALLBACK( void, onPreEdit, ( SimSet* selection ) );
  123. DECLARE_CALLBACK( void, onPostEdit, ( SimSet* selection ) );
  124. DECLARE_CALLBACK( void, onClearSelected, () );
  125. DECLARE_CALLBACK( void, onSelect, ( GuiControl* control ) );
  126. DECLARE_CALLBACK( void, onAddSelected, ( GuiControl* control ) );
  127. DECLARE_CALLBACK( void, onRemoveSelected, ( GuiControl* control ) );
  128. DECLARE_CALLBACK( void, onPreSelectionNudged, ( SimSet* selection ) );
  129. DECLARE_CALLBACK( void, onPostSelectionNudged, ( SimSet* selection ) );
  130. DECLARE_CALLBACK( void, onSelectionMoved, ( GuiControl* control ) ); //FIXME: this should be a selection SimSet
  131. DECLARE_CALLBACK( void, onSelectionCloned, ( SimSet* selection ) );
  132. DECLARE_CALLBACK( void, onTrashSelection, ( SimSet* selection ) );
  133. DECLARE_CALLBACK( void, onAddNewCtrl, ( GuiControl* control ) );
  134. DECLARE_CALLBACK( void, onAddNewCtrlSet, ( SimSet* set ) );
  135. DECLARE_CALLBACK( void, onSelectionResized, ( GuiControl* control ) );
  136. DECLARE_CALLBACK( void, onFitIntoParent, ( bool width, bool height ) );
  137. DECLARE_CALLBACK( void, onMouseModeChange, () );
  138. DECLARE_CALLBACK( void, onControlInspectPreApply, ( GuiControl* control ) );
  139. DECLARE_CALLBACK( void, onControlInspectPostApply, ( GuiControl* control ) );
  140. /// @}
  141. static bool inNut( const Point2I &pt, S32 x, S32 y )
  142. {
  143. S32 dx = pt.x - x;
  144. S32 dy = pt.y - y;
  145. return dx <= NUT_SIZE && dx >= -NUT_SIZE && dy <= NUT_SIZE && dy >= -NUT_SIZE;
  146. }
  147. static void drawCrossSection( U32 axis, S32 offset, const RectI& bounds, ColorI color, GFXDrawUtil* drawer )
  148. {
  149. Point2I start;
  150. Point2I end;
  151. if( axis == 0 )
  152. {
  153. start.x = end.x = offset;
  154. start.y = bounds.point.y;
  155. end.y = bounds.point.y + bounds.extent.y - 1;
  156. }
  157. else
  158. {
  159. start.y = end.y = offset;
  160. start.x = bounds.point.x;
  161. end.x = bounds.point.x + bounds.extent.x - 1;
  162. }
  163. drawer->drawLine( start, end, color );
  164. }
  165. static void snapDelta( snappingAxis axis, snappingEdges edge, S32 offset, const RectI& bounds, Point2I& delta )
  166. {
  167. switch( axis )
  168. {
  169. case SnapVertical:
  170. switch( edge )
  171. {
  172. case SnapEdgeMin:
  173. delta.x = offset - bounds.point.x;
  174. break;
  175. case SnapEdgeMid:
  176. delta.x = offset - bounds.point.x - bounds.extent.x / 2;
  177. break;
  178. case SnapEdgeMax:
  179. delta.x = offset - bounds.point.x - bounds.extent.x + 1;
  180. break;
  181. }
  182. break;
  183. case SnapHorizontal:
  184. switch( edge )
  185. {
  186. case SnapEdgeMin:
  187. delta.y = offset - bounds.point.y;
  188. break;
  189. case SnapEdgeMid:
  190. delta.y = offset - bounds.point.y - bounds.extent.y / 2;
  191. break;
  192. case SnapEdgeMax:
  193. delta.y = offset - bounds.point.y - bounds.extent.y + 1;
  194. break;
  195. }
  196. break;
  197. }
  198. }
  199. public:
  200. GuiEditCtrl();
  201. DECLARE_CONOBJECT(GuiEditCtrl);
  202. DECLARE_CATEGORY( "Gui Editor" );
  203. DECLARE_DESCRIPTION( "Implements the framework for the GUI editor." );
  204. bool onWake();
  205. void onSleep();
  206. static void initPersistFields();
  207. GuiControl* getContentControl() const { return mContentControl; }
  208. void setContentControl(GuiControl *ctrl);
  209. void setEditMode(bool value);
  210. S32 getSizingHitKnobs(const Point2I &pt, const RectI &box);
  211. void getDragRect(RectI &b);
  212. void drawNut(const Point2I &nut, ColorI &outlineColor, ColorI &nutColor);
  213. void drawNuts(RectI &box, ColorI &outlineColor, ColorI &nutColor);
  214. void onPreRender();
  215. void onRender(Point2I offset, const RectI &updateRect);
  216. void addNewControl(GuiControl *ctrl);
  217. void setCurrentAddSet(GuiControl *ctrl, bool clearSelection = true);
  218. GuiControl* getCurrentAddSet();
  219. // Selections.
  220. void select( GuiControl *ctrl );
  221. bool selectionContains( GuiControl *ctrl );
  222. bool selectionContainsParentOf( GuiControl* ctrl );
  223. void setSelection( GuiControl *ctrl, bool inclusive = false );
  224. RectI getSelectionBounds() const;
  225. RectI getSelectionGlobalBounds() const;
  226. void canHitSelectedControls( bool state = true );
  227. void justifySelection( Justification j );
  228. void moveSelection( const Point2I &delta, bool callback = true );
  229. void moveAndSnapSelection( const Point2I &delta, bool callback = true );
  230. void saveSelection( const char *filename );
  231. void loadSelection( const char *filename );
  232. void addSelection( S32 id );
  233. void addSelection( GuiControl* ctrl );
  234. void removeSelection( S32 id );
  235. void removeSelection( GuiControl* ctrl );
  236. void deleteSelection();
  237. void clearSelection();
  238. void selectAll();
  239. void bringToFront();
  240. void pushToBack();
  241. void moveSelectionToCtrl( GuiControl* ctrl, bool callback = true );
  242. void addSelectControlsInRegion( const RectI& rect, U32 hitTestFlags = 0 );
  243. void addSelectControlAt( const Point2I& pos );
  244. void resizeControlsInSelectionBy( const Point2I& delta, U32 mode );
  245. void fitIntoParents( bool width = true, bool height = true );
  246. void selectParents( bool addToSelection = false );
  247. void selectChildren( bool addToSelection = false );
  248. void cloneSelection();
  249. U32 getNumSelected() const { return mSelectedControls.size(); }
  250. // Guides.
  251. U32 addGuide( guideAxis axis, U32 offset ) { U32 index = mGuides[ axis ].size(); mGuides[ axis ].push_back( offset ); return index; }
  252. void readGuides( guideAxis axis, GuiControl* ctrl );
  253. void writeGuides( guideAxis axis, GuiControl* ctrl );
  254. void clearGuides( guideAxis axis ) { mGuides[ axis ].clear(); }
  255. // Undo Access.
  256. void undo();
  257. void redo();
  258. // When a control is changed by the inspector
  259. void controlInspectPreApply(GuiControl* object);
  260. void controlInspectPostApply(GuiControl* object);
  261. // Sizing Cursors
  262. void getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent);
  263. U32 getSelectionSize() const { return mSelectedControls.size(); }
  264. const Vector<GuiControl *>& getSelected() const { return mSelectedControls; }
  265. SimSet* getSelectedSet() { updateSelectedSet(); return mSelectedSet; }
  266. SimGroup* getTrash() { return mTrash; }
  267. GuiControl* getAddSet() const { return mCurrentAddSet; }; //JDD
  268. bool onKeyDown(const GuiEvent &event);
  269. void onMouseDown(const GuiEvent &event);
  270. void onMouseUp(const GuiEvent &event);
  271. void onMouseDragged(const GuiEvent &event);
  272. void onRightMouseDown(const GuiEvent &event);
  273. mouseModes getMouseMode() const { return mMouseDownMode; }
  274. virtual bool onAdd();
  275. virtual void onRemove();
  276. void setSnapToGrid(U32 gridsize);
  277. };
  278. #endif //_GUI_EDIT_CTRL_H