guiEditCtrl.h

Engine/source/gui/editor/guiEditCtrl.h

More...

Classes:

class

Native side of the GUI editor.

Detailed Description

  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#ifndef _GUIEDITCTRL_H_
 25#define _GUIEDITCTRL_H_
 26
 27#ifndef _GUICONTROL_H_
 28   #include "gui/core/guiControl.h"
 29#endif
 30#ifndef _UNDO_H_
 31   #include "util/undo.h"
 32#endif
 33#ifndef _GFX_GFXDRAWER_H_
 34   #include "gfx/gfxDrawUtil.h"
 35#endif
 36
 37
 38/// Native side of the GUI editor.
 39class GuiEditCtrl : public GuiControl
 40{
 41   public:
 42   
 43      typedef GuiControl Parent;
 44      friend class GuiEditorRuler;
 45
 46      enum Justification
 47      {
 48         JUSTIFY_LEFT,
 49         JUSTIFY_CENTER_VERTICAL,
 50         JUSTIFY_RIGHT,
 51         JUSTIFY_TOP,
 52         JUSTIFY_BOTTOM,
 53         SPACING_VERTICAL,
 54         SPACING_HORIZONTAL,
 55         JUSTIFY_CENTER_HORIZONTAL,
 56      };
 57      
 58      enum guideAxis { GuideVertical, GuideHorizontal };
 59      
 60      enum mouseModes { Selecting, MovingSelection, SizingSelection, DragSelecting, DragGuide, DragClone };
 61      enum sizingModes { sizingNone = 0, sizingLeft = 1, sizingRight = 2, sizingTop = 4, sizingBottom = 8 };
 62      
 63      enum snappingAxis { SnapVertical, SnapHorizontal };
 64      enum snappingEdges { SnapEdgeMin, SnapEdgeMid, SnapEdgeMax };
 65
 66   protected:
 67   
 68      enum
 69      {
 70         NUT_SIZE = 4,
 71         MIN_GRID_SIZE = 3
 72      };
 73   
 74      typedef Vector< GuiControl*> GuiControlVector;
 75      typedef SimObjectPtr< GuiControl> GuiControlPtr;
 76
 77      bool                 mDrawBorderLines;
 78      bool                 mDrawGuides;
 79      bool                 mFullBoxSelection;
 80      GuiControlVector     mSelectedControls;
 81      GuiControlPtr        mCurrentAddSet;
 82      GuiControlPtr        mContentControl;
 83      Point2I              mLastMousePos;
 84      Point2I              mLastDragPos;
 85      Point2I              mSelectionAnchor;
 86      Point2I              mGridSnap;
 87      Point2I              mDragBeginPoint;
 88      Vector<Point2I>      mDragBeginPoints;
 89      bool                 mDragAddSelection;
 90      bool                 mDragMoveUndo;
 91
 92      // Guides.
 93      
 94      bool                 mSnapToGuides;       ///< If true, edge and center snapping will work against guides.
 95      bool                 mDragGuide[ 2 ];
 96      U32                  mDragGuideIndex[ 2 ];///< Indices of the guide's being dragged in DragGuide mouse mode.
 97      Vector< U32>        mGuides[ 2 ];        ///< The guides defined on the current content control.
 98
 99      // Snapping
100      
101      bool                 mSnapToControls;     ///< If true, edge and center snapping will work against controls.
102      bool                 mSnapToCanvas;       ///< If true, edge and center snapping will work against canvas (= content control).
103      bool                 mSnapToEdges;        ///< If true, selection edges will snap to other control edges.
104      bool                 mSnapToCenters;      ///< If true, selection centers will snap to other control centers.
105      S32                  mSnapSensitivity;    ///< Snap distance in pixels.
106      
107      bool                 mSnapped[ 2 ];       ///< Snap flag for each axis.  If true, we are currently snapped in a drag.
108      S32                  mSnapOffset[ 2 ];    ///< Reference point on snap line for each axis.
109      GuiControlVector     mSnapHits[ 2 ];      ///< Hit testing lists for each axis.
110      snappingEdges        mSnapEdge[ 2 ];      ///< Identification of edge being snapped for each axis.
111      GuiControlPtr        mSnapTargets[ 2 ];   ///< Controls providing the snap reference lines on each axis.
112
113      // Undo
114      SimGroup*            mTrash;
115      SimSet*              mSelectedSet;
116
117      // grid drawing
118      GFXVertexBufferHandle<GFXVertexPCT> mDots;
119      GFXStateBlockRef mDotSB;
120
121      mouseModes           mMouseDownMode;
122      sizingModes          mSizingMode;
123      
124      static StringTableEntry smGuidesPropertyName[ 2 ];
125
126      // private methods
127      void                 updateSelectedSet();
128      
129      S32                  findGuide( guideAxis axis, const Point2I& point, U32 tolerance = 0 );
130      
131      RectI                getSnapRegion( snappingAxis axis, const Point2I& center ) const;   
132      void                 findSnaps( snappingAxis axis, const Point2I& mousePoint, const RectI& minRegion, const RectI& midRegion, const RectI& maxRegion );
133      void                 registerSnap( snappingAxis axis, const Point2I& mousePoint, const Point2I& point, snappingEdges edge, GuiControl* ctrl = NULL );
134      
135      void                 doSnapping( const GuiEvent& event, const RectI& selectionBounds, Point2I& delta );
136      void                 doGuideSnap( const GuiEvent& event, const RectI& selectionBounds, const RectI& selectionBoundsGlobal, Point2I& delta );
137      void                 doControlSnap( const GuiEvent& event, const RectI& selectionBounds, const RectI& selectionBoundsGlobal, Point2I& delta );
138      void                 doGridSnap( const GuiEvent& event, const RectI& selectionBounds, const RectI& selectionBoundsGlobal, Point2I& delta );
139      void                 snapToGrid( Point2I& point );
140      
141      void                 startDragMove( const Point2I& startPoint );
142      void                 startDragRectangle( const Point2I& startPoint );      
143      void                 startDragClone( const Point2I& startPoint );
144      void                 startMouseGuideDrag( guideAxis axis, U32 index, bool lockMouse = true );
145      
146      void                 setMouseMode( mouseModes mode );
147      
148      /// @name Callbacks
149      /// @{
150      
151      DECLARE_CALLBACK( void, onHierarchyChanged, () );
152      DECLARE_CALLBACK( void, onDelete, () );
153      DECLARE_CALLBACK( void, onPreEdit, ( SimSet* selection ) );
154      DECLARE_CALLBACK( void, onPostEdit, ( SimSet* selection ) );
155      DECLARE_CALLBACK( void, onClearSelected, () );
156      DECLARE_CALLBACK( void, onSelect, ( GuiControl* control ) );
157      DECLARE_CALLBACK( void, onAddSelected, ( GuiControl* control ) );
158      DECLARE_CALLBACK( void, onRemoveSelected, ( GuiControl* control ) );
159      DECLARE_CALLBACK( void, onPreSelectionNudged, ( SimSet* selection ) );
160      DECLARE_CALLBACK( void, onPostSelectionNudged, ( SimSet* selection ) );
161      DECLARE_CALLBACK( void, onSelectionMoved, ( GuiControl* control ) ); //FIXME: this should be a selection SimSet
162      DECLARE_CALLBACK( void, onSelectionCloned, ( SimSet* selection ) );
163      DECLARE_CALLBACK( void, onTrashSelection, ( SimSet* selection ) );
164      DECLARE_CALLBACK( void, onAddNewCtrl, ( GuiControl* control ) );
165      DECLARE_CALLBACK( void, onAddNewCtrlSet, ( SimSet* set ) );
166      DECLARE_CALLBACK( void, onSelectionResized, ( GuiControl* control ) );
167      DECLARE_CALLBACK( void, onFitIntoParent, ( bool width, bool height ) );
168      DECLARE_CALLBACK( void, onMouseModeChange, () );
169      DECLARE_CALLBACK( void, onControlInspectPreApply, ( GuiControl* control ) );
170      DECLARE_CALLBACK( void, onControlInspectPostApply, ( GuiControl* control ) );
171      
172      /// @}
173      
174      static bool inNut( const Point2I &pt, S32 x, S32 y )
175      {
176         S32 dx = pt.x - x;
177         S32 dy = pt.y - y;
178         return dx <= NUT_SIZE && dx >= -NUT_SIZE && dy <= NUT_SIZE && dy >= -NUT_SIZE;
179      }
180
181      static void drawCrossSection( U32 axis, S32 offset, const RectI& bounds, ColorI color, GFXDrawUtil* drawer )
182      {
183         Point2I start;
184         Point2I end;
185         
186         if( axis == 0 )
187         {
188            start.x = end.x = offset;
189            start.y = bounds.point.y;
190            end.y = bounds.point.y + bounds.extent.y - 1;
191         }
192         else
193         {
194            start.y = end.y = offset;
195            start.x = bounds.point.x;
196            end.x = bounds.point.x + bounds.extent.x - 1;
197         }
198         
199         drawer->drawLine( start, end, color );
200      }
201      
202      static void snapDelta( snappingAxis axis, snappingEdges edge, S32 offset, const RectI& bounds, Point2I& delta )
203      {
204         switch( axis )
205         {
206            case SnapVertical:
207               switch( edge )
208               {
209                  case SnapEdgeMin:
210                     delta.x = offset - bounds.point.x;
211                     break;
212                     
213                  case SnapEdgeMid:
214                     delta.x = offset - bounds.point.x - bounds.extent.x / 2;
215                     break;
216                     
217                  case SnapEdgeMax:
218                     delta.x = offset - bounds.point.x - bounds.extent.x + 1;
219                     break;
220               }
221               break;
222            
223            case SnapHorizontal:
224               switch( edge )
225               {
226                  case SnapEdgeMin:
227                     delta.y = offset - bounds.point.y;
228                     break;
229                     
230                  case SnapEdgeMid:
231                     delta.y = offset - bounds.point.y - bounds.extent.y / 2;
232                     break;
233                     
234                  case SnapEdgeMax:
235                     delta.y = offset - bounds.point.y - bounds.extent.y + 1;
236                     break;
237               }
238               break;
239         }
240      }
241
242   public:
243
244      GuiEditCtrl();
245      
246      DECLARE_CONOBJECT(GuiEditCtrl);
247      DECLARE_CATEGORY( "Gui Editor" );
248      DECLARE_DESCRIPTION( "Implements the framework for the GUI editor." );
249
250      bool onWake();
251      void onSleep();
252      
253      static void initPersistFields();
254
255      GuiControl*       getContentControl() const { return mContentControl; }
256      void              setContentControl(GuiControl *ctrl);
257      void              setEditMode(bool value);
258      S32               getSizingHitKnobs(const Point2I &pt, const RectI &box);
259      void              getDragRect(RectI &b);
260      void              drawNut(const Point2I &nut, ColorI &outlineColor, ColorI &nutColor);
261      void              drawNuts(RectI &box, ColorI &outlineColor, ColorI &nutColor);
262      void              onPreRender();
263      void              onRender(Point2I offset, const RectI &updateRect);
264      void              addNewControl(GuiControl *ctrl);
265      void              setCurrentAddSet(GuiControl *ctrl, bool clearSelection = true);
266      GuiControl*       getCurrentAddSet();
267      
268      // Selections.
269
270      void              select( GuiControl *ctrl );
271      bool              selectionContains( GuiControl *ctrl );
272      bool              selectionContainsParentOf( GuiControl* ctrl );
273      void              setSelection( GuiControl *ctrl, bool inclusive = false );
274      RectI             getSelectionBounds() const;
275      RectI             getSelectionGlobalBounds() const;
276      void              canHitSelectedControls( bool state = true );
277      void              justifySelection( Justification j );
278      void              moveSelection( const Point2I &delta, bool callback = true );
279      void              moveAndSnapSelection( const Point2I &delta, bool callback = true );
280      void              saveSelection( const char *filename );
281      void              loadSelection( const char *filename );
282      void              addSelection( S32 id );
283      void              addSelection( GuiControl* ctrl );
284      void              removeSelection( S32 id );
285      void              removeSelection( GuiControl* ctrl );
286      void              deleteSelection();
287      void              clearSelection();
288      void              selectAll();
289      void              bringToFront();
290      void              pushToBack();
291      void              moveSelectionToCtrl( GuiControl* ctrl, bool callback = true );
292      void              addSelectControlsInRegion( const RectI& rect, U32 hitTestFlags = 0 );
293      void              addSelectControlAt( const Point2I& pos );
294      void              resizeControlsInSelectionBy( const Point2I& delta, U32 mode );
295      void              fitIntoParents( bool width = true, bool height = true );
296      void              selectParents( bool addToSelection = false );
297      void              selectChildren( bool addToSelection = false );
298      void              cloneSelection();
299      U32               getNumSelected() const { return mSelectedControls.size(); }
300      
301      // Guides.
302      
303      U32               addGuide( guideAxis axis, U32 offset ) { U32 index = mGuides[ axis ].size(); mGuides[ axis ].push_back( offset ); return index; }
304      void              readGuides( guideAxis axis, GuiControl* ctrl );
305      void              writeGuides( guideAxis axis, GuiControl* ctrl );
306      void              clearGuides( guideAxis axis ) { mGuides[ axis ].clear(); }
307
308      // Undo Access.
309      
310      void              undo();
311      void              redo();
312
313      // When a control is changed by the inspector
314      void              controlInspectPreApply(GuiControl* object);
315      void              controlInspectPostApply(GuiControl* object);
316
317      // Sizing Cursors
318      void              getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent);
319
320      U32               getSelectionSize() const { return mSelectedControls.size(); }
321      const Vector<GuiControl*>& getSelected() const { return mSelectedControls; }
322      SimSet* getSelectedSet() { updateSelectedSet(); return mSelectedSet; }
323      SimGroup* getTrash() { return mTrash; }
324      GuiControl* getAddSet() const { return mCurrentAddSet; }; //JDD
325
326      bool              onKeyDown(const GuiEvent &event);
327      void              onMouseDown(const GuiEvent &event);
328      void              onMouseUp(const GuiEvent &event);
329      void              onMouseDragged(const GuiEvent &event);
330      void              onRightMouseDown(const GuiEvent &event);
331      
332      mouseModes        getMouseMode() const { return mMouseDownMode; }
333
334      virtual bool      onAdd();
335      virtual void      onRemove();
336
337      void              setSnapToGrid(U32 gridsize);
338};
339
340#endif //_GUI_EDIT_CTRL_H
341