Torque3D Documentation / _generateds / guiFormCtrl.cpp

guiFormCtrl.cpp

Engine/source/gui/containers/guiFormCtrl.cpp

More...

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#include "console/engineAPI.h"
 25#include "platform/platform.h"
 26#include "gui/containers/guiFormCtrl.h"
 27
 28#include "gui/core/guiDefaultControlRender.h"
 29#include "gfx/gfxDrawUtil.h"
 30
 31#ifdef TORQUE_TOOLS
 32
 33IMPLEMENT_CONOBJECT(GuiFormCtrl);
 34
 35ConsoleDocClass( GuiFormCtrl,
 36   "@brief A generic form control.\n\n"
 37   "Currently editor use only.\n\n "
 38   "@internal"
 39);
 40
 41IMPLEMENT_CALLBACK( GuiFormCtrl, onResize, void, (), (),
 42   "Called when the control is resized." );
 43
 44GuiFormCtrl::GuiFormCtrl()
 45{
 46   setMinExtent(Point2I(200,100));
 47   mActive        = true;
 48   mMouseOver     = false;
 49   mDepressed     = false;
 50   mCanMove       = false;
 51   mCaption       = "[none]";
 52   mUseSmallCaption = false;
 53
 54   mContentLibrary = StringTable->EmptyString();
 55   mContent = StringTable->EmptyString();
 56
 57   mCanSaveFieldDictionary = true;
 58   mIsContainer = true;
 59
 60   // The attached menu bar
 61   mHasMenu = false;
 62   mMenuBar = NULL;
 63   mMouseMovingWin = false;
 64}
 65
 66GuiFormCtrl::~GuiFormCtrl()
 67{
 68   // If we still have a menu bar, delete it.
 69
 70   if( mMenuBar )
 71      mMenuBar->deleteObject();
 72}
 73
 74bool GuiFormCtrl::_setHasMenu( void *object, const char *index, const char *data )
 75{
 76   GuiFormCtrl* ctrl = reinterpret_cast< GuiFormCtrl* >( object );
 77   ctrl->setHasMenu( dAtob( data ) );
 78   return false;
 79}
 80
 81void GuiFormCtrl::initPersistFields()
 82{
 83   addField("caption",        TypeRealString, Offset(mCaption,        GuiFormCtrl));
 84   addField("contentLibrary",TypeString,     Offset(mContentLibrary, GuiFormCtrl));
 85   addField("content",       TypeString,     Offset(mContent,        GuiFormCtrl));
 86   addField("movable",        TypeBool,       Offset(mCanMove,        GuiFormCtrl));
 87   
 88   addProtectedField( "hasMenu", TypeBool,  Offset(mHasMenu, GuiFormCtrl),
 89      &_setHasMenu, &defaultProtectedGetFn,
 90      "" );
 91
 92   Parent::initPersistFields();
 93}
 94
 95void GuiFormCtrl::setHasMenu( bool value )
 96{
 97   if( mHasMenu == value )
 98      return;
 99      
100   if( !value )
101   {
102      mMenuBar->deleteObject();
103      mMenuBar = NULL;
104   }
105   else
106   {
107      if( !mMenuBar )
108      {
109         mMenuBar = new GuiMenuBar();
110         mMenuBar->setField( "profile", "GuiFormMenuBarProfile" );
111         mMenuBar->setField( "horizSizing", "right" );
112         mMenuBar->setField( "vertSizing", "bottom" );
113         mMenuBar->setField( "extent", "16 16" );
114         mMenuBar->setField( "minExtent", "16 16" );
115         mMenuBar->setField( "position", "0 0" );
116         mMenuBar->setField( "class", "FormMenuBarClass "); // Give a generic class to the menu bar so that one set of functions may be used for all of them.
117
118         mMenuBar->registerObject();
119         mMenuBar->setProcessTicks(true); // Activate the processing of ticks to track if the mouse pointer has been hovering within the menu
120      }
121      
122      addObject( mMenuBar ); // Add the menu bar to the form
123   }
124   
125   mHasMenu = value;
126}
127
128bool GuiFormCtrl::onWake()
129{
130   if ( !Parent::onWake() )
131      return false;
132
133   mFont = mProfile->mFont;
134   AssertFatal(mFont, "GuiFormCtrl::onWake: invalid font in profile" );
135
136   mProfile->constructBitmapArray();
137
138   if(mProfile->mUseBitmapArray && mProfile->mBitmapArrayRects.size())
139   {
140      mThumbSize.set(   mProfile->mBitmapArrayRects[0].extent.x, mProfile->mBitmapArrayRects[0].extent.y );
141      mThumbSize.setMax( mProfile->mBitmapArrayRects[1].extent );
142
143      if(mFont->getHeight() > mThumbSize.y)
144         mThumbSize.y = mFont->getHeight();
145   }
146   else
147   {
148      mThumbSize.set(20, 20);
149   }
150
151   return true;
152}
153
154
155void GuiFormCtrl::addObject(SimObject *newObj )
156{
157   if( ( mHasMenu && size() > 1) || (!mHasMenu && size() > 0 ) )
158   {
159      Con::warnf("GuiFormCtrl::addObject - Forms may only have one *direct* child - Placing on Parent!");
160      
161      GuiControl* parent = getParent();
162      if ( parent )
163         parent->addObject( newObj );
164
165      return;
166   }
167
168   GuiControl *newCtrl = dynamic_cast<GuiControl*>( newObj );
169   GuiFormCtrl*formCtrl = dynamic_cast<GuiFormCtrl*>( newObj );
170   
171   if( newCtrl && formCtrl )
172      newCtrl->setCanSave( true );
173   else if ( newCtrl )
174      newCtrl->setCanSave( false );
175
176   Parent::addObject( newObj );
177}
178
179void GuiFormCtrl::removeObject( SimObject* object )
180{
181   if( object == mMenuBar )
182   {
183      mHasMenu = false;
184      mMenuBar = NULL;
185   }
186   
187   Parent::removeObject( object );
188}
189
190bool GuiFormCtrl::acceptsAsChild( SimObject* object ) const
191{
192   return Parent::acceptsAsChild( object ) &&
193      ( ( mHasMenu && size() == 1 ) || ( !mHasMenu && !size() ) ); // Only accept a single child.
194}
195
196void GuiFormCtrl::onSleep()
197{
198   Parent::onSleep();
199   mFont = NULL;
200}
201
202bool GuiFormCtrl::resize(const Point2I &newPosition, const Point2I &newExtent)
203{
204   if( !Parent::resize(newPosition, newExtent) ) 
205      return false;
206
207   if( !mAwake || !mProfile->mBitmapArrayRects.size() )
208      return false;
209
210   // Should the caption be modified because the title bar is too small?
211   S32 textWidth = mProfile->mFont->getStrWidth(mCaption);
212   S32 newTextArea = getWidth() - mThumbSize.x - mProfile->mBitmapArrayRects[4].extent.x;
213   if(newTextArea < textWidth)
214   {
215      static char buf[256];
216
217      mUseSmallCaption = true;
218      mSmallCaption = StringTable->EmptyString();
219
220      S32 strlen = dStrlen((const char*)mCaption);
221      for(S32 i=strlen; i>=0; --i)
222      {
223         dStrcpy(buf, "", i);
224         dStrcat(buf, (const char*)mCaption, i);
225         dStrcat(buf, "...", i);
226
227         textWidth = mProfile->mFont->getStrWidth(buf);
228
229         if(textWidth < newTextArea)
230         {
231            mSmallCaption = StringTable->insert(buf, true);
232            break;
233         }
234      }
235
236   } else
237   {
238      mUseSmallCaption = false;
239   }
240
241   onResize_callback();
242
243   return true;
244}
245
246void GuiFormCtrl::onRender(Point2I offset, const RectI &updateRect)
247{
248   // Fill in the control's child area
249   RectI boundsRect(offset, getExtent());
250   boundsRect.point.y += mThumbSize.y;
251   boundsRect.extent.y -= mThumbSize.y;
252
253   // draw the border of the form if specified
254   if (mProfile->mOpaque)
255      GFX->getDrawUtil()->drawRectFill(boundsRect, mProfile->mFillColor);
256
257   if (mProfile->mBorder)
258      renderBorder(boundsRect, mProfile);
259
260   // If we don't have a child, put some text in the child area
261   if( empty() )
262   {
263      GFX->getDrawUtil()->setBitmapModulation(ColorI(0,0,0));
264      renderJustifiedText(boundsRect.point, boundsRect.extent, "[none]");
265   }
266
267   S32 textWidth = 0;
268
269   // Draw our little bar, too
270   if (mProfile->mBitmapArrayRects.size() >= 5)
271   {
272      GFX->getDrawUtil()->clearBitmapModulation();
273
274      S32 barStart = offset.x + textWidth;
275      S32 barTop   = mThumbSize.y / 2 + offset.y - mProfile->mBitmapArrayRects[3].extent.y / 2;
276
277      Point2I barOffset(barStart, barTop);
278
279      // Draw the start of the bar...
280      GFX->getDrawUtil()->drawBitmapStretchSR(mProfile->mTextureObject ,RectI(barOffset, mProfile->mBitmapArrayRects[2].extent), mProfile->mBitmapArrayRects[2] );
281
282      // Now draw the middle...
283      barOffset.x += mProfile->mBitmapArrayRects[2].extent.x;
284
285      S32 barMiddleSize = (getExtent().x - (barOffset.x - offset.x)) - mProfile->mBitmapArrayRects[4].extent.x + 1;
286
287      if (barMiddleSize > 0)
288      {
289         // We have to do this inset to prevent nasty stretching artifacts
290         RectI foo = mProfile->mBitmapArrayRects[3];
291         foo.inset(1,0);
292
293         GFX->getDrawUtil()->drawBitmapStretchSR(
294            mProfile->mTextureObject,
295            RectI(barOffset, Point2I(barMiddleSize, mProfile->mBitmapArrayRects[3].extent.y)),
296            foo
297            );
298      }
299
300      // And the end
301      barOffset.x += barMiddleSize;
302
303      GFX->getDrawUtil()->drawBitmapStretchSR( mProfile->mTextureObject, RectI(barOffset, mProfile->mBitmapArrayRects[4].extent),
304         mProfile->mBitmapArrayRects[4]);
305
306      GFX->getDrawUtil()->setBitmapModulation((mMouseOver ? mProfile->mFontColorHL : mProfile->mFontColor));
307      renderJustifiedText(Point2I(mThumbSize.x, 0) + offset, Point2I(getWidth() - mThumbSize.x - mProfile->mBitmapArrayRects[4].extent.x, mThumbSize.y), (mUseSmallCaption ? mSmallCaption : mCaption) );
308
309   }
310
311   // Render the children
312   renderChildControls(offset, updateRect);
313}
314
315void GuiFormCtrl::onMouseMove(const GuiEvent &event)
316{
317   Point2I localMove = globalToLocalCoord(event.mousePoint);
318
319   // If we're clicking in the header then resize
320   mMouseOver = (localMove.y < mThumbSize.y);
321   if(isMouseLocked())
322      mDepressed = mMouseOver;
323
324}
325
326void GuiFormCtrl::onMouseEnter(const GuiEvent &event)
327{
328   setUpdate();
329   if(isMouseLocked())
330   {
331      mDepressed = true;
332      mMouseOver = true;
333   }
334   else
335   {
336      mMouseOver = true;
337   }
338
339}
340
341void GuiFormCtrl::onMouseLeave(const GuiEvent &event)
342{
343   setUpdate();
344   if(isMouseLocked())
345      mDepressed = false;
346   mMouseOver = false;
347}
348
349void GuiFormCtrl::onMouseDown(const GuiEvent &event)
350{
351   Point2I localClick = globalToLocalCoord(event.mousePoint);
352
353   // If we're clicking in the header then resize
354   if(localClick.y < mThumbSize.y)
355   {
356      mouseLock();
357      mDepressed = true;
358      mMouseMovingWin = mCanMove;
359
360      //update
361      setUpdate();
362   }
363
364   mOrigBounds = getBounds();
365
366   mMouseDownPosition = event.mousePoint;
367
368   if (mMouseMovingWin )
369   {
370      mouseLock();
371   }
372   else
373   {
374      GuiControl *ctrl = findHitControl(localClick);
375      if (ctrl && ctrl != this)
376         ctrl->onMouseDown(event);
377   }
378}
379
380void GuiFormCtrl::onMouseUp(const GuiEvent &event)
381{
382   // Make sure we only get events we ought to be getting...
383   if (! mActive)
384      return; 
385
386   mouseUnlock();
387   setUpdate();
388
389   // If we're clicking in the header then resize
390   //if(localClick.y < mThumbSize.y && mDepressed)
391   //   setCollapsed(!mCollapsed);
392}
393
394DefineEngineMethod( GuiFormCtrl, getMenuID, S32, (),,
395   "Get the ID of this form's menu.\n\n"
396   "@return The ID of the form menu\n" )
397{
398   return object->getMenuBarID();
399}
400
401U32 GuiFormCtrl::getMenuBarID()
402{
403   return mMenuBar ? mMenuBar->getId() : 0;
404}
405
406DefineEngineMethod( GuiFormCtrl, setCaption, void, ( const char* caption ),,
407   "Sets the title of the form.\n\n"
408   "@param caption Form caption\n" )
409{
410   object->setCaption( caption );
411}
412
413#endif
414