Engine directory for ticket #1

This commit is contained in:
DavidWyand-GG 2012-09-19 11:15:01 -04:00
parent 352279af7a
commit 7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions

View file

@ -0,0 +1,569 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "gui/core/guiArrayCtrl.h"
#include "console/console.h"
#include "console/engineAPI.h"
#include "platform/event.h"
#include "gui/containers/guiScrollCtrl.h"
#include "gfx/gfxDrawUtil.h"
#include "gui/core/guiDefaultControlRender.h"
IMPLEMENT_CONOBJECT(GuiArrayCtrl);
ConsoleDocClass( GuiArrayCtrl,
"@brief Abstract base class for controls that store and display multiple elements in a single view.\n\n"
"You cannot actually instantiate this class. Instead you can use its childre:\n\n"
"- GuiConsole\n"
"- GuiTextListCtrl\n"
"- GuiTreeViewCtrl\n"
"- DbgFileView\n"
"- CreatorTree\n"
"This base class is primarily used by other internal classes or those dedicated to editors.\n\n"
"@ingroup GuiCore\n"
"@internal"
);
IMPLEMENT_CALLBACK( GuiArrayCtrl, onCellSelected, void, ( const Point2I& cell ), ( cell ),
"Call when a cell in the array is selected (clicked).\n\n"
"@param @cell Coordinates of the cell"
);
IMPLEMENT_CALLBACK( GuiArrayCtrl, onCellHighlighted, void, ( const Point2I& cell ), ( cell ),
"Call when a cell in the array is highlighted (moused over).\n\n"
"@param @cell Coordinates of the cell"
);
//-----------------------------------------------------------------------------
GuiArrayCtrl::GuiArrayCtrl()
{
mActive = true;
mCellSize.set(80, 30);
mSize = Point2I(5, 30);
mSelectedCell.set(-1, -1);
mMouseOverCell.set(-1, -1);
mHeaderDim.set(0, 0);
mIsContainer = true;
}
//-----------------------------------------------------------------------------
bool GuiArrayCtrl::onWake()
{
if (! Parent::onWake())
return false;
//get the font
mFont = mProfile->mFont;
return true;
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::onSleep()
{
Parent::onSleep();
mFont = NULL;
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::setSize(Point2I newSize)
{
mSize = newSize;
Point2I newExtent(newSize.x * mCellSize.x + mHeaderDim.x, newSize.y * mCellSize.y + mHeaderDim.y);
setExtent(newExtent);
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::getScrollDimensions(S32 &cell_size, S32 &num_cells)
{
cell_size = mCellSize.y;
num_cells = mSize.y;
}
//-----------------------------------------------------------------------------
bool GuiArrayCtrl::cellSelected(Point2I cell)
{
if (cell.x < 0 || cell.x >= mSize.x || cell.y < 0 || cell.y >= mSize.y)
{
mSelectedCell = Point2I(-1,-1);
return false;
}
mSelectedCell = cell;
scrollSelectionVisible();
onCellSelected(cell);
setUpdate();
return true;
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::onCellSelected(Point2I cell)
{
// [rene, 21-Jan-11 ] clashes with callbacks defined in derived classes
Con::executef(this, "onSelect", Con::getFloatArg(cell.x), Con::getFloatArg(cell.y));
onCellSelected_callback( cell );
//call the console function
execConsoleCallback();
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::onCellHighlighted(Point2I cell)
{
onCellHighlighted_callback( cell );
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::setSelectedCell(Point2I cell)
{
cellSelected(cell);
}
//-----------------------------------------------------------------------------
Point2I GuiArrayCtrl::getSelectedCell()
{
return mSelectedCell;
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::scrollSelectionVisible()
{
scrollCellVisible(mSelectedCell);
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::scrollCellVisible(Point2I cell)
{
//make sure we have a parent
//make sure we have a valid cell selected
GuiScrollCtrl *parent = dynamic_cast<GuiScrollCtrl*>(getParent());
if(!parent || cell.x < 0 || cell.y < 0)
return;
RectI cellBounds(cell.x * mCellSize.x, cell.y * mCellSize.y, mCellSize.x, mCellSize.y);
parent->scrollRectVisible(cellBounds);
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::onRenderColumnHeaders(Point2I offset, Point2I parentOffset, Point2I headerDim)
{
if (mProfile->mBorder)
{
RectI cellR(offset.x + headerDim.x, parentOffset.y, getWidth() - headerDim.x, headerDim.y);
GFX->getDrawUtil()->drawRectFill(cellR, mProfile->mBorderColor);
}
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::onRenderRowHeader(Point2I offset, Point2I parentOffset, Point2I headerDim, Point2I cell)
{
ColorI color;
RectI cellR;
if (cell.x % 2)
color.set(255, 0, 0, 255);
else
color.set(0, 255, 0, 255);
cellR.point.set(parentOffset.x, offset.y);
cellR.extent.set(headerDim.x, mCellSize.y);
GFX->getDrawUtil()->drawRectFill(cellR, color);
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver)
{
ColorI color(255 * (cell.x % 2), 255 * (cell.y % 2), 255 * ((cell.x + cell.y) % 2), 255);
if (selected)
{
color.set(255, 0, 0, 255);
}
else if (mouseOver)
{
color.set(0, 0, 255, 255);
}
//draw the cell
RectI cellR(offset.x, offset.y, mCellSize.x, mCellSize.y);
GFX->getDrawUtil()->drawRectFill(cellR, color);
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::onRender(Point2I offset, const RectI &updateRect)
{
// The unmodified offset which was passed into this method.
const Point2I inOffset( offset );
//Parent::onRender( offset, updateRect );
// We render our fill, borders, and child controls ourself.
// This allows us to render child controls after we render cells,
// so child controls appear on-top, as they should.
// Render our fill and borders.
// This code from GuiControl::onRender().
{
RectI ctrlRect(offset, getExtent());
//if opaque, fill the update rect with the fill color
if ( mProfile->mOpaque )
GFX->getDrawUtil()->drawRectFill(ctrlRect, mProfile->mFillColor);
//if there's a border, draw the border
if ( mProfile->mBorder )
renderBorder(ctrlRect, mProfile);
}
//make sure we have a parent
GuiControl *parent = getParent();
if (! parent)
return;
S32 i, j;
RectI headerClip;
RectI clipRect(updateRect.point, updateRect.extent);
Point2I parentOffset = parent->localToGlobalCoord(Point2I(0, 0));
//if we have column headings
if (mHeaderDim.y > 0)
{
headerClip.point.x = parentOffset.x + mHeaderDim.x;
headerClip.point.y = parentOffset.y;
headerClip.extent.x = clipRect.extent.x;// - headerClip.point.x; // This seems to fix some strange problems with some Gui's, bug? -pw
headerClip.extent.y = mHeaderDim.y;
if (headerClip.intersect(clipRect))
{
GFX->setClipRect(headerClip);
//now render the header
onRenderColumnHeaders(offset, parentOffset, mHeaderDim);
clipRect.point.y = headerClip.point.y + headerClip.extent.y - 1;
}
offset.y += mHeaderDim.y;
}
//if we have row headings
if (mHeaderDim.x > 0)
{
clipRect.point.x = getMax(clipRect.point.x, parentOffset.x + mHeaderDim.x);
offset.x += mHeaderDim.x;
}
//save the original for clipping the row headers
RectI origClipRect = clipRect;
for (j = 0; j < mSize.y; j++)
{
//skip until we get to a visible row
if ((j + 1) * mCellSize.y + offset.y < updateRect.point.y)
continue;
//break once we've reached the last visible row
if(j * mCellSize.y + offset.y >= updateRect.point.y + updateRect.extent.y)
break;
//render the header
if (mHeaderDim.x > 0)
{
headerClip.point.x = parentOffset.x;
headerClip.extent.x = mHeaderDim.x;
headerClip.point.y = offset.y + j * mCellSize.y;
headerClip.extent.y = mCellSize.y;
if (headerClip.intersect(origClipRect))
{
GFX->setClipRect(headerClip);
//render the row header
onRenderRowHeader(Point2I(0, offset.y + j * mCellSize.y),
Point2I(parentOffset.x, offset.y + j * mCellSize.y),
mHeaderDim, Point2I(0, j));
}
}
//render the cells for the row
for (i = 0; i < mSize.x; i++)
{
//skip past columns off the left edge
if ((i + 1) * mCellSize.x + offset.x < updateRect.point.x)
continue;
//break once past the last visible column
if (i * mCellSize.x + offset.x >= updateRect.point.x + updateRect.extent.x)
break;
S32 cellx = offset.x + i * mCellSize.x;
S32 celly = offset.y + j * mCellSize.y;
RectI cellClip(cellx, celly, mCellSize.x, mCellSize.y);
//make sure the cell is within the update region
if (cellClip.intersect(clipRect))
{
//set the clip rect
GFX->setClipRect(cellClip);
//render the cell
onRenderCell(Point2I(cellx, celly), Point2I(i, j),
i == mSelectedCell.x && j == mSelectedCell.y,
i == mMouseOverCell.x && j == mMouseOverCell.y);
}
}
}
// Done rendering cells.
// Render child controls, if any, on top.
renderChildControls( inOffset, updateRect );
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::onMouseDown( const GuiEvent &event )
{
if ( !mActive || !mAwake || !mVisible )
return;
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::onMouseUp( const GuiEvent &event )
{
if ( !mActive || !mAwake || !mVisible )
return;
//let the guiControl method take care of the rest
Parent::onMouseUp(event);
Point2I pt = globalToLocalCoord(event.mousePoint);
pt.x -= mHeaderDim.x; pt.y -= mHeaderDim.y;
Point2I cell(
(pt.x < 0 ? -1 : pt.x / mCellSize.x),
(pt.y < 0 ? -1 : pt.y / mCellSize.y)
);
if (cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
{
//store the previously selected cell
Point2I prevSelected = mSelectedCell;
//select the new cell
cellSelected(Point2I(cell.x, cell.y));
//if we double clicked on the *same* cell, evaluate the altConsole Command
if ( ( event.mouseClickCount > 1 ) && ( prevSelected == mSelectedCell ) )
execAltConsoleCallback();
}
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::onMouseEnter(const GuiEvent &event)
{
Point2I pt = globalToLocalCoord(event.mousePoint);
pt.x -= mHeaderDim.x; pt.y -= mHeaderDim.y;
//get the cell
Point2I cell((pt.x < 0 ? -1 : pt.x / mCellSize.x), (pt.y < 0 ? -1 : pt.y / mCellSize.y));
if (cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
{
mMouseOverCell = cell;
setUpdateRegion(Point2I(cell.x * mCellSize.x + mHeaderDim.x,
cell.y * mCellSize.y + mHeaderDim.y), mCellSize );
onCellHighlighted(mMouseOverCell);
}
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::onMouseLeave(const GuiEvent & /*event*/)
{
setUpdateRegion(Point2I(mMouseOverCell.x * mCellSize.x + mHeaderDim.x,
mMouseOverCell.y * mCellSize.y + mHeaderDim.y), mCellSize);
mMouseOverCell.set(-1,-1);
onCellHighlighted(mMouseOverCell);
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::onMouseDragged(const GuiEvent &event)
{
// for the array control, the behavior of onMouseDragged is the same
// as on mouse moved - basically just recalc the current mouse over cell
// and set the update regions if necessary
GuiArrayCtrl::onMouseMove(event);
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::onMouseMove(const GuiEvent &event)
{
Point2I pt = globalToLocalCoord(event.mousePoint);
pt.x -= mHeaderDim.x; pt.y -= mHeaderDim.y;
Point2I cell((pt.x < 0 ? -1 : pt.x / mCellSize.x), (pt.y < 0 ? -1 : pt.y / mCellSize.y));
if (cell.x != mMouseOverCell.x || cell.y != mMouseOverCell.y)
{
if (mMouseOverCell.x != -1)
{
setUpdateRegion(Point2I(mMouseOverCell.x * mCellSize.x + mHeaderDim.x,
mMouseOverCell.y * mCellSize.y + mHeaderDim.y), mCellSize);
}
if (cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
{
setUpdateRegion(Point2I(cell.x * mCellSize.x + mHeaderDim.x,
cell.y * mCellSize.y + mHeaderDim.y), mCellSize);
mMouseOverCell = cell;
}
else
mMouseOverCell.set(-1,-1);
}
onCellHighlighted(mMouseOverCell);
}
//-----------------------------------------------------------------------------
bool GuiArrayCtrl::onKeyDown(const GuiEvent &event)
{
//if this control is a dead end, kill the event
if ((! mVisible) || (! mActive) || (! mAwake)) return true;
//get the parent
S32 pageSize = 1;
GuiControl *parent = getParent();
if (parent && mCellSize.y > 0)
{
pageSize = getMax(1, (parent->getHeight() / mCellSize.y) - 1);
}
Point2I delta(0,0);
switch (event.keyCode)
{
case KEY_LEFT:
delta.set(-1, 0);
break;
case KEY_RIGHT:
delta.set(1, 0);
break;
case KEY_UP:
delta.set(0, -1);
break;
case KEY_DOWN:
delta.set(0, 1);
break;
case KEY_PAGE_UP:
delta.set(0, -pageSize);
break;
case KEY_PAGE_DOWN:
delta.set(0, pageSize);
break;
case KEY_HOME:
cellSelected( Point2I( 0, 0 ) );
return( true );
case KEY_END:
cellSelected( Point2I( 0, mSize.y - 1 ) );
return( true );
default:
return Parent::onKeyDown(event);
}
if (mSize.x < 1 || mSize.y < 1)
return true;
//select the first cell if no previous cell was selected
if (mSelectedCell.x == -1 || mSelectedCell.y == -1)
{
cellSelected(Point2I(0,0));
return true;
}
//select the cell
Point2I cell = mSelectedCell;
cell.x = getMax(0, getMin(mSize.x - 1, cell.x + delta.x));
cell.y = getMax(0, getMin(mSize.y - 1, cell.y + delta.y));
cellSelected(cell);
return true;
}
//-----------------------------------------------------------------------------
void GuiArrayCtrl::onRightMouseDown(const GuiEvent &event)
{
if ( !mActive || !mAwake || !mVisible )
return;
Parent::onRightMouseDown( event );
Point2I cell;
if( _findHitCell( event.mousePoint, cell ) )
{
char buf[32];
dSprintf( buf, sizeof( buf ), "%d %d", event.mousePoint.x, event.mousePoint.y );
// [rene, 21-Jan-11 ] clashes with callbacks defined in derived classes
// Pass it to the console:
Con::executef(this, "onRightMouseDown", Con::getIntArg(cell.x), Con::getIntArg(cell.y), buf);
}
}
//-----------------------------------------------------------------------------
bool GuiArrayCtrl::_findHitCell( const Point2I& pos, Point2I& cellOut )
{
Point2I pt = globalToLocalCoord( pos );
pt.x -= mHeaderDim.x; pt.y -= mHeaderDim.y;
Point2I cell( ( pt.x < 0 ? -1 : pt.x / mCellSize.x ), ( pt.y < 0 ? -1 : pt.y / mCellSize.y ) );
if( cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y )
{
cellOut = cell;
return true;
}
return false;
}

View file

@ -0,0 +1,108 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUIARRAYCTRL_H_
#define _GUIARRAYCTRL_H_
#ifndef _GUITYPES_H_
#include "gui/core/guiTypes.h"
#endif
#ifndef _GUITEXTCTRL_H_
#include "gui/controls/guiTextCtrl.h"
#endif
/// Renders a grid of cells.
class GuiArrayCtrl : public GuiControl
{
typedef GuiControl Parent;
protected:
Point2I mHeaderDim;
Point2I mSize;
Point2I mCellSize;
Point2I mSelectedCell;
Point2I mMouseOverCell;
Resource<GFont> mFont;
virtual bool cellSelected(Point2I cell);
virtual void onCellSelected(Point2I cell);
virtual void onCellHighlighted(Point2I cell);
bool _findHitCell( const Point2I& pos, Point2I& cellOut );
/// @name Callbacks
/// @{
DECLARE_CALLBACK( void, onCellHighlighted, ( const Point2I& cell ) );
DECLARE_CALLBACK( void, onCellSelected, ( const Point2I& cell ) );
/// @}
public:
GuiArrayCtrl();
DECLARE_CONOBJECT(GuiArrayCtrl);
bool onWake();
void onSleep();
/// @name Array attribute methods
/// @{
Point2I getSize() { return mSize; }
virtual void setSize(Point2I size);
void setHeaderDim(const Point2I &dim) { mHeaderDim = dim; }
void getScrollDimensions(S32 &cell_size, S32 &num_cells);
/// @}
/// @name Selected cell methods
/// @{
void setSelectedCell(Point2I cell);
void deselectCells() { mSelectedCell.set(-1,-1); }
Point2I getSelectedCell();
void scrollSelectionVisible();
void scrollCellVisible(Point2I cell);
/// @}
/// @name Rendering methods
/// @{
virtual void onRenderColumnHeaders(Point2I offset, Point2I parentOffset, Point2I headerDim);
virtual void onRenderRowHeader(Point2I offset, Point2I parentOffset, Point2I headerDim, Point2I cell);
virtual void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver);
void onRender(Point2I offset, const RectI &updateRect);
/// @}
/// @name Mouse input methods
/// @{
void onMouseDown( const GuiEvent &event );
void onMouseUp( const GuiEvent &event );
void onMouseMove( const GuiEvent &event );
void onMouseDragged( const GuiEvent &event );
void onMouseEnter( const GuiEvent &event );
void onMouseLeave( const GuiEvent &event );
bool onKeyDown( const GuiEvent &event );
void onRightMouseDown( const GuiEvent &event );
/// @}
};
#endif //_GUI_ARRAY_CTRL_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,455 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUICANVAS_H_
#define _GUICANVAS_H_
#ifndef _SIMBASE_H_
#include "console/simBase.h"
#endif
#ifndef _EVENT_H_
#include "platform/event.h"
#endif
#ifndef _GUICONTROL_H_
#include "gui/core/guiControl.h"
#endif
#ifndef _PLATFORMINPUT_H_
#include "platform/platformInput.h"
#endif
#include "component/interfaces/IProcessInput.h"
#include "windowManager/platformWindowMgr.h"
#include "gfx/gfxFence.h"
#ifdef TORQUE_DEMO_PURCHASE
#ifndef _PURCHASESCREEN_H_
#include "demo/purchase/purchaseScreen.h"
#endif
#endif
/// A canvas on which rendering occurs.
///
///
/// @section GuiCanvas_contents What a GUICanvas Can Contain...
///
/// @subsection GuiCanvas_content_contentcontrol Content Control
/// A content control is the top level GuiControl for a screen. This GuiControl
/// will be the parent control for all other GuiControls on that particular
/// screen.
///
/// @subsection GuiCanvas_content_dialogs Dialogs
///
/// A dialog is essentially another screen, only it gets overlaid on top of the
/// current content control, and all input goes to the dialog. This is most akin
/// to the "Open File" dialog box found in most operating systems. When you
/// choose to open a file, and the "Open File" dialog pops up, you can no longer
/// send input to the application, and must complete or cancel the open file
/// request. Torque keeps track of layers of dialogs. The dialog with the highest
/// layer is on top and will get all the input, unless the dialog is
/// modeless, which is a profile option.
///
/// @see GuiControlProfile
///
/// @section GuiCanvas_dirty Dirty Rectangles
///
/// The GuiCanvas is based on dirty regions.
///
/// Every frame the canvas paints only the areas of the canvas that are 'dirty'
/// or need updating. In most cases, this only is the area under the mouse cursor.
/// This is why if you look in guiCanvas.cc the call to glClear is commented out.
/// If you want a really good idea of what exactly dirty regions are and how they
/// work, un-comment that glClear line in the renderFrame method of guiCanvas.cc
///
/// What you will see is a black screen, except in the dirty regions, where the
/// screen will be painted normally. If you are making an animated GuiControl
/// you need to add your control to the dirty areas of the canvas.
///
class GuiCanvas : public GuiControl, public IProcessInput
{
protected:
typedef GuiControl Parent;
/// @name Rendering
/// @{
RectI mOldUpdateRects[2];
RectI mCurUpdateRect;
U32 mLastRenderMs;
/// @}
/// @name Cursor Properties
/// @{
bool mCursorEnabled;
bool mShowCursor;
bool mRenderFront;
Point2F mCursorPt; ///< Current cursor position in local coordinates.
Point2I mLastCursorPt;
GuiCursor *mDefaultCursor;
GuiCursor *mLastCursor;
bool mLastCursorEnabled;
bool mForceMouseToGUI;
bool mClampTorqueCursor;
bool mAlwaysHandleMouseButtons;
/// @}
/// @name Mouse Input
/// @{
SimObjectPtr<GuiControl> mMouseCapturedControl; ///< All mouse events will go to this ctrl only
SimObjectPtr<GuiControl> mMouseControl; ///< the control the mouse was last seen in unless some other one captured it
bool mMouseControlClicked; ///< whether the current ctrl has been clicked - used by helpctrl
U32 mPrevMouseTime; ///< this determines how long the mouse has been in the same control
bool mMouseButtonDown; ///< Flag to determine if the button is depressed
bool mMouseRightButtonDown; ///< bool to determine if the right button is depressed
bool mMouseMiddleButtonDown; ///< Middle button flag
GuiEvent mLastEvent;
U8 mLastMouseClickCount;
S32 mLastMouseDownTime;
bool mLeftMouseLast;
bool mMiddleMouseLast;
bool mRightMouseLast;
Point2F mMouseDownPoint;
/// Processes keyboard input events. Helper method for processInputEvent
///
/// \param inputEvent Information on the input even to be processed.
/// \return True if the event was handled or false if it was not.
virtual bool processKeyboardEvent(InputEventInfo &inputEvent);
/// Processes mouse input events. Helper method for processInputEvent
///
/// \param inputEvent Information on the input even to be processed.
/// \return True if the event was handled or false if it was not.
virtual bool processMouseEvent(InputEventInfo &inputEvent);
/// Processes gamepad input events. Helper method for processInputEvent
///
/// \param inputEvent Information on the input even to be processed.
/// \return True if the event was handled or false if it was not.
virtual bool processGamepadEvent(InputEventInfo &inputEvent);
virtual void findMouseControl(const GuiEvent &event);
virtual void refreshMouseControl();
/// @}
/// @name Keyboard Input
/// @{
/// Accelerator key map
struct AccKeyMap
{
GuiControl *ctrl;
U32 index;
U32 keyCode;
U32 modifier;
};
Vector <AccKeyMap> mAcceleratorMap;
//for tooltip rendering
U32 mHoverControlStart;
GuiControl* mHoverControl;
Point2I mHoverPosition;
bool mHoverPositionSet;
U32 mHoverLeftControlTime;
/// @}
// Internal event handling callbacks for use with PlatformWindow.
void handleResize (WindowId did, S32 width, S32 height);
void handleAppEvent (WindowId did, S32 event);
void handlePaintEvent (WindowId did);
PlatformWindow *mPlatformWindow;
GFXFence **mFences;
S32 mNextFenceIdx;
S32 mNumFences;
static bool setProtectedNumFences( void *object, const char *index, const char *data );
virtual void setupFences();
void checkLockMouseMove( const GuiEvent& event );
public:
DECLARE_CONOBJECT(GuiCanvas);
DECLARE_CATEGORY( "Gui Core" );
GuiCanvas();
virtual ~GuiCanvas();
virtual bool onAdd();
virtual void onRemove();
static void initPersistFields();
/// @name Rendering methods
///
/// @{
/// Repaints the dirty regions of the canvas
/// @param preRenderOnly If set to true, only the onPreRender methods of all the GuiControls will be called
/// @param bufferSwap If set to true, it will swap buffers at the end. This is to support canvas-subclassing.
virtual void renderFrame(bool preRenderOnly, bool bufferSwap = true);
/// Repaints the canvas by calling the platform window display event.
virtual void paint();
/// Repaints the canvas skipping rendering if the target time
/// has not yet elapsed.
/// @param elapsedMS The time since the last frame.
virtual void repaint(U32 elapsedMS);
/// This signal is triggered at the beginning and end of each render frame
///
/// @param beginFrame true at the beginning of the frame, false at the end
///
typedef Signal <void ( bool beginFrame )> GuiCanvasFrameSignal;
static GuiCanvasFrameSignal& getGuiCanvasFrameSignal();
/// Adds a dirty area to the canvas so it will be updated on the next frame
/// @param pos Screen-coordinates of the upper-left hand corner of the dirty area
/// @param ext Width/height of the dirty area
virtual void addUpdateRegion(Point2I pos, Point2I ext);
/// Resets the update regions so that the next call to renderFrame will
/// repaint the whole canvas
virtual void resetUpdateRegions();
/// Resizes the content control to match the canvas size.
void maintainSizing();
/// This builds a rectangle which encompasses all of the dirty regions to be
/// repainted
/// @param updateUnion (out) Rectangle which surrounds all dirty areas
virtual void buildUpdateUnion(RectI *updateUnion);
/// This will swap the buffers at the end of renderFrame. It was added for canvas
/// sub-classes in case they wanted to do some custom code before the buffer
/// flip occured.
virtual void swapBuffers();
/// @}
/// @name Canvas Content Management
/// @{
/// This returns the PlatformWindow owned by this Canvas
virtual PlatformWindow *getPlatformWindow()
{
return mPlatformWindow;
}
/// This sets the content control to something different
/// @param gui New content control
virtual void setContentControl(GuiControl *gui);
/// Returns the content control
virtual GuiControl *getContentControl();
/// Adds a dialog control onto the stack of dialogs
/// @param gui Dialog to add
/// @param layer Layer to put dialog on
/// @param center Center dialog on canvas.
virtual void pushDialogControl(GuiControl *gui, S32 layer = 0, bool center = false);
/// Removes a specific layer of dialogs
/// @param layer Layer to pop off from
virtual void popDialogControl(S32 layer = 0);
/// Removes a specific dialog control
/// @param gui Dialog to remove from the dialog stack
virtual void popDialogControl(GuiControl *gui);
///@}
/// This turns on/off front-buffer rendering
/// @param front True if all rendering should be done to the front buffer
virtual void setRenderFront(bool front) { mRenderFront = front; }
/// @name Cursor commands
/// A cursor can be on, but not be shown. If a cursor is not on, than it does not
/// process input.
/// @{
/// Sets the cursor for the canvas.
/// @param cursor New cursor to use.
virtual void setCursor(GuiCursor *cursor);
S32 mCursorChanged;
/// Returns true if the cursor is on.
virtual bool isCursorON() { return mCursorEnabled; }
/// Sets if mouse events should be passed to the GUI even if the cursor is off.
/// @param onOff True if events should be passed to the GUI if the cursor is off
virtual void setForceMouseToGUI(bool onOff);
/// Sets if the Torque cursor should be clamped to the window.
/// @param onOff True if the Torque cursor should be clamped against the window
virtual void setClampTorqueCursor(bool onOff);
/// Returns if the Torque cursor is clamped to the window
virtual bool getClampTorqueCursor() { return mClampTorqueCursor; }
/// Turns the cursor on or off.
/// @param onOff True if the cursor should be on.
virtual void setCursorON(bool onOff);
/// Sets the position of the cursor
/// @param pt Point, in screenspace for the cursor
virtual void setCursorPos(const Point2I &pt);
/// Returns the point, in screenspace, at which the cursor is located.
virtual Point2I getCursorPos();
/// Enable/disable rendering of the cursor.
/// @param state True if we should render cursor
virtual void showCursor(bool state);
/// Returns true if the cursor is being rendered.
virtual bool isCursorShown();
/// @}
///used by the tooltip resource
Point2I getCursorExtent() { return mDefaultCursor->getExtent(); }
/// @name Input Processing
/// @{
/// Processes an input event
/// @see InputEvent
/// @param event Input event to process
virtual bool processInputEvent(InputEventInfo &inputEvent);
/// @}
/// @name Mouse Methods
/// @{
/// When a control gets the mouse lock this means that that control gets
/// ALL mouse input and no other control receives any input.
/// @param lockingControl Control to lock mouse to
virtual void mouseLock(GuiControl *lockingControl);
/// Unlocks the mouse from a control
/// @param lockingControl Control to unlock from
virtual void mouseUnlock(GuiControl *lockingControl);
/// Returns the control which the mouse is over
virtual GuiControl* getMouseControl() { return mMouseControl; }
/// Returns the control which the mouse is locked to if any
virtual GuiControl* getMouseLockedControl() { return mMouseCapturedControl; }
/// Returns true if the left mouse button is down
virtual bool mouseButtonDown(void) { return mMouseButtonDown; }
/// Returns true if the right mouse button is down
virtual bool mouseRightButtonDown(void) { return mMouseRightButtonDown; }
/// @}
/// @name Mouse input methods
/// These events process the events before passing them down to the
/// controls they effect. This allows for things such as the input
/// locking and such.
///
/// Each of these methods corresponds to the action in it's method name
/// and processes the GuiEvent passed as a parameter
/// @{
virtual void rootMouseUp(const GuiEvent &event);
virtual void rootMouseDown(const GuiEvent &event);
virtual void rootMouseMove(const GuiEvent &event);
virtual void rootMouseDragged(const GuiEvent &event);
virtual void rootRightMouseDown(const GuiEvent &event);
virtual void rootRightMouseUp(const GuiEvent &event);
virtual void rootRightMouseDragged(const GuiEvent &event);
virtual void rootMiddleMouseDown(const GuiEvent &event);
virtual void rootMiddleMouseUp(const GuiEvent &event);
virtual void rootMiddleMouseDragged(const GuiEvent &event);
virtual bool rootMouseWheelUp(const GuiEvent &event);
virtual bool rootMouseWheelDown(const GuiEvent &event);
/// @}
/// @name Keyboard input methods
/// First responders
///
/// A first responder is a the GuiControl which responds first to input events
/// before passing them off for further processing.
/// @{
/// Moves the first responder to the next tabable controle
virtual bool tabNext(void);
/// Moves the first responder to the previous tabable control
virtual bool tabPrev(void);
/// Setups a keyboard accelerator which maps to a GuiControl.
///
/// @param ctrl GuiControl to map to.
/// @param index
/// @param keyCode Key code.
/// @param modifier Shift, ctrl, etc.
virtual void addAcceleratorKey(GuiControl *ctrl, U32 index, U32 keyCode, U32 modifier);
/// Sets the first responder.
/// @param firstResponder Control to designate as first responder
virtual void setFirstResponder(GuiControl *firstResponder);
/// This is used to toggle processing of native OS accelerators, not
/// to be confused with the Torque accelerator key system, to keep them
/// from swallowing up keystrokes. Both GuiTextEditCtrl and GuiTextPadCtrl
/// use this method.
virtual void setNativeAcceleratorsEnabled( bool enabled );
/// @}
///
virtual Point2I getWindowSize();
virtual void enableKeyboardTranslation();
virtual void disableKeyboardTranslation();
virtual void setWindowTitle(const char *newTitle);
private:
static const U32 MAX_GAMEPADS = 4; ///< The maximum number of supported gamepads
#ifdef TORQUE_DEMO_PURCHASE
private:
PurchaseScreen* mPurchaseScreen;
U32 mLastPurchaseHideTime;
public:
void showPurchaseScreen(bool show, bool startBlocker, const char* location, bool doExit);
void updatePurchaseScreen(const char* value);
#endif
#ifdef TORQUE_DEMO_TIMEOUT
private:
void checkTimeOut();
#endif
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,830 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUICONTROL_H_
#define _GUICONTROL_H_
#ifndef _MPOINT3_H_
#include "math/mPoint3.h"
#endif
#ifndef _MRECT_H_
#include "math/mRect.h"
#endif
#ifndef _COLOR_H_
#include "core/color.h"
#endif
#ifndef _SIMBASE_H_
#include "console/simBase.h"
#endif
#ifndef _GUITYPES_H_
#include "gui/core/guiTypes.h"
#endif
#ifndef _EVENT_H_
#include "platform/event.h"
#endif
#ifndef _UTIL_DELEGATE_H_
#include "core/util/delegate.h"
#endif
#ifndef _LANG_H_
#include "i18n/lang.h"
#endif
class GuiCanvas;
class GuiEditCtrl;
class GuiWindowCtrl;
DECLARE_SCOPE( GuiAPI );
/// A delegate used in tool tip rendering.
///
/// @param hoverPos position to display the tip near
/// @param cursorPos the actual position of the cursor when the delegate is called
/// @param tipText optional alternate tip to be rendered
/// @return Returns true if the tooltip was rendered.
///
/// @see GuiControl::mRenderTooltipDelegate
typedef Delegate<bool( const Point2I &hoverPos, const Point2I &cursorPos, const char *tipText )> RenderTooltipDelegate;
/// @defgroup gui_group Gui System
/// The GUI system in Torque provides a powerful way of creating
/// WYSIWYG User Interfaces for your Game or Application written
/// in Torque.
///
/// The GUI Provides a range of different controls that you may use
/// to arrange and layout your GUI's, including Buttons, Lists, Bitmaps
/// Windows, Containers, and HUD elements.
///
/// The Base Control Class GuiControl provides a basis upon which to
/// write GuiControl's that may be specific to your particular type
/// of game.
/// @addtogroup gui_core_group Core
/// @section GuiControl_Intro Introduction
///
/// GuiControl is the base class for GUI controls in Torque. It provides these
/// basic areas of functionality:
/// - Inherits from SimGroup, so that controls can have children.
/// - Interfacing with a GuiControlProfile.
/// - An abstraction from the details of handling user input
/// and so forth, providing friendly hooks like onMouseEnter(), onMouseMove(),
/// and onMouseLeave(), onKeyDown(), and so forth.
/// - An abstraction from the details of rendering and resizing.
/// - Helper functions to manipulate the mouse (mouseLock and
/// mouseUnlock), and convert coordinates (localToGlobalCoord() and
/// globalToLocalCoord()).
///
/// @ref GUI has an overview of the GUI system.
///
///
/// @ingroup gui_group Gui System
/// @{
class GuiControl : public SimGroup
{
public:
typedef SimGroup Parent;
friend class GuiWindowCtrl; // mCollapseGroupVec
friend class GuiCanvas;
friend class GuiEditCtrl;
friend class GuiDragAndDropControl; // drag callbacks
/// Additional write flags for GuiControls.
enum
{
NoCheckParentCanSave = BIT( 31 ), ///< Don't inherit mCanSave=false from parents.
};
enum horizSizingOptions
{
horizResizeRight = 0, ///< fixed on the left and width
horizResizeWidth, ///< fixed on the left and right
horizResizeLeft, ///< fixed on the right and width
horizResizeCenter,
horizResizeRelative, ///< resize relative
horizResizeWindowRelative ///< resize window relative
};
enum vertSizingOptions
{
vertResizeBottom = 0, ///< fixed on the top and in height
vertResizeHeight, ///< fixed on the top and bottom
vertResizeTop, ///< fixed in height and on the bottom
vertResizeCenter,
vertResizeRelative, ///< resize relative
vertResizeWindowRelative ///< resize window relative
};
private:
SimGroup *mAddGroup; ///< The internal name of a SimGroup child of the global GuiGroup in which to organize this gui on creation
RectI mBounds; ///< The internal bounds of this control
protected:
GuiControlProfile* mProfile; ///< The profile for this gui (data settings that are likely to be shared by multiple guis)
GuiControlProfile* mTooltipProfile; ///< The profile for any tooltips
/// @name Control State
/// @{
static bool setProfileProt( void *object, const char *index, const char *data );
static bool setTooltipProfileProt( void *object, const char *index, const char *data );
S32 mTipHoverTime;
/// Delegate called to render a tooltip for this control.
/// By default this will be set to defaultTooltipRender.
RenderTooltipDelegate mRenderTooltipDelegate;
/// The default tooltip rendering function.
/// @see RenderTooltipDelegate
bool defaultTooltipRender( const Point2I &hoverPos, const Point2I &cursorPos, const char* tipText = NULL );
bool mVisible;
bool mActive;
bool mAwake;
bool mSetFirstResponder;
bool mIsContainer; ///< if true, then the GuiEditor can drag other controls into this one.
bool mCanResize;
bool mCanHit;
S32 mLayer;
Point2I mMinExtent;
StringTableEntry mLangTableName;
LangTable *mLangTable;
bool mNotifyChildrenResized;
// Contains array of windows located inside GuiControl
typedef Vector< Vector< GuiWindowCtrl *> > CollapseGroupVec;
CollapseGroupVec mCollapseGroupVec;
static bool smDesignTime; ///< static GuiControl boolean that specifies if the GUI Editor is active
/// @}
/// @name Design Time Editor Access
/// @{
static GuiEditCtrl *smEditorHandle; ///< static GuiEditCtrl pointer that gives controls access to editor-NULL if editor is closed
/// @}
/// @name Keyboard Input
/// @{
GuiControl *mFirstResponder;
static GuiControl *smPrevResponder;
static GuiControl *smCurResponder;
/// @}
/// @name Control State
/// @{
S32 mHorizSizing; ///< Set from horizSizingOptions.
S32 mVertSizing; ///< Set from vertSizingOptions.
StringTableEntry mAcceleratorKey;
StringTableEntry mConsoleVariable;
String mConsoleCommand;
String mAltConsoleCommand;
String mTooltip;
/// @}
/// @name Console
/// The console variable collection of functions allows a console variable to be bound to the GUI control.
///
/// This allows, say, an edit field to be bound to '$foo'. The value of the console
/// variable '$foo' would then be equal to the text inside the text field. Changing
/// either changes the other.
/// @{
/// $ThisControl variable for callback execution.
static GuiControl* smThisControl;
/// Set $ThisControl and evaluate the given script code.
const char* evaluate( const char* str );
/// Sets the value of the console variable bound to this control
/// @param value String value to assign to control's console variable
void setVariable(const char *value);
/// Sets the value of the console variable bound to this control
/// @param value Integer value to assign to control's console variable
void setIntVariable(S32 value);
/// Sets the value of the console variable bound to this control
/// @param value Float value to assign to control's console variable
void setFloatVariable(F32 value);
const char* getVariable(); ///< Returns value of control's bound variable as a string
S32 getIntVariable(); ///< Returns value of control's bound variable as a integer
F32 getFloatVariable(); ///< Returns value of control's bound variable as a float
GFXStateBlockRef mDefaultGuiSB;
/// @name Callbacks
/// @{
DECLARE_CALLBACK( void, onAdd, () );
DECLARE_CALLBACK( void, onRemove, () );
DECLARE_CALLBACK( void, onWake, () );
DECLARE_CALLBACK( void, onSleep, () );
DECLARE_CALLBACK( void, onLoseFirstResponder, () );
DECLARE_CALLBACK( void, onGainFirstResponder, () );
DECLARE_CALLBACK( void, onAction, () );
DECLARE_CALLBACK( void, onVisible, ( bool state ) );
DECLARE_CALLBACK( void, onActive, ( bool state ) );
DECLARE_CALLBACK( void, onDialogPush, () );
DECLARE_CALLBACK( void, onDialogPop, () );
DECLARE_CALLBACK( void, onControlDragEnter, ( GuiControl* control, const Point2I& dropPoint ) );
DECLARE_CALLBACK( void, onControlDragExit, ( GuiControl* control, const Point2I& dropPoint ) );
DECLARE_CALLBACK( void, onControlDragged, ( GuiControl* control, const Point2I& dropPoint ) );
DECLARE_CALLBACK( void, onControlDropped, ( GuiControl* control, const Point2I& dropPoint ) );
/// @}
public:
/// Set the name of the console variable which this GuiObject is bound to
/// @param variable Variable name
void setConsoleVariable(const char *variable);
/// Set the name of the console function bound to, such as a script function
/// a button calls when clicked.
/// @param newCmd Console function to attach to this GuiControl
void setConsoleCommand( const String& newCmd );
const char * getConsoleCommand(); ///< Returns the name of the function bound to this GuiControl
LangTable *getGUILangTable(void);
const UTF8 *getGUIString(S32 id);
/// @}
/// @name Callbacks
/// @{
/// Executes a console command, and returns the result.
///
/// The global console variable $ThisControl is set to the id of the calling
/// control. WARNING: because multiple controls may set $ThisControl, at any time,
/// the value of $ThisControl should be stored in a local variable by the
/// callback code. The use of the $ThisControl variable is not thread safe.
/// Executes mConsoleCommand, and returns the result.
const char* execConsoleCallback();
/// Executes mAltConsoleCommand, and returns the result.
const char* execAltConsoleCallback();
/// @}
static bool _setVisible( void *object, const char *index, const char *data ) { static_cast<GuiControl*>(object)->setVisible( dAtob( data ) ); return false; };
static bool _setActive( void *object, const char *index, const char *data ) { static_cast<GuiControl*>(object)->setActive( dAtob( data ) ); return false; };
/// @name Editor
/// These functions are used by the GUI Editor
/// @{
/// Sets the size of the GuiControl
/// @param horz Width of the control
/// @param vert Height of the control
void setSizing(S32 horz, S32 vert);
/// Overrides Parent Serialization to allow specific controls to not be saved (Dynamic Controls, etc)
void write(Stream &stream, U32 tabStop, U32 flags);
/// Returns boolean as to whether any parent of this control has the 'no serialization' flag set.
bool getCanSaveParent();
/// @}
/// @name Initialization
/// @{
DECLARE_CONOBJECT(GuiControl);
DECLARE_CATEGORY( "Gui Core" );
DECLARE_DESCRIPTION( "Base class for GUI controls. Can also be used as a generic container." );
GuiControl();
virtual ~GuiControl();
virtual bool processArguments(S32 argc, const char **argv);
static void initPersistFields();
static void consoleInit();
/// @}
/// @name Accessors
/// @{
inline const Point2I& getPosition() const { return mBounds.point; } ///< Returns position of the control
inline const Point2I& getExtent() const { return mBounds.extent; } ///< Returns extents of the control
inline const RectI getBounds()const { return mBounds; } ///< Returns the bounds of the control
inline const RectI getGlobalBounds() ///< Returns the bounds of this object, in global coordinates
{
RectI retRect = getBounds();
retRect.point = localToGlobalCoord( Point2I(0,0) );
return retRect;
};
virtual Point2I getMinExtent() const { return mMinExtent; } ///< Returns minimum size the control can be
virtual void setMinExtent( const Point2I &newMinExtent ) { mMinExtent = newMinExtent; };
inline const S32 getLeft() const { return mBounds.point.x; } ///< Returns the X position of the control
inline const S32 getTop() const { return mBounds.point.y; } ///< Returns the Y position of the control
inline const S32 getWidth() const { return mBounds.extent.x; } ///< Returns the width of the control
inline const S32 getHeight() const { return mBounds.extent.y; } ///< Returns the height of the control
inline const S32 getHorizSizing() const { return mHorizSizing; }
inline const S32 getVertSizing() const { return mVertSizing; }
/// @}
/// @name Flags
/// @{
/// Sets the visibility of the control
/// @param value True if object should be visible
virtual void setVisible(bool value);
inline bool isVisible() const { return mVisible; } ///< Returns true if the object is visible
virtual bool isHidden() const { return !isVisible(); }
virtual void setHidden( bool state ) { setVisible( !state ); }
void setCanHit( bool value ) { mCanHit = value; }
/// Sets the status of this control as active and responding or inactive
/// @param value True if this is active
virtual void setActive(bool value);
bool isActive() { return mActive; } ///< Returns true if this control is active
bool isAwake() { return mAwake; } ///< Returns true if this control is awake
/// @}
/// Get information about the size of a scroll line.
///
/// @param rowHeight The height, in pixels, of a row
/// @param columnWidth The width, in pixels, of a column
virtual void getScrollLineSizes(U32 *rowHeight, U32 *columnWidth);
/// Get information about the cursor.
/// @param cursor Cursor information will be stored here
/// @param showCursor Will be set to true if the cursor is visible
/// @param lastGuiEvent GuiEvent containing cursor position and modifier keys (ie ctrl, shift, alt etc)
virtual void getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent);
/// @name Children
/// @{
/// Adds an object as a child of this object.
/// @param obj New child object of this control
void addObject(SimObject *obj);
/// Removes a child object from this control.
/// @param obj Object to remove from this control
void removeObject(SimObject *obj);
GuiControl *getParent(); ///< Returns the control which owns this one.
GuiCanvas *getRoot(); ///< Returns the root canvas of this control.
virtual bool acceptsAsChild( SimObject* object ) const;
virtual void onGroupRemove();
/// @}
/// @name Coordinates
/// @{
/// Translates local coordinates (wrt this object) into global coordinates
///
/// @param src Local coordinates to translate
Point2I localToGlobalCoord(const Point2I &src);
/// Returns global coordinates translated into local space
///
/// @param src Global coordinates to translate
Point2I globalToLocalCoord(const Point2I &src);
/// @}
/// @name Resizing
/// @{
/// Changes the size and/or position of this control
/// @param newPosition New position of this control
/// @param newExtent New size of this control
virtual bool resize(const Point2I &newPosition, const Point2I &newExtent);
/// Changes the position of this control
/// @param newPosition New position of this control
virtual bool setPosition( const Point2I &newPosition );
inline void setPosition( const S32 x, const S32 y ) { setPosition(Point2I(x,y)); }
/// Changes the size of this control
/// @param newExtent New size of this control
virtual bool setExtent( const Point2I &newExtent );
inline void setExtent( const S32 width, const S32 height) { setExtent(Point2I(width, height)); }
/// Changes the bounds of this control
/// @param newBounds New bounds of this control
virtual bool setBounds( const RectI &newBounds );
inline void setBounds( const S32 left, const S32 top,
const S32 width, const S32 height) { setBounds(RectI(left, top, width, height)); }
/// Changes the X position of this control
/// @param newXPosition New X Position of this control
virtual void setLeft( S32 newLeft );
/// Changes the Y position of this control
/// @param newYPosition New Y Position of this control
virtual void setTop( S32 newTop );
/// Changes the width of this control
/// @param newWidth New width of this control
virtual void setWidth( S32 newWidth );
/// Changes the height of this control
/// @param newHeight New Height of this control
virtual void setHeight( S32 newHeight );
/// Called when a child control of the object is resized
/// @param child Child object
virtual void childResized(GuiControl *child);
/// Called when this objects parent is resized
/// @param oldParentRect The old rectangle of the parent object
/// @param newParentRect The new rectangle of the parent object
virtual void parentResized(const RectI &oldParentRect, const RectI &newParentRect);
/// @}
/// @name Rendering
/// @{
/// Called when this control is to render itself
/// @param offset The location this control is to begin rendering
/// @param updateRect The screen area this control has drawing access to
virtual void onRender(Point2I offset, const RectI &updateRect);
/// Called when this control should render its children
/// @param offset The location this control is to begin rendering
/// @param updateRect The screen area this control has drawing access to
void renderChildControls(Point2I offset, const RectI &updateRect);
/// Sets the area (local coordinates) this control wants refreshed each frame
/// @param pos UpperLeft point on rectangle of refresh area
/// @param ext Extent of update rect
void setUpdateRegion(Point2I pos, Point2I ext);
/// Sets the update area of the control to encompass the whole control
virtual void setUpdate();
/// @}
//child hierarchy calls
void awaken(); ///< Called when this control and its children have been wired up.
void sleep(); ///< Called when this control is no more.
void preRender(); ///< Pre-render this control and all its children.
/// @name Events
///
/// If you subclass these, make sure to call the Parent::'s versions.
///
/// @{
/// Called when this object is asked to wake up returns true if it's actually awake at the end
virtual bool onWake();
/// Called when this object is asked to sleep
virtual void onSleep();
/// Do special pre-render processing
virtual void onPreRender();
/// Called when this object is removed
virtual void onRemove();
/// Called when one of this objects children is removed
virtual void onChildRemoved( GuiControl *child );
/// Called when this object is added to the scene
virtual bool onAdd();
/// Called when the mProfile or mToolTipProfile is deleted
virtual void onDeleteNotify(SimObject *object);
/// Called when this object has a new child
virtual void onChildAdded( GuiControl *child );
/// @}
/// @name Console
/// @{
/// Returns the value of the variable bound to this object
virtual const char *getScriptValue();
/// Sets the value of the variable bound to this object
virtual void setScriptValue(const char *value);
/// @}
/// @name Input (Keyboard/Mouse)
/// @{
/// This function will return true if the provided coordinates (wrt parent object) are
/// within the bounds of this control
/// @param parentCoordPoint Coordinates to test
virtual bool pointInControl(const Point2I& parentCoordPoint);
/// Returns true if the global cursor is inside this control
bool cursorInControl();
/// Returns the control which the provided point is under, with layering
/// @param pt Point to test
/// @param initialLayer Layer of gui objects to begin the search
virtual GuiControl* findHitControl(const Point2I &pt, S32 initialLayer = -1 );
enum EHitTestFlags
{
HIT_FullBoxOnly = BIT( 0 ), ///< Hit only counts if all of a control's bounds are within the hit rectangle.
HIT_ParentPreventsChildHit = BIT( 1 ), ///< A positive hit test on a parent control will prevent hit tests on children.
HIT_AddParentHits = BIT( 2 ), ///< Parent's that get hit should be added regardless of whether any of their children get hit, too.
HIT_NoCanHitNoRecurse = BIT( 3 ), ///< A hit-disabled control will not recurse into children.
};
///
virtual bool findHitControls( const RectI& rect, Vector< GuiControl* >& outResult, U32 flags = 0, S32 initialLayer = -1, U32 depth = 0 );
/// Lock the mouse within the provided control
/// @param lockingControl Control to lock the mouse within
void mouseLock(GuiControl *lockingControl);
/// Turn on mouse locking with last used lock control
void mouseLock();
/// Unlock the mouse
void mouseUnlock();
/// Returns true if the mouse is locked
bool isMouseLocked();
/// @}
/// General input handler.
virtual bool onInputEvent(const InputEventInfo &event);
/// @name Mouse Events
/// These functions are called when the input event which is
/// in the name of the function occurs.
/// @{
virtual void onMouseUp(const GuiEvent &event);
virtual void onMouseDown(const GuiEvent &event);
virtual void onMouseMove(const GuiEvent &event);
virtual void onMouseDragged(const GuiEvent &event);
virtual void onMouseEnter(const GuiEvent &event);
virtual void onMouseLeave(const GuiEvent &event);
virtual bool onMouseWheelUp(const GuiEvent &event);
virtual bool onMouseWheelDown(const GuiEvent &event);
virtual void onRightMouseDown(const GuiEvent &event);
virtual void onRightMouseUp(const GuiEvent &event);
virtual void onRightMouseDragged(const GuiEvent &event);
virtual void onMiddleMouseDown(const GuiEvent &event);
virtual void onMiddleMouseUp(const GuiEvent &event);
virtual void onMiddleMouseDragged(const GuiEvent &event);
/// @}
/// @name Gamepad Events
/// These functions are called when the input event which is in the name of
/// the function occurs.
/// @{
virtual bool onGamepadButtonDown(const GuiEvent &event); ///< Default behavior is call-through to onKeyDown
virtual bool onGamepadButtonUp(const GuiEvent &event); ///< Default behavior is call-through to onKeyUp
virtual bool onGamepadAxisUp(const GuiEvent &event);
virtual bool onGamepadAxisDown(const GuiEvent &event);
virtual bool onGamepadAxisLeft(const GuiEvent &event);
virtual bool onGamepadAxisRight(const GuiEvent &event);
virtual bool onGamepadTrigger(const GuiEvent &event);
/// @}
/// @name Editor Mouse Events
///
/// These functions are called when the input event which is
/// in the name of the function occurs. Conversely from normal
/// mouse events, these have a boolean return value that, if
/// they return true, the editor will NOT act on them or be able
/// to respond to this particular event.
///
/// This is particularly useful for when writing controls so that
/// they may become aware of the editor and allow customization
/// of their data or appearance as if they were actually in use.
/// For example, the GuiTabBookCtrl catches on mouse down to select
/// a tab and NOT let the editor do any instant group manipulation.
///
/// @{
/// Called when a mouseDown event occurs on a control and the GUI editor is active
/// @param event the GuiEvent which caused the call to this function
/// @param offset the offset which is representative of the units x and y that the editor takes up on screen
virtual bool onMouseDownEditor(const GuiEvent &event, Point2I offset) { return false; };
/// Called when a mouseUp event occurs on a control and the GUI editor is active
/// @param event the GuiEvent which caused the call to this function
/// @param offset the offset which is representative of the units x and y that the editor takes up on screen
virtual bool onMouseUpEditor(const GuiEvent &event, Point2I offset) { return false; };
/// Called when a rightMouseDown event occurs on a control and the GUI editor is active
/// @param event the GuiEvent which caused the call to this function
/// @param offset the offset which is representative of the units x and y that the editor takes up on screen
virtual bool onRightMouseDownEditor(const GuiEvent &event, Point2I offset) { return false; };
/// Called when a mouseDragged event occurs on a control and the GUI editor is active
/// @param event the GuiEvent which caused the call to this function
/// @param offset the offset which is representative of the units x and y that the editor takes up on screen
virtual bool onMouseDraggedEditor(const GuiEvent &event, Point2I offset) { return false; };
/// @}
/// @name Tabs
/// @{
/// Find the first tab-accessible child of this control
virtual GuiControl* findFirstTabable();
/// Find the last tab-accessible child of this control
/// @param firstCall Set to true to clear the global previous responder
virtual GuiControl* findLastTabable(bool firstCall = true);
/// Find previous tab-accessible control with respect to the provided one
/// @param curResponder Current control
/// @param firstCall Set to true to clear the global previous responder
virtual GuiControl* findPrevTabable(GuiControl *curResponder, bool firstCall = true);
/// Find next tab-accessible control with regards to the provided control.
///
/// @param curResponder Current control
/// @param firstCall Set to true to clear the global current responder
virtual GuiControl* findNextTabable(GuiControl *curResponder, bool firstCall = true);
/// @}
/// Returns true if the provided control is a child (grandchild, or great-grandchild) of this one.
///
/// @param child Control to test
virtual bool controlIsChild(GuiControl *child);
/// @name First Responder
/// A first responder is the control which reacts first, in it's responder chain, to keyboard events
/// The responder chain is set for each parent and so there is only one first responder amongst it's
/// children.
/// @{
/// Sets the first responder for child controls
/// @param firstResponder First responder for this chain
virtual void setFirstResponder(GuiControl *firstResponder);
/// Sets up this control to be the first in it's group to respond to an input event
/// @param value True if this should be a first responder
virtual void makeFirstResponder(bool value);
/// Returns true if this control is a first responder
bool isFirstResponder();
/// Sets this object to be a first responder
virtual void setFirstResponder();
/// Clears the first responder for this chain
void clearFirstResponder();
/// Returns the first responder for this chain
GuiControl *getFirstResponder() { return mFirstResponder; }
/// Occurs when the control gains first-responder status.
virtual void onGainFirstResponder();
/// Occurs when the control loses first-responder status.
virtual void onLoseFirstResponder();
/// @}
/// @name Keyboard Events
/// @{
/// Adds the accelerator key for this object to the canvas
void addAcceleratorKey();
/// Adds this control's accelerator key to the accelerator map, and
/// recursively tells all children to do the same.
virtual void buildAcceleratorMap();
/// Occurs when the accelerator key for this control is pressed
///
/// @param index Index in the accelerator map of the key
virtual void acceleratorKeyPress(U32 index);
/// Occurs when the accelerator key for this control is released
///
/// @param index Index in the accelerator map of the key
virtual void acceleratorKeyRelease(U32 index);
/// Happens when a key is depressed
/// @param event Event descriptor (which contains the key)
virtual bool onKeyDown(const GuiEvent &event);
/// Happens when a key is released
/// @param event Event descriptor (which contains the key)
virtual bool onKeyUp(const GuiEvent &event);
/// Happens when a key is held down, resulting in repeated keystrokes.
/// @param event Event descriptor (which contains the key)
virtual bool onKeyRepeat(const GuiEvent &event);
/// @}
/// Return the delegate used to render tooltips on this control.
RenderTooltipDelegate& getRenderTooltipDelegate() { return mRenderTooltipDelegate; }
const RenderTooltipDelegate& getRenderTooltipDelegate() const { return mRenderTooltipDelegate; }
/// Returns our tooltip profile (and finds the profile if it hasn't been set yet)
GuiControlProfile* getTooltipProfile() { return mTooltipProfile; }
/// Sets the tooltip profile for this control.
///
/// @see GuiControlProfile
/// @param prof Tooltip profile to apply
void setTooltipProfile(GuiControlProfile *prof);
/// Returns our profile (and finds the profile if it hasn't been set yet)
GuiControlProfile* getControlProfile() { return mProfile; }
/// Sets the control profile for this control.
///
/// @see GuiControlProfile
/// @param prof Control profile to apply
void setControlProfile(GuiControlProfile *prof);
/// Occurs when this control performs its "action"
virtual void onAction();
/// @name Peer Messaging
/// Used to send a message to other GUIControls which are children of the same parent.
///
/// This is mostly used by radio controls.
/// @{
void messageSiblings(S32 message); ///< Send a message to all siblings
virtual void onMessage(GuiControl *sender, S32 msg); ///< Receive a message from another control
/// @}
/// @name Canvas Events
/// Functions called by the canvas
/// @{
/// Called if this object is a dialog, when it is added to the visible layers
virtual void onDialogPush();
/// Called if this object is a dialog, when it is removed from the visible layers
virtual void onDialogPop();
/// @}
/// Renders justified text using the profile.
///
/// @note This should move into the graphics library at some point
void renderJustifiedText(Point2I offset, Point2I extent, const char *text);
/// Returns text clipped to fit within a pixel width. The clipping
/// occurs on the right side and "..." is appended. It returns width
/// of the final clipped text in pixels.
U32 clipText( String &inOutText, U32 width ) const;
void inspectPostApply();
void inspectPreApply();
};
typedef GuiControl::horizSizingOptions GuiHorizontalSizing;
typedef GuiControl::vertSizingOptions GuiVerticalSizing;
DefineEnumType( GuiHorizontalSizing );
DefineEnumType( GuiVerticalSizing );
/// @}
#endif

View file

@ -0,0 +1,547 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "gui/core/guiDefaultControlRender.h"
#include "gui/core/guiTypes.h"
#include "core/color.h"
#include "math/mRect.h"
#include "gfx/gfxDevice.h"
#include "gfx/gfxDrawUtil.h"
static ColorI colorLightGray(192, 192, 192);
static ColorI colorGray(128, 128, 128);
static ColorI colorDarkGray(64, 64, 64);
static ColorI colorWhite(255,255,255);
static ColorI colorBlack(0,0,0);
void renderRaisedBox( const RectI &bounds, GuiControlProfile *profile )
{
S32 l = bounds.point.x, r = bounds.point.x + bounds.extent.x - 1;
S32 t = bounds.point.y, b = bounds.point.y + bounds.extent.y - 1;
GFX->getDrawUtil()->drawRectFill( bounds, profile->mFillColor);
GFX->getDrawUtil()->drawLine(l, t, l, b - 1, colorWhite);
GFX->getDrawUtil()->drawLine(l, t, r - 1, t, colorWhite);
GFX->getDrawUtil()->drawLine(l, b, r, b, colorBlack);
GFX->getDrawUtil()->drawLine(r, b - 1, r, t, colorBlack);
GFX->getDrawUtil()->drawLine(l + 1, b - 1, r - 1, b - 1, profile->mBorderColor);
GFX->getDrawUtil()->drawLine(r - 1, b - 2, r - 1, t + 1, profile->mBorderColor);
}
void renderSlightlyRaisedBox( const RectI &bounds, GuiControlProfile *profile )
{
S32 l = bounds.point.x + 1, r = bounds.point.x + bounds.extent.x - 1;
S32 t = bounds.point.y + 1, b = bounds.point.y + bounds.extent.y - 1;
GFXDrawUtil *drawer = GFX->getDrawUtil();
drawer->drawRectFill( bounds, profile->mFillColor);
drawer->drawLine(l, t, l, b, profile->mBorderColor);
drawer->drawLine(l, t, r, t, profile->mBorderColor);
drawer->drawLine(l + 1, b, r, b, profile->mBorderColor);
drawer->drawLine(r, t + 1, r, b - 1, profile->mBorderColor);
}
void renderLoweredBox( const RectI &bounds, GuiControlProfile *profile )
{
S32 l = bounds.point.x, r = bounds.point.x + bounds.extent.x - 1;
S32 t = bounds.point.y, b = bounds.point.y + bounds.extent.y - 1;
GFX->getDrawUtil()->drawRectFill( bounds, profile->mFillColor);
GFX->getDrawUtil()->drawLine(l, b, r, b, colorWhite);
GFX->getDrawUtil()->drawLine(r, b - 1, r, t, colorWhite);
GFX->getDrawUtil()->drawLine(l, t, r - 1, t, colorBlack);
GFX->getDrawUtil()->drawLine(l, t + 1, l, b - 1, colorBlack);
GFX->getDrawUtil()->drawLine(l + 1, t + 1, r - 2, t + 1, profile->mBorderColor);
GFX->getDrawUtil()->drawLine(l + 1, t + 2, l + 1, b - 2, profile->mBorderColor);
}
void renderSlightlyLoweredBox( const RectI &bounds, GuiControlProfile *profile )
{
S32 l = bounds.point.x + 1, r = bounds.point.x + bounds.extent.x - 1;
S32 t = bounds.point.y + 1, b = bounds.point.y + bounds.extent.y - 1;
GFX->getDrawUtil()->drawRectFill( bounds, profile->mFillColor);
GFX->getDrawUtil()->drawLine(l, b, r, b, profile->mBorderColor);
GFX->getDrawUtil()->drawLine(r, t, r, b - 1, profile->mBorderColor);
GFX->getDrawUtil()->drawLine(l, t, l, b - 1, profile->mBorderColor);
GFX->getDrawUtil()->drawLine(l + 1, t, r - 1, t, profile->mBorderColor);
}
void renderBorder( const RectI &bounds, GuiControlProfile *profile )
{
S32 l = bounds.point.x, r = bounds.point.x + bounds.extent.x - 1;
S32 t = bounds.point.y, b = bounds.point.y + bounds.extent.y - 1;
GFXDrawUtil *drawer = GFX->getDrawUtil();
switch(profile->mBorder)
{
case 1:
drawer->drawRect(bounds, profile->mBorderColor);
break;
case 2:
drawer->drawLine(l + 1, t + 1, l + 1, b - 2, profile->mBevelColorHL);
drawer->drawLine(l + 2, t + 1, r - 2, t + 1, profile->mBevelColorHL);
drawer->drawLine(r, t, r, b, profile->mBevelColorHL);
drawer->drawLine(l, b, r - 1, b, profile->mBevelColorHL);
drawer->drawLine(l, t, r - 1, t, profile->mBorderColorNA);
drawer->drawLine(l, t + 1, l, b - 1, profile->mBorderColorNA);
drawer->drawLine(l + 1, b - 1, r - 1, b - 1, profile->mBorderColorNA);
drawer->drawLine(r - 1, t + 1, r - 1, b - 2, profile->mBorderColorNA);
break;
case 3:
drawer->drawLine(l, b, r, b, profile->mBevelColorHL);
drawer->drawLine(r, t, r, b - 1, profile->mBevelColorHL);
drawer->drawLine(l + 1, b - 1, r - 1, b - 1, profile->mFillColor);
drawer->drawLine(r - 1, t + 1, r - 1, b - 2, profile->mFillColor);
drawer->drawLine(l, t, l, b - 1, profile->mBorderColorNA);
drawer->drawLine(l + 1, t, r - 1, t, profile->mBorderColorNA);
drawer->drawLine(l + 1, t + 1, l + 1, b - 2, profile->mBevelColorLL);
drawer->drawLine(l + 2, t + 1, r - 2, t + 1, profile->mBevelColorLL);
break;
case 4:
drawer->drawLine(l, t, l, b - 1, profile->mBevelColorHL);
drawer->drawLine(l + 1, t, r, t, profile->mBevelColorHL);
drawer->drawLine(l, b, r, b, profile->mBevelColorLL);
drawer->drawLine(r, t + 1, r, b - 1, profile->mBevelColorLL);
drawer->drawLine(l + 1, b - 1, r - 1, b - 1, profile->mBorderColor);
drawer->drawLine(r - 1, t + 1, r - 1, b - 2, profile->mBorderColor);
break;
case 5:
renderFilledBorder( bounds, profile );
break;
//
case -1:
// Draw a simple sizable border with corners
// Taken from the 'Skinnable GUI Controls in TGE' resource by Justin DuJardin
if(profile->mBitmapArrayRects.size() >= 8)
{
drawer->clearBitmapModulation();
RectI destRect;
RectI stretchRect;
RectI* mBitmapBounds = profile->mBitmapArrayRects.address();
// Indices into the bitmap array
enum
{
BorderTopLeft = 0,
BorderTop,
BorderTopRight,
BorderLeft,
//Fill,
BorderRight,
BorderBottomLeft,
BorderBottom,
BorderBottomRight,
NumBitmaps
};
// Draw all corners first.
//top left border
drawer->drawBitmapSR(profile->mTextureObject,Point2I(bounds.point.x,bounds.point.y),mBitmapBounds[BorderTopLeft]);
//top right border
drawer->drawBitmapSR(profile->mTextureObject,Point2I(bounds.point.x + bounds.extent.x - mBitmapBounds[BorderTopRight].extent.x,bounds.point.y),mBitmapBounds[BorderTopRight]);
//bottom left border
drawer->drawBitmapSR(profile->mTextureObject,Point2I(bounds.point.x,bounds.point.y + bounds.extent.y - mBitmapBounds[BorderBottomLeft].extent.y),mBitmapBounds[BorderBottomLeft]);
//bottom right border
drawer->drawBitmapSR(profile->mTextureObject,Point2I(
bounds.point.x + bounds.extent.x - mBitmapBounds[BorderBottomRight].extent.x,
bounds.point.y + bounds.extent.y - mBitmapBounds[BorderBottomRight].extent.y),
mBitmapBounds[BorderBottomRight]);
// End drawing corners
// Begin drawing sides and top stretched borders
//start with top line stretch
destRect.point.x = bounds.point.x + mBitmapBounds[BorderTopLeft].extent.x;
destRect.extent.x = bounds.extent.x - mBitmapBounds[BorderTopRight].extent.x - mBitmapBounds[BorderTopLeft].extent.x;
destRect.extent.y = mBitmapBounds[BorderTop].extent.y;
destRect.point.y = bounds.point.y;
//stretch it
stretchRect = mBitmapBounds[BorderTop];
stretchRect.inset(1,0);
//draw it
drawer->drawBitmapStretchSR(profile->mTextureObject,destRect,stretchRect);
//bottom line stretch
destRect.point.x = bounds.point.x + mBitmapBounds[BorderBottomLeft].extent.x;
destRect.extent.x = bounds.extent.x - mBitmapBounds[BorderBottomRight].extent.x - mBitmapBounds[BorderBottomLeft].extent.x;
destRect.extent.y = mBitmapBounds[BorderBottom].extent.y;
destRect.point.y = bounds.point.y + bounds.extent.y - mBitmapBounds[BorderBottom].extent.y;
//stretch it
stretchRect = mBitmapBounds[BorderBottom];
stretchRect.inset(1,0);
//draw it
drawer->drawBitmapStretchSR(profile->mTextureObject,destRect,stretchRect);
//left line stretch
destRect.point.x = bounds.point.x;
destRect.extent.x = mBitmapBounds[BorderLeft].extent.x;
destRect.extent.y = bounds.extent.y - mBitmapBounds[BorderTopLeft].extent.y - mBitmapBounds[BorderBottomLeft].extent.y;
destRect.point.y = bounds.point.y + mBitmapBounds[BorderTopLeft].extent.y;
//stretch it
stretchRect = mBitmapBounds[BorderLeft];
stretchRect.inset(0,1);
//draw it
drawer->drawBitmapStretchSR(profile->mTextureObject,destRect,stretchRect);
//right line stretch
destRect.point.x = bounds.point.x + bounds.extent.x - mBitmapBounds[BorderRight].extent.x;
destRect.extent.x = mBitmapBounds[BorderRight].extent.x;
destRect.extent.y = bounds.extent.y - mBitmapBounds[BorderTopRight].extent.y - mBitmapBounds[BorderBottomRight].extent.y;
destRect.point.y = bounds.point.y + mBitmapBounds[BorderTopRight].extent.y;
//stretch it
stretchRect = mBitmapBounds[BorderRight];
stretchRect.inset(0,1);
//draw it
drawer->drawBitmapStretchSR(profile->mTextureObject,destRect,stretchRect);
// End drawing sides and top stretched borders
break;
}
case -2:
// Draw a simple sizable border with corners that is filled in
renderSizableBitmapBordersFilled(bounds, 1, profile);
break;
case -3:
// Draw a simple fixed height border with center fill horizontally.
renderFixedBitmapBordersFilled( bounds, 1, profile );
break;
}
}
void renderFilledBorder( const RectI &bounds, GuiControlProfile *profile )
{
renderFilledBorder( bounds, profile->mBorderColor, profile->mFillColor, profile->mBorderThickness );
}
void renderFilledBorder( const RectI &bounds, const ColorI &borderColor, const ColorI &fillColor, U32 thickness )
{
RectI fillBounds = bounds;
fillBounds.inset( thickness, thickness );
GFX->getDrawUtil()->drawRectFill( bounds, borderColor );
GFX->getDrawUtil()->drawRectFill( fillBounds, fillColor );
}
// Render out the sizable bitmap borders based on a multiplier into the bitmap array
// Based on the 'Skinnable GUI Controls in TGE' resource by Justin DuJardin
void renderSizableBitmapBordersFilled( const RectI &bounds, S32 baseMultiplier, GuiControlProfile *profile)
{
// Indices into the bitmap array
S32 numBitmaps = 9;
S32 borderTopLeft = numBitmaps * baseMultiplier - numBitmaps;
S32 borderTop = 1 + borderTopLeft;
S32 borderTopRight = 2 + borderTopLeft;
S32 borderLeft = 3 + borderTopLeft;
S32 fill = 4 + borderTopLeft;
S32 borderRight = 5 + borderTopLeft;
S32 borderBottomLeft = 6 + borderTopLeft;
S32 borderBottom = 7 + borderTopLeft;
S32 borderBottomRight = 8 + borderTopLeft;
GFXDrawUtil *drawer = GFX->getDrawUtil();
drawer->clearBitmapModulation();
if(profile->mBitmapArrayRects.size() >= (numBitmaps * baseMultiplier))
{
RectI destRect;
RectI stretchRect;
RectI* mBitmapBounds = profile->mBitmapArrayRects.address();
// Draw all corners first.
//top left border
drawer->drawBitmapSR(profile->mTextureObject,Point2I(bounds.point.x,bounds.point.y),mBitmapBounds[borderTopLeft]);
//top right border
drawer->drawBitmapSR(profile->mTextureObject,Point2I(bounds.point.x + bounds.extent.x - mBitmapBounds[borderTopRight].extent.x,bounds.point.y),mBitmapBounds[borderTopRight]);
//bottom left border
drawer->drawBitmapSR(profile->mTextureObject,Point2I(bounds.point.x,bounds.point.y + bounds.extent.y - mBitmapBounds[borderBottomLeft].extent.y),mBitmapBounds[borderBottomLeft]);
//bottom right border
drawer->drawBitmapSR(profile->mTextureObject,Point2I(
bounds.point.x + bounds.extent.x - mBitmapBounds[borderBottomRight].extent.x,
bounds.point.y + bounds.extent.y - mBitmapBounds[borderBottomRight].extent.y),
mBitmapBounds[borderBottomRight]);
// End drawing corners
// Begin drawing sides and top stretched borders
//start with top line stretch
destRect.point.x = bounds.point.x + mBitmapBounds[borderTopLeft].extent.x;
destRect.extent.x = bounds.extent.x - mBitmapBounds[borderTopRight].extent.x - mBitmapBounds[borderTopLeft].extent.x;
destRect.extent.y = mBitmapBounds[borderTop].extent.y;
destRect.point.y = bounds.point.y;
//stretch it
stretchRect = mBitmapBounds[borderTop];
stretchRect.inset(1,0);
//draw it
drawer->drawBitmapStretchSR(profile->mTextureObject,destRect,stretchRect);
//bottom line stretch
destRect.point.x = bounds.point.x + mBitmapBounds[borderBottomLeft].extent.x;
destRect.extent.x = bounds.extent.x - mBitmapBounds[borderBottomRight].extent.x - mBitmapBounds[borderBottomLeft].extent.x;
destRect.extent.y = mBitmapBounds[borderBottom].extent.y;
destRect.point.y = bounds.point.y + bounds.extent.y - mBitmapBounds[borderBottom].extent.y;
//stretch it
stretchRect = mBitmapBounds[borderBottom];
stretchRect.inset(1,0);
//draw it
drawer->drawBitmapStretchSR(profile->mTextureObject,destRect,stretchRect);
//left line stretch
destRect.point.x = bounds.point.x;
destRect.extent.x = mBitmapBounds[borderLeft].extent.x;
destRect.extent.y = bounds.extent.y - mBitmapBounds[borderTopLeft].extent.y - mBitmapBounds[borderBottomLeft].extent.y;
destRect.point.y = bounds.point.y + mBitmapBounds[borderTopLeft].extent.y;
//stretch it
stretchRect = mBitmapBounds[borderLeft];
stretchRect.inset(0,1);
//draw it
drawer->drawBitmapStretchSR(profile->mTextureObject,destRect,stretchRect);
//right line stretch
destRect.point.x = bounds.point.x + bounds.extent.x - mBitmapBounds[borderRight].extent.x;
destRect.extent.x = mBitmapBounds[borderRight].extent.x;
destRect.extent.y = bounds.extent.y - mBitmapBounds[borderTopRight].extent.y - mBitmapBounds[borderBottomRight].extent.y;
destRect.point.y = bounds.point.y + mBitmapBounds[borderTopRight].extent.y;
//stretch it
stretchRect = mBitmapBounds[borderRight];
stretchRect.inset(0,1);
//draw it
drawer->drawBitmapStretchSR(profile->mTextureObject,destRect,stretchRect);
//fill stretch
destRect.point.x = bounds.point.x + mBitmapBounds[borderLeft].extent.x;
destRect.extent.x = (bounds.extent.x) - mBitmapBounds[borderLeft].extent.x - mBitmapBounds[borderRight].extent.x;
destRect.extent.y = bounds.extent.y - mBitmapBounds[borderTop].extent.y - mBitmapBounds[borderBottom].extent.y;
destRect.point.y = bounds.point.y + mBitmapBounds[borderTop].extent.y;
//stretch it
stretchRect = mBitmapBounds[fill];
stretchRect.inset(1,1);
//draw it
drawer->drawBitmapStretchSR(profile->mTextureObject,destRect,stretchRect);
// End drawing sides and top stretched borders
}
}
// Render out the sizable bitmap borders based on a multiplier into the bitmap array
// Based on the 'Skinnable GUI Controls in TGE' resource by Justin DuJardin
void renderSizableBitmapBordersFilledIndex( const RectI &bounds, S32 startIndex, GuiControlProfile *profile )
{
// Indices into the bitmap array
S32 numBitmaps = 9;
S32 borderTopLeft = startIndex;
S32 borderTop = 1 + borderTopLeft;
S32 borderTopRight = 2 + borderTopLeft;
S32 borderLeft = 3 + borderTopLeft;
S32 fill = 4 + borderTopLeft;
S32 borderRight = 5 + borderTopLeft;
S32 borderBottomLeft = 6 + borderTopLeft;
S32 borderBottom = 7 + borderTopLeft;
S32 borderBottomRight = 8 + borderTopLeft;
GFXDrawUtil *drawer = GFX->getDrawUtil();
drawer->clearBitmapModulation();
if(profile->mBitmapArrayRects.size() >= (startIndex + numBitmaps))
{
RectI destRect;
RectI stretchRect;
RectI* mBitmapBounds = profile->mBitmapArrayRects.address();
// Draw all corners first.
//top left border
drawer->drawBitmapSR(profile->mTextureObject,Point2I(bounds.point.x,bounds.point.y),mBitmapBounds[borderTopLeft]);
//top right border
drawer->drawBitmapSR(profile->mTextureObject,Point2I(bounds.point.x + bounds.extent.x - mBitmapBounds[borderTopRight].extent.x,bounds.point.y),mBitmapBounds[borderTopRight]);
//bottom left border
drawer->drawBitmapSR(profile->mTextureObject,Point2I(bounds.point.x,bounds.point.y + bounds.extent.y - mBitmapBounds[borderBottomLeft].extent.y),mBitmapBounds[borderBottomLeft]);
//bottom right border
drawer->drawBitmapSR(profile->mTextureObject,Point2I(
bounds.point.x + bounds.extent.x - mBitmapBounds[borderBottomRight].extent.x,
bounds.point.y + bounds.extent.y - mBitmapBounds[borderBottomRight].extent.y),
mBitmapBounds[borderBottomRight]);
// End drawing corners
// Begin drawing sides and top stretched borders
//start with top line stretch
destRect.point.x = bounds.point.x + mBitmapBounds[borderTopLeft].extent.x;
destRect.extent.x = bounds.extent.x - mBitmapBounds[borderTopRight].extent.x - mBitmapBounds[borderTopLeft].extent.x;
destRect.extent.y = mBitmapBounds[borderTop].extent.y;
destRect.point.y = bounds.point.y;
//stretch it
stretchRect = mBitmapBounds[borderTop];
stretchRect.inset(1,0);
//draw it
drawer->drawBitmapStretchSR(profile->mTextureObject,destRect,stretchRect);
//bottom line stretch
destRect.point.x = bounds.point.x + mBitmapBounds[borderBottomLeft].extent.x;
destRect.extent.x = bounds.extent.x - mBitmapBounds[borderBottomRight].extent.x - mBitmapBounds[borderBottomLeft].extent.x;
destRect.extent.y = mBitmapBounds[borderBottom].extent.y;
destRect.point.y = bounds.point.y + bounds.extent.y - mBitmapBounds[borderBottom].extent.y;
//stretch it
stretchRect = mBitmapBounds[borderBottom];
stretchRect.inset(1,0);
//draw it
drawer->drawBitmapStretchSR(profile->mTextureObject,destRect,stretchRect);
//left line stretch
destRect.point.x = bounds.point.x;
destRect.extent.x = mBitmapBounds[borderLeft].extent.x;
destRect.extent.y = bounds.extent.y - mBitmapBounds[borderTopLeft].extent.y - mBitmapBounds[borderBottomLeft].extent.y;
destRect.point.y = bounds.point.y + mBitmapBounds[borderTopLeft].extent.y;
//stretch it
stretchRect = mBitmapBounds[borderLeft];
stretchRect.inset(0,1);
//draw it
drawer->drawBitmapStretchSR(profile->mTextureObject,destRect,stretchRect);
//left line stretch
destRect.point.x = bounds.point.x + bounds.extent.x - mBitmapBounds[borderRight].extent.x;
destRect.extent.x = mBitmapBounds[borderRight].extent.x;
destRect.extent.y = bounds.extent.y - mBitmapBounds[borderTopRight].extent.y - mBitmapBounds[borderBottomRight].extent.y;
destRect.point.y = bounds.point.y + mBitmapBounds[borderTopRight].extent.y;
//stretch it
stretchRect = mBitmapBounds[borderRight];
stretchRect.inset(0,1);
//draw it
drawer->drawBitmapStretchSR(profile->mTextureObject,destRect,stretchRect);
//fill stretch
destRect.point.x = bounds.point.x + mBitmapBounds[borderLeft].extent.x;
destRect.extent.x = (bounds.extent.x) - mBitmapBounds[borderLeft].extent.x - mBitmapBounds[borderRight].extent.x;
destRect.extent.y = bounds.extent.y - mBitmapBounds[borderTop].extent.y - mBitmapBounds[borderBottom].extent.y;
destRect.point.y = bounds.point.y + mBitmapBounds[borderTop].extent.y;
//stretch it
stretchRect = mBitmapBounds[fill];
stretchRect.inset(1,1);
//draw it
drawer->drawBitmapStretchSR(profile->mTextureObject,destRect,stretchRect);
// End drawing sides and top stretched borders
}
}
// Render out the fixed bitmap borders based on a multiplier into the bitmap array
// It renders left and right caps, with a sizable fill area in the middle to reach
// the x extent. It does not stretch in the y direction.
void renderFixedBitmapBordersFilled( const RectI &bounds, S32 baseMultiplier, GuiControlProfile *profile )
{
// Indices into the bitmap array
S32 numBitmaps = 3;
S32 borderLeft = numBitmaps * baseMultiplier - numBitmaps;
S32 fill = 1 + borderLeft;
S32 borderRight = 2 + borderLeft;
GFXDrawUtil *drawer = GFX->getDrawUtil();
drawer->clearBitmapModulation();
if(profile->mBitmapArrayRects.size() >= (numBitmaps * baseMultiplier))
{
RectI destRect;
RectI stretchRect;
RectI* mBitmapBounds = profile->mBitmapArrayRects.address();
// Draw all corners first.
//left border
drawer->drawBitmapSR(profile->mTextureObject,Point2I(bounds.point.x,bounds.point.y),mBitmapBounds[borderLeft]);
//right border
drawer->drawBitmapSR(profile->mTextureObject,Point2I(bounds.point.x + bounds.extent.x - mBitmapBounds[borderRight].extent.x,bounds.point.y),mBitmapBounds[borderRight]);
// End drawing corners
// Begin drawing fill
//fill stretch
destRect.point.x = bounds.point.x + mBitmapBounds[borderLeft].extent.x;
destRect.extent.x = (bounds.extent.x) - mBitmapBounds[borderLeft].extent.x - mBitmapBounds[borderRight].extent.x;
destRect.extent.y = mBitmapBounds[fill].extent.y;
destRect.point.y = bounds.point.y;
//stretch it
stretchRect = mBitmapBounds[fill];
stretchRect.inset(1,0);
//draw it
drawer->drawBitmapStretchSR(profile->mTextureObject,destRect,stretchRect);
// End drawing fill
}
}
// Render out the fixed bitmap borders based on a multiplier into the bitmap array
// It renders left and right caps, with a sizable fill area in the middle to reach
// the x extent. It does not stretch in the y direction.
void renderFixedBitmapBordersFilledIndex( const RectI &bounds, S32 startIndex, GuiControlProfile *profile )
{
// Indices into the bitmap array
S32 numBitmaps = 3;
S32 borderLeft = startIndex;
S32 fill = 1 + startIndex;
S32 borderRight = 2 + startIndex;
GFXDrawUtil *drawer = GFX->getDrawUtil();
drawer->clearBitmapModulation();
if(profile->mBitmapArrayRects.size() >= (startIndex + numBitmaps))
{
RectI destRect;
RectI stretchRect;
RectI* mBitmapBounds = profile->mBitmapArrayRects.address();
// Draw all corners first.
//left border
drawer->drawBitmapSR(profile->mTextureObject,Point2I(bounds.point.x,bounds.point.y),mBitmapBounds[borderLeft]);
//right border
drawer->drawBitmapSR(profile->mTextureObject,Point2I(bounds.point.x + bounds.extent.x - mBitmapBounds[borderRight].extent.x,bounds.point.y),mBitmapBounds[borderRight]);
// End drawing corners
// Begin drawing fill
//fill stretch
destRect.point.x = bounds.point.x + mBitmapBounds[borderLeft].extent.x;
destRect.extent.x = (bounds.extent.x) - mBitmapBounds[borderLeft].extent.x - mBitmapBounds[borderRight].extent.x;
destRect.extent.y = mBitmapBounds[fill].extent.y;
destRect.point.y = bounds.point.y;
//stretch it
stretchRect = mBitmapBounds[fill];
stretchRect.inset(1,0);
//draw it
drawer->drawBitmapStretchSR(profile->mTextureObject,destRect,stretchRect);
// End drawing fill
}
}

View file

@ -0,0 +1,45 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _H_GUIDEFAULTCONTROLRENDER_
#define _H_GUIDEFAULTCONTROLRENDER_
#ifndef _MRECT_H_
#include "math/mRect.h"
#endif
class GuiControlProfile;
class ColorI;
void renderRaisedBox( const RectI &bounds, GuiControlProfile *profile);
void renderSlightlyRaisedBox( const RectI &bounds, GuiControlProfile *profile);
void renderLoweredBox( const RectI &bounds, GuiControlProfile *profile);
void renderSlightlyLoweredBox( const RectI &bounds, GuiControlProfile *profile);
void renderBorder( const RectI &bounds, GuiControlProfile *profile);
void renderFilledBorder( const RectI &bounds, GuiControlProfile *profile );
void renderFilledBorder( const RectI &bounds, const ColorI &borderColor, const ColorI &fillColor, U32 thickness = 1 );
void renderSizableBitmapBordersFilled( const RectI &bounds, S32 baseMultiplier, GuiControlProfile *profile); // Added
void renderSizableBitmapBordersFilledIndex( const RectI &bounds, S32 startIndex, GuiControlProfile *profile);
void renderFixedBitmapBordersFilled( const RectI &bounds, S32 baseMultiplier, GuiControlProfile *profile); // Added
void renderFixedBitmapBordersFilled( const RectI &bounds, S32 startIndex, GuiControlProfile *profile);
#endif

View file

@ -0,0 +1,285 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "gui/core/guiScriptNotifyControl.h"
#include "console/consoleTypes.h"
#include "console/engineAPI.h"
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GuiScriptNotifyCtrl);
ConsoleDocClass( GuiScriptNotifyCtrl,
"@brief A control which adds several reactions to other GUIs via callbacks.\n\n"
"GuiScriptNotifyCtrl does not exist to render anything. When parented or made a child of "
"other controls, you can toggle flags on or off to make use of its specialized callbacks. "
"Normally these callbacks are used as utility functions by the GUI Editor, or other container "
"classes. However, for very fancy GUI work where controls interact with each other "
"constantly, this is a handy utility to make use of.\n\n "
"@tsexample\n"
"// Common member fields left out for sake of example\n"
"new GuiScriptNotifyCtrl()\n"
"{\n"
" onChildAdded = \"0\";\n"
" onChildRemoved = \"0\";\n"
" onChildResized = \"0\";\n"
" onParentResized = \"0\";\n"
"};\n"
"@endtsexample\n\n"
"@ingroup GuiUtil\n");
GuiScriptNotifyCtrl::GuiScriptNotifyCtrl()
{
mOnChildAdded = false;
mOnChildRemoved = false;
mOnResize = false;
mOnChildResized = false;
mOnParentResized = false;
}
GuiScriptNotifyCtrl::~GuiScriptNotifyCtrl()
{
}
void GuiScriptNotifyCtrl::initPersistFields()
{
// Callbacks Group
addGroup("Callbacks");
addField("onChildAdded", TypeBool, Offset( mOnChildAdded, GuiScriptNotifyCtrl ), "Enables/disables onChildAdded callback" );
addField("onChildRemoved", TypeBool, Offset( mOnChildRemoved, GuiScriptNotifyCtrl ), "Enables/disables onChildRemoved callback" );
addField("onChildResized", TypeBool, Offset( mOnChildResized, GuiScriptNotifyCtrl ), "Enables/disables onChildResized callback" );
addField("onParentResized", TypeBool, Offset( mOnParentResized, GuiScriptNotifyCtrl ), "Enables/disables onParentResized callback" );
addField("onResize", TypeBool, Offset( mOnResize, GuiScriptNotifyCtrl ), "Enables/disables onResize callback" );
addField("onLoseFirstResponder", TypeBool, Offset( mOnLoseFirstResponder, GuiScriptNotifyCtrl ), "Enables/disables onLoseFirstResponder callback" );
addField("onGainFirstResponder", TypeBool, Offset( mOnGainFirstResponder, GuiScriptNotifyCtrl ), "Enables/disables onGainFirstResponder callback" );
endGroup("Callbacks");
Parent::initPersistFields();
}
IMPLEMENT_CALLBACK( GuiScriptNotifyCtrl, onResize, void, ( SimObjectId ID ), ( ID ),
"Called when this GUI is resized.\n\n"
"@param ID Unique object ID assigned when created (%this in script).\n"
);
IMPLEMENT_CALLBACK( GuiScriptNotifyCtrl, onChildAdded, void, ( SimObjectId ID, SimObjectId childID ), ( ID, childID ),
"Called when a child is added to this GUI.\n\n"
"@param ID Unique object ID assigned when created (%this in script).\n"
"@param childID Unique object ID of child being added.\n"
);
IMPLEMENT_CALLBACK( GuiScriptNotifyCtrl, onChildRemoved, void, ( SimObjectId ID, SimObjectId childID ), ( ID, childID ),
"Called when a child is removed from this GUI.\n\n"
"@param ID Unique object ID assigned when created (%this in script).\n"
"@param childID Unique object ID of child being removed.\n"
);
IMPLEMENT_CALLBACK( GuiScriptNotifyCtrl, onChildResized, void, ( SimObjectId ID, SimObjectId childID ), ( ID, childID ),
"Called when a child is of this GUI is being resized.\n\n"
"@param ID Unique object ID assigned when created (%this in script).\n"
"@param childID Unique object ID of child being resized.\n"
);
IMPLEMENT_CALLBACK( GuiScriptNotifyCtrl, onParentResized, void, ( SimObjectId ID ), ( ID ),
"Called when this GUI's parent is resized.\n\n"
"@param ID Unique object ID assigned when created (%this in script).\n"
);
IMPLEMENT_CALLBACK( GuiScriptNotifyCtrl, onLoseFirstResponder, void, ( SimObjectId ID ), ( ID ),
"Called when this GUI loses focus.\n\n"
"@param ID Unique object ID assigned when created (%this in script).\n"
);
IMPLEMENT_CALLBACK( GuiScriptNotifyCtrl, onGainFirstResponder, void, ( SimObjectId ID ), ( ID ),
"Called when this GUI gains focus.\n\n"
"@param ID Unique object ID assigned when created (%this in script).\n"
);
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
void GuiScriptNotifyCtrl::onChildAdded( GuiControl *child )
{
Parent::onChildAdded( child );
// Call Script.
if( mOnChildAdded )
onChildAdded_callback(getId(), child->getId());
}
void GuiScriptNotifyCtrl::onChildRemoved( GuiControl *child )
{
Parent::onChildRemoved( child );
// Call Script.
if( mOnChildRemoved )
onChildRemoved_callback(getId(), child->getId());
}
//----------------------------------------------------------------
bool GuiScriptNotifyCtrl::resize(const Point2I &newPosition, const Point2I &newExtent)
{
if( !Parent::resize( newPosition, newExtent ) )
return false;
// Call Script.
if( mOnResize )
onResize_callback(getId());
return true;
}
void GuiScriptNotifyCtrl::childResized(GuiScriptNotifyCtrl *child)
{
Parent::childResized( child );
// Call Script.
if( mOnChildResized )
onChildResized_callback(getId(), child->getId());
}
void GuiScriptNotifyCtrl::parentResized(const RectI &oldParentRect, const RectI &newParentRect)
{
Parent::parentResized( oldParentRect, newParentRect );
// Call Script.
if( mOnParentResized )
onParentResized_callback(getId());
}
void GuiScriptNotifyCtrl::onLoseFirstResponder()
{
Parent::onLoseFirstResponder();
// Call Script.
if( mOnLoseFirstResponder )
onLoseFirstResponder_callback(getId());
}
void GuiScriptNotifyCtrl::setFirstResponder( GuiControl* firstResponder )
{
Parent::setFirstResponder( firstResponder );
// Call Script.
if( mOnGainFirstResponder && isFirstResponder() )
onGainFirstResponder_callback(getId());
}
void GuiScriptNotifyCtrl::setFirstResponder()
{
Parent::setFirstResponder();
// Call Script.
if( mOnGainFirstResponder && isFirstResponder() )
onGainFirstResponder_callback(getId());
}
void GuiScriptNotifyCtrl::onMessage(GuiScriptNotifyCtrl *sender, S32 msg)
{
Parent::onMessage( sender, msg );
}
void GuiScriptNotifyCtrl::onDialogPush()
{
Parent::onDialogPush();
}
void GuiScriptNotifyCtrl::onDialogPop()
{
Parent::onDialogPop();
}
//void GuiScriptNotifyCtrl::onMouseUp(const GuiEvent &event)
//{
//}
//
//void GuiScriptNotifyCtrl::onMouseDown(const GuiEvent &event)
//{
//}
//
//void GuiScriptNotifyCtrl::onMouseMove(const GuiEvent &event)
//{
//}
//
//void GuiScriptNotifyCtrl::onMouseDragged(const GuiEvent &event)
//{
//}
//
//void GuiScriptNotifyCtrl::onMouseEnter(const GuiEvent &)
//{
//}
//
//void GuiScriptNotifyCtrl::onMouseLeave(const GuiEvent &)
//{
//}
//
//bool GuiScriptNotifyCtrl::onMouseWheelUp( const GuiEvent &event )
//{
//}
//
//bool GuiScriptNotifyCtrl::onMouseWheelDown( const GuiEvent &event )
//{
//}
//
//void GuiScriptNotifyCtrl::onRightMouseDown(const GuiEvent &)
//{
//}
//
//void GuiScriptNotifyCtrl::onRightMouseUp(const GuiEvent &)
//{
//}
//
//void GuiScriptNotifyCtrl::onRightMouseDragged(const GuiEvent &)
//{
//}
//
//void GuiScriptNotifyCtrl::onMiddleMouseDown(const GuiEvent &)
//{
//}
//
//void GuiScriptNotifyCtrl::onMiddleMouseUp(const GuiEvent &)
//{
//}
//
//void GuiScriptNotifyCtrl::onMiddleMouseDragged(const GuiEvent &)
//{
//}
//void GuiScriptNotifyCtrl::onMouseDownEditor(const GuiEvent &event, Point2I offset)
//{
//}
//void GuiScriptNotifyCtrl::onRightMouseDownEditor(const GuiEvent &event, Point2I offset)
//{
//}
//bool GuiScriptNotifyCtrl::onKeyDown(const GuiEvent &event)
//{
// if ( Parent::onKeyDown( event ) )
// return true;
//}
//
//bool GuiScriptNotifyCtrl::onKeyRepeat(const GuiEvent &event)
//{
// // default to just another key down.
// return onKeyDown(event);
//}
//
//bool GuiScriptNotifyCtrl::onKeyUp(const GuiEvent &event)
//{
// if ( Parent::onKeyUp( event ) )
// return true;
//}

View file

@ -0,0 +1,115 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUISCRIPTNOTIFYCTRL_H_
#define _GUISCRIPTNOTIFYCTRL_H_
#ifndef _GUICONTROL_H_
#include "gui/core/guiControl.h"
#endif
class GuiScriptNotifyCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
public:
/// @name Event Callbacks
/// @{
bool mOnChildAdded; ///< Script Notify : onAddObject(%object)
bool mOnChildRemoved; ///< Script Notify : onRemoveObject(%object)
bool mOnResize; ///< Script Notify : onResize()
bool mOnChildResized; ///< Script Notify : onChildResized(%child)
bool mOnParentResized; ///< Script Notify : onParentResized()
bool mOnLoseFirstResponder; ///< Script Notify : onLoseFirstResponder()
bool mOnGainFirstResponder; ///< Script Notify : onGainFirstResponder()
/// @}
public:
/// @name Initialization
/// @{
DECLARE_CONOBJECT(GuiScriptNotifyCtrl);
DECLARE_CATEGORY( "Gui Other Script" );
DECLARE_DESCRIPTION( "A control that implements various script callbacks for\n"
"certain GUI events." );
GuiScriptNotifyCtrl();
virtual ~GuiScriptNotifyCtrl();
static void initPersistFields();
virtual bool resize(const Point2I &newPosition, const Point2I &newExtent);
virtual void childResized(GuiScriptNotifyCtrl *child);
virtual void parentResized(const RectI &oldParentRect, const RectI &newParentRect);
virtual void onChildRemoved( GuiControl *child );
virtual void onChildAdded( GuiControl *child );
DECLARE_CALLBACK(void, onResize, (SimObjectId ID) );
DECLARE_CALLBACK(void, onChildAdded, (SimObjectId ID, SimObjectId childID));
DECLARE_CALLBACK(void, onChildRemoved, (SimObjectId ID, SimObjectId childID));
DECLARE_CALLBACK(void, onChildResized, (SimObjectId ID, SimObjectId childID));
DECLARE_CALLBACK(void, onParentResized, (SimObjectId ID));
DECLARE_CALLBACK(void, onLoseFirstResponder, (SimObjectId ID));
DECLARE_CALLBACK(void, onGainFirstResponder, (SimObjectId ID));
//virtual void onMouseUp(const GuiEvent &event);
//virtual void onMouseDown(const GuiEvent &event);
//virtual void onMouseMove(const GuiEvent &event);
//virtual void onMouseDragged(const GuiEvent &event);
//virtual void onMouseEnter(const GuiEvent &event);
//virtual void onMouseLeave(const GuiEvent &event);
//virtual bool onMouseWheelUp(const GuiEvent &event);
//virtual bool onMouseWheelDown(const GuiEvent &event);
//virtual void onRightMouseDown(const GuiEvent &event);
//virtual void onRightMouseUp(const GuiEvent &event);
//virtual void onRightMouseDragged(const GuiEvent &event);
//virtual void onMiddleMouseDown(const GuiEvent &event);
//virtual void onMiddleMouseUp(const GuiEvent &event);
//virtual void onMiddleMouseDragged(const GuiEvent &event);
//virtual void onMouseDownEditor(const GuiEvent &event, Point2I offset);
//virtual void onRightMouseDownEditor(const GuiEvent &event, Point2I offset);
virtual void setFirstResponder(GuiControl *firstResponder);
virtual void setFirstResponder();
void clearFirstResponder();
virtual void onLoseFirstResponder();
//virtual void acceleratorKeyPress(U32 index);
//virtual void acceleratorKeyRelease(U32 index);
//virtual bool onKeyDown(const GuiEvent &event);
//virtual bool onKeyUp(const GuiEvent &event);
//virtual bool onKeyRepeat(const GuiEvent &event);
virtual void onMessage(GuiScriptNotifyCtrl *sender, S32 msg); ///< Receive a message from another control
virtual void onDialogPush();
virtual void onDialogPop();
};
#endif

View file

@ -0,0 +1,737 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "platform/types.h"
#include "console/consoleTypes.h"
#include "console/console.h"
#include "gui/core/guiTypes.h"
#include "gui/core/guiControl.h"
#include "gfx/gFont.h"
#include "gfx/bitmap/gBitmap.h"
#include "gfx/gfxDevice.h"
#include "gfx/gfxDrawUtil.h"
#include "sfx/sfxTrack.h"
#include "sfx/sfxTypes.h"
#include "console/engineAPI.h"
//#define DEBUG_SPEW
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
IMPLEMENT_CONOBJECT(GuiCursor);
ConsoleDocClass( GuiCursor,
"@brief Acts as a skin for the cursor, where each GuiCursor object can have its own look and click-zone.\n\n"
"GuiCursors act as skins for the cursor in the game, where each individual GuiCursor can have its own defined imagemap,\n"
"click zone and render offset. This allows a game to easily support a wide range of cursors. The active cursor can de changed\n"
"for each Canvas using %canvasObj.setCursor(GuiCursor);."
"@tsexample\n"
"new GuiCursor(DefaultCursor)\n"
"{\n"
" hotSpot = \"1 1\";\n"
" renderOffset = \"0 0\";\n"
" bitmapName = \"~/art/gui/images/defaultCursor\";\n"
"};\n"
"@endtsexample\n\n"
"@see GuiCanvas\n\n"
"@ingroup GuiCore\n"
);
GFX_ImplementTextureProfile(GFXGuiCursorProfile,
GFXTextureProfile::DiffuseMap,
GFXTextureProfile::PreserveSize |
GFXTextureProfile::Static,
GFXTextureProfile::None);
GFX_ImplementTextureProfile(GFXDefaultGUIProfile,
GFXTextureProfile::DiffuseMap,
GFXTextureProfile::PreserveSize |
GFXTextureProfile::Static |
GFXTextureProfile::NoPadding,
GFXTextureProfile::None);
GuiCursor::GuiCursor()
{
mHotSpot.set(0,0);
mRenderOffset.set(0.0f,0.0f);
mExtent.set(1,1);
mTextureObject = NULL;
}
GuiCursor::~GuiCursor()
{
}
void GuiCursor::initPersistFields()
{
addField("hotSpot", TypePoint2I, Offset(mHotSpot, GuiCursor), "The location of the cursor's hot spot (which pixel carries the click).");
addField("renderOffset",TypePoint2F, Offset(mRenderOffset, GuiCursor), "Offset of the bitmap, where 0 signifies left edge of the bitmap, 1, the right. Similarly for the Y-component.");
addField("bitmapName", TypeFilename, Offset(mBitmapName, GuiCursor), "File name of the bitmap for the cursor.");
Parent::initPersistFields();
}
bool GuiCursor::onAdd()
{
if(!Parent::onAdd())
return false;
Sim::getGuiDataGroup()->addObject(this);
return true;
}
void GuiCursor::onRemove()
{
Parent::onRemove();
}
void GuiCursor::render(const Point2I &pos)
{
if (!mTextureObject && mBitmapName && mBitmapName[0])
{
mTextureObject.set( mBitmapName, &GFXGuiCursorProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__));
if(!mTextureObject)
return;
mExtent.set(mTextureObject->getWidth(), mTextureObject->getHeight());
}
// Render the cursor centered according to dimensions of texture
S32 texWidth = mTextureObject.getWidth();
S32 texHeight = mTextureObject.getHeight();
Point2I renderPos = pos;
renderPos.x -= (S32)( texWidth * mRenderOffset.x );
renderPos.y -= (S32)( texHeight * mRenderOffset.y );
GFX->getDrawUtil()->clearBitmapModulation();
GFX->getDrawUtil()->drawBitmap(mTextureObject, renderPos);
}
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GuiControlProfile);
ConsoleDocClass( GuiControlProfile,
"@brief A collection of properties that determine control behavior and rendering.\n"
"@ingroup GuiCore\n"
""
);
ImplementEnumType( GuiAlignmentType,
"\n\n"
"@ingroup GuiCore" )
{ GuiControlProfile::LeftJustify, "Left" },
{ GuiControlProfile::CenterJustify, "Center" },
{ GuiControlProfile::RightJustify, "Right" },
{ GuiControlProfile::TopJustify, "Top" },
{ GuiControlProfile::BottomJustify, "Bottom" }
EndImplementEnumType;
ImplementEnumType( GuiFontCharset,
"\n\n"
"@ingroup GuiCore" )
{ TGE_ANSI_CHARSET, "ANSI" },
{ TGE_SYMBOL_CHARSET, "SYMBOL" },
{ TGE_SHIFTJIS_CHARSET, "SHIFTJIS" },
{ TGE_HANGEUL_CHARSET, "HANGEUL" },
{ TGE_HANGUL_CHARSET, "HANGUL" },
{ TGE_GB2312_CHARSET, "GB2312" },
{ TGE_CHINESEBIG5_CHARSET, "CHINESEBIG5" },
{ TGE_OEM_CHARSET, "OEM" },
{ TGE_JOHAB_CHARSET, "JOHAB" },
{ TGE_HEBREW_CHARSET, "HEBREW" },
{ TGE_ARABIC_CHARSET, "ARABIC" },
{ TGE_GREEK_CHARSET, "GREEK" },
{ TGE_TURKISH_CHARSET, "TURKISH" },
{ TGE_VIETNAMESE_CHARSET, "VIETNAMESE" },
{ TGE_THAI_CHARSET, "THAI" },
{ TGE_EASTEUROPE_CHARSET, "EASTEUROPE" },
{ TGE_RUSSIAN_CHARSET, "RUSSIAN" },
{ TGE_MAC_CHARSET, "MAC" },
{ TGE_BALTIC_CHARSET, "BALTIC" },
EndImplementEnumType;
StringTableEntry GuiControlProfile::sFontCacheDirectory = "";
void GuiControlProfile::setBitmapHandle(GFXTexHandle handle)
{
mTextureObject = handle;
mBitmapName = StringTable->insert("texhandle");
}
bool GuiControlProfile::protectedSetBitmap( void *object, const char *index, const char *data )
{
GuiControlProfile *profile = static_cast<GuiControlProfile*>( object );
profile->mBitmapName = StringTable->insert(data);
if ( !profile->isProperlyAdded() )
return false;
if( profile->mLoadCount > 0 )
{
profile->mBitmapArrayRects.clear();
profile->mTextureObject = NULL;
//verify the bitmap
if (profile->mBitmapName && profile->mBitmapName[0] && dStricmp(profile->mBitmapName, "texhandle") != 0 &&
!profile->mTextureObject.set( profile->mBitmapName, &GFXDefaultPersistentProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__) ))
Con::errorf("Failed to load profile bitmap (%s)",profile->mBitmapName);
// If we've got a special border, make sure it's usable.
//if( profile->mBorder == -1 || profile->mBorder == -2 )
profile->constructBitmapArray();
}
return false;
}
const char* GuiControlProfile::protectedGetSoundButtonDown( void* object, const char* data )
{
GuiControlProfile* profile = reinterpret_cast< GuiControlProfile* >( object );
SFXTrack* track = profile->mSoundButtonDown;
if( !track )
return "";
return track->getName();
}
bool GuiControlProfile::protectedSetSoundButtonDown( void* object, const char* index, const char* data )
{
GuiControlProfile* profile = reinterpret_cast< GuiControlProfile* >( object );
SFXTrack* track = NULL;
if( data && data[ 0] && !Sim::findObject( data, track ) )
{
Con::errorf( "GuiControlProfile::protectedSetSoundButtonDown - no SFXTrack '%s'", data );
return false;
}
profile->mSoundButtonDown = track;
return false;
}
const char* GuiControlProfile::protectedGetSoundButtonOver( void* object, const char* data )
{
GuiControlProfile* profile = reinterpret_cast< GuiControlProfile* >( object );
SFXTrack* track = profile->mSoundButtonOver;
if( !track )
return "";
return track->getName();
}
bool GuiControlProfile::protectedSetSoundButtonOver( void* object, const char* index, const char* data )
{
GuiControlProfile* profile = reinterpret_cast< GuiControlProfile* >( object );
SFXTrack* track = NULL;
if( data && data[ 0] && !Sim::findObject( data, track ) )
{
Con::errorf( "GuiControlProfile::protectedSetSoundButtonOver - no SFXTrack '%s'", data );
return false;
}
profile->mSoundButtonOver = track;
return false;
}
GuiControlProfile::GuiControlProfile(void) :
mFillColor(255,0,255,255),
mFillColorHL(255,0,255,255),
mFillColorNA(255,0,255,255),
mFillColorSEL(255,0,255,255),
mBorderColor(255,0,255,255),
mBorderColorHL(255,0,255,255),
mBorderColorNA(255,0,255,255),
mBevelColorHL(255,0,255,255),
mBevelColorLL(255,0,255,255),
// initialize these references to locations in the font colors array
// the array is initialized below.
mFontColor(mFontColors[BaseColor]),
mFontColorHL(mFontColors[ColorHL]),
mFontColorNA(mFontColors[ColorNA]),
mFontColorSEL(mFontColors[ColorSEL]),
mCursorColor(255,0,255,255),
mTextOffset(0,0),
mBitmapArrayRects(0)
{
mLoadCount = 0;
mUseCount = 0;
// event focus behavior
mTabable = false;
mCanKeyFocus = false;
mModal = false;
// fill and border
mOpaque = false;
mBorder = 1;
mBorderThickness = 1;
// font members
mFontType = "Arial";
mFontSize = 10;
for(U32 i = 0; i < 10; i++)
mFontColors[i].set(255,0,255,255);
mFontCharset = TGE_ANSI_CHARSET;
// sizing and alignment
mAlignment = LeftJustify;
mAutoSizeWidth = false;
mAutoSizeHeight= false;
mReturnTab = false;
mNumbersOnly = false;
mMouseOverSelected = false;
// bitmap members
mBitmapName = NULL;
mUseBitmapArray = false;
mTextureObject = NULL; // initialized in incLoadCount()
mChildrenProfileName = NULL;
mChildrenProfile = NULL;
// inherit/copy values from GuiDefaultProfile
GuiControlProfile *def = dynamic_cast<GuiControlProfile*>(Sim::findObject("GuiDefaultProfile"));
if (def)
{
mTabable = def->mTabable;
mCanKeyFocus = def->mCanKeyFocus;
mOpaque = def->mOpaque;
mFillColor = def->mFillColor;
mFillColorHL = def->mFillColorHL;
mFillColorNA = def->mFillColorNA;
mFillColorSEL = def->mFillColorSEL;
mBorder = def->mBorder;
mBorderThickness = def->mBorderThickness;
mBorderColor = def->mBorderColor;
mBorderColorHL = def->mBorderColorHL;
mBorderColorNA = def->mBorderColorNA;
mBevelColorHL = def->mBevelColorHL;
mBevelColorLL = def->mBevelColorLL;
// default font
mFontType = def->mFontType;
mFontSize = def->mFontSize;
mFontCharset = def->mFontCharset;
for(U32 i = 0; i < 10; i++)
mFontColors[i] = def->mFontColors[i];
// default bitmap
mBitmapName = def->mBitmapName;
mUseBitmapArray = def->mUseBitmapArray;
mTextOffset = def->mTextOffset;
// default sound
mSoundButtonDown = def->mSoundButtonDown;
mSoundButtonOver = def->mSoundButtonOver;
//used by GuiTextCtrl
mModal = def->mModal;
mAlignment = def->mAlignment;
mAutoSizeWidth = def->mAutoSizeWidth;
mAutoSizeHeight= def->mAutoSizeHeight;
mReturnTab = def->mReturnTab;
mNumbersOnly = def->mNumbersOnly;
mCursorColor = def->mCursorColor;
mChildrenProfileName = def->mChildrenProfileName;
setChildrenProfile(def->mChildrenProfile);
}
}
GuiControlProfile::~GuiControlProfile()
{
}
void GuiControlProfile::initPersistFields()
{
addGroup( "Behavior" );
addField( "tab", TypeBool, Offset(mTabable, GuiControlProfile));
addField("canKeyFocus", TypeBool, Offset(mCanKeyFocus, GuiControlProfile),
"Whether the control can have the keyboard focus." );
addField("mouseOverSelected", TypeBool, Offset(mMouseOverSelected, GuiControlProfile));
addField("modal", TypeBool, Offset(mModal, GuiControlProfile));
endGroup( "Behavior" );
addGroup( "Appearance" );
addField("opaque", TypeBool, Offset(mOpaque, GuiControlProfile));
addField("fillColor", TypeColorI, Offset(mFillColor, GuiControlProfile));
addField("fillColorHL", TypeColorI, Offset(mFillColorHL, GuiControlProfile));
addField("fillColorNA", TypeColorI, Offset(mFillColorNA, GuiControlProfile));
addField("fillColorSEL", TypeColorI, Offset(mFillColorSEL, GuiControlProfile));
addField("border", TypeS32, Offset(mBorder, GuiControlProfile),
"Border type (0=no border)." );
addField("borderThickness",TypeS32, Offset(mBorderThickness, GuiControlProfile),
"Thickness of border in pixels." );
addField("borderColor", TypeColorI, Offset(mBorderColor, GuiControlProfile),
"Color to draw border with." );
addField("borderColorHL", TypeColorI, Offset(mBorderColorHL, GuiControlProfile));
addField("borderColorNA", TypeColorI, Offset(mBorderColorNA, GuiControlProfile));
addField("bevelColorHL", TypeColorI, Offset(mBevelColorHL, GuiControlProfile));
addField("bevelColorLL", TypeColorI, Offset(mBevelColorLL, GuiControlProfile));
endGroup( "Appearance" );
addGroup( "Text" );
addField("fontType", TypeString, Offset(mFontType, GuiControlProfile),
"Name of font family and typeface (e.g. \"Arial Bold\")." );
addField("fontSize", TypeS32, Offset(mFontSize, GuiControlProfile),
"Font size in points." );
addField("fontCharset", TYPEID< FontCharset >(), Offset(mFontCharset, GuiControlProfile) );
addField("fontColors", TypeColorI, Offset(mFontColors, GuiControlProfile), 10,
"Font colors to use for different text types/states." );
addField("fontColor", TypeColorI, Offset(mFontColors[BaseColor], GuiControlProfile),
"Font color for normal text (same as fontColors[0])." );
addField("fontColorHL", TypeColorI, Offset(mFontColors[ColorHL], GuiControlProfile),
"Font color for highlighted text (same as fontColors[1])." );
addField("fontColorNA", TypeColorI, Offset(mFontColors[ColorNA], GuiControlProfile),
"Font color when control is not active/disabled (same as fontColors[2])." );
addField("fontColorSEL", TypeColorI, Offset(mFontColors[ColorSEL], GuiControlProfile),
"Font color for selected text (same as fontColors[3])." );
addField("fontColorLink", TypeColorI, Offset(mFontColors[ColorUser0], GuiControlProfile),
"Font color for links in text (same as fontColors[4])." );
addField("fontColorLinkHL", TypeColorI, Offset(mFontColors[ColorUser1], GuiControlProfile),
"Font color for highlighted links in text (same as fontColors[5])." );
addField( "justify", TYPEID< GuiControlProfile::AlignmentType >(), Offset(mAlignment, GuiControlProfile),
"Horizontal alignment for text." );
addField( "textOffset", TypePoint2I, Offset(mTextOffset, GuiControlProfile));
addField( "autoSizeWidth", TypeBool, Offset(mAutoSizeWidth, GuiControlProfile),
"Automatically adjust width of control to fit contents." );
addField("autoSizeHeight",TypeBool, Offset(mAutoSizeHeight, GuiControlProfile),
"Automatically adjust height of control to fit contents." );
addField("returnTab", TypeBool, Offset(mReturnTab, GuiControlProfile),
"Whether to add automatic tab event when return is pressed so focus moves on to next control (GuiTextEditCtrl)." );
addField("numbersOnly", TypeBool, Offset(mNumbersOnly, GuiControlProfile),
"Whether control should only accept numerical data (GuiTextEditCtrl)." );
addField("cursorColor", TypeColorI, Offset(mCursorColor, GuiControlProfile),
"Color to use for the text cursor." );
endGroup( "Text" );
addGroup( "Misc" );
addProtectedField( "bitmap", TypeFilename, Offset(mBitmapName, GuiControlProfile),
&GuiControlProfile::protectedSetBitmap, &defaultProtectedGetFn,
"Texture to use for rendering control." );
addField("hasBitmapArray", TypeBool, Offset(mUseBitmapArray, GuiControlProfile),
"If true, 'bitmap' is an array of images." );
addProtectedField( "soundButtonDown", TypeSFXTrackName, Offset(mSoundButtonDown, GuiControlProfile),
&GuiControlProfile::protectedSetSoundButtonDown, &GuiControlProfile::protectedGetSoundButtonDown,
"Sound to play when mouse has been pressed on control." );
addProtectedField( "soundButtonOver", TypeSFXTrackName, Offset(mSoundButtonOver, GuiControlProfile),
&GuiControlProfile::protectedSetSoundButtonOver, &GuiControlProfile::protectedGetSoundButtonOver,
"Sound to play when mouse is hovering over control." );
addField("profileForChildren", TypeString, Offset(mChildrenProfileName, GuiControlProfile));
endGroup( "Misc" );
addField( "category", TypeRealString, Offset( mCategory, GuiControlProfile ),
"Category under which the profile will appear in the editor."
);
Parent::initPersistFields();
}
bool GuiControlProfile::onAdd()
{
if(!Parent::onAdd())
return false;
Sim::getGuiDataGroup()->addObject(this);
// Make sure we have an up-to-date children profile
getChildrenProfile();
return true;
}
void GuiControlProfile::onStaticModified(const char* slotName, const char* newValue)
{
if( mLoadCount > 0 )
{
if ( !dStricmp(slotName, "fontType") ||
!dStricmp(slotName, "fontCharset") ||
!dStricmp(slotName, "fontSize" ) )
{
// Reload the font
mFont = GFont::create(mFontType, mFontSize, sFontCacheDirectory, mFontCharset);
if ( mFont == NULL )
Con::errorf("Failed to load/create profile font (%s/%d)", mFontType, mFontSize);
}
}
}
void GuiControlProfile::onDeleteNotify(SimObject *object)
{
if (object == mChildrenProfile)
mChildrenProfile = NULL;
}
GuiControlProfile* GuiControlProfile::getChildrenProfile()
{
// We can early out if we still have a valid profile
if (mChildrenProfile)
return mChildrenProfile;
// Attempt to find the profile specified
if (mChildrenProfileName)
{
GuiControlProfile *profile = dynamic_cast<GuiControlProfile*>(Sim::findObject( mChildrenProfileName ));
if( profile )
setChildrenProfile(profile);
}
return mChildrenProfile;
}
void GuiControlProfile::setChildrenProfile(GuiControlProfile *prof)
{
if(prof == mChildrenProfile)
return;
// Clear the delete notification we previously set up
if (mChildrenProfile)
clearNotify(mChildrenProfile);
mChildrenProfile = prof;
// Make sure that the new profile will notify us when it is deleted
if (mChildrenProfile)
deleteNotify(mChildrenProfile);
}
RectI GuiControlProfile::getBitmapArrayRect(U32 i)
{
if(!mBitmapArrayRects.size())
constructBitmapArray();
if( i >= mBitmapArrayRects.size())
return RectI(0,0,0,0);
return mBitmapArrayRects[i];
}
S32 GuiControlProfile::constructBitmapArray()
{
if(mBitmapArrayRects.size())
return mBitmapArrayRects.size();
if( mTextureObject.isNull() )
{
if ( !mBitmapName || !mBitmapName[0] || !mTextureObject.set( mBitmapName, &GFXDefaultPersistentProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__) ))
return 0;
}
GBitmap *bmp = mTextureObject->getBitmap();
//get the separator color
ColorI sepColor;
if ( !bmp || !bmp->getColor( 0, 0, sepColor ) )
{
Con::errorf("Failed to create bitmap array from %s for profile %s - couldn't ascertain seperator color!", mBitmapName, getName());
AssertFatal( false, avar("Failed to create bitmap array from %s for profile %s - couldn't ascertain seperator color!", mBitmapName, getName()));
return 0;
}
//now loop through all the scroll pieces, and find the bounding rectangle for each piece in each state
S32 curY = 0;
// ascertain the height of this row...
ColorI color;
mBitmapArrayRects.clear();
while(curY < bmp->getHeight())
{
// skip any sep colors
bmp->getColor( 0, curY, color);
if(color == sepColor)
{
curY++;
continue;
}
// ok, process left to right, grabbing bitmaps as we go...
S32 curX = 0;
while(curX < bmp->getWidth())
{
bmp->getColor(curX, curY, color);
if(color == sepColor)
{
curX++;
continue;
}
S32 startX = curX;
while(curX < bmp->getWidth())
{
bmp->getColor(curX, curY, color);
if(color == sepColor)
break;
curX++;
}
S32 stepY = curY;
while(stepY < bmp->getHeight())
{
bmp->getColor(startX, stepY, color);
if(color == sepColor)
break;
stepY++;
}
mBitmapArrayRects.push_back(RectI(startX, curY, curX - startX, stepY - curY));
}
// ok, now skip to the next separation color on column 0
while(curY < bmp->getHeight())
{
bmp->getColor(0, curY, color);
if(color == sepColor)
break;
curY++;
}
}
return mBitmapArrayRects.size();
}
void GuiControlProfile::incLoadCount()
{
if( !mLoadCount )
{
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[GuiControlProfile] Loading profile %i:%s (%s:%s)",
getId(), getClassName(), getName(), getInternalName() );
#endif
sFontCacheDirectory = Con::getVariable( "$GUI::fontCacheDirectory" );
// Load font (if not already loaded).
if( mFont == NULL )
loadFont();
//
if (mBitmapName && mBitmapName[0] && dStricmp(mBitmapName, "texhandle") != 0 &&
!mTextureObject.set( mBitmapName, &GFXDefaultPersistentProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__) ))
Con::errorf("Failed to load profile bitmap (%s)",mBitmapName);
constructBitmapArray();
}
mLoadCount ++;
// Quick check to make sure our children profile is up-to-date
getChildrenProfile();
}
void GuiControlProfile::decLoadCount()
{
AssertFatal( mLoadCount, "GuiControlProfile::decLoadCount - zero load count" );
if(!mLoadCount)
return;
-- mLoadCount;
if( !mLoadCount )
{
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[GuiControlProfile] Unloading profile %i:%s (%s:%s)",
getId(), getClassName(), getName(), getInternalName() );
#endif
if( !mBitmapName || !mBitmapName[0] || dStricmp(mBitmapName, "texhandle") != 0 )
mTextureObject = NULL;
}
}
bool GuiControlProfile::loadFont()
{
mFont = GFont::create( mFontType, mFontSize, sFontCacheDirectory, mFontCharset );
if( mFont == NULL )
{
Con::errorf( "GuiControlProfile::loadFont - Failed to load/create profile font (%s/%d)", mFontType, mFontSize );
return false;
}
return true;
}
ConsoleMethod( GuiControlProfile, getStringWidth, S32, 3, 3, "( pString )" )
{
return object->mFont->getStrNWidth( argv[2], dStrlen( argv[2] ) );
}
//-----------------------------------------------------------------------------
// TypeRectSpacingI
//-----------------------------------------------------------------------------
IMPLEMENT_STRUCT( RectSpacingI,
RectSpacingI, GuiAPI,
"" )
FIELD( left, leftPadding, 1, "" )
FIELD( right, rightPadding, 1, "" )
FIELD( top, topPadding, 1, "" )
FIELD( bottom, bottomPadding, 1, "" )
END_IMPLEMENT_STRUCT;
ConsoleType( RectSpacingI, TypeRectSpacingI, RectSpacingI )
ImplementConsoleTypeCasters( TypeRectSpacingI, RectSpacingI )
ConsoleGetType( TypeRectSpacingI )
{
RectSpacingI *rect = (RectSpacingI *) dptr;
char* returnBuffer = Con::getReturnBuffer(256);
dSprintf(returnBuffer, 256, "%d %d %d %d", rect->top, rect->bottom,
rect->left, rect->right);
return returnBuffer;
}
ConsoleSetType( TypeRectSpacingI )
{
if(argc == 1)
dSscanf(argv[0], "%d %d %d %d", &((RectSpacingI *) dptr)->top, &((RectSpacingI *) dptr)->bottom,
&((RectSpacingI *) dptr)->left, &((RectSpacingI *) dptr)->right);
else if(argc == 4)
*((RectSpacingI *) dptr) = RectSpacingI(dAtoi(argv[0]), dAtoi(argv[1]), dAtoi(argv[2]), dAtoi(argv[3]));
else
Con::printf("RectSpacingI must be set as { t, b, l, r } or \"t b l r\"");
}

View file

@ -0,0 +1,523 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUITYPES_H_
#define _GUITYPES_H_
#ifndef _GFONT_H_
#include "gfx/gFont.h"
#endif
#ifndef _COLOR_H_
#include "core/color.h"
#endif
#ifndef _SIMBASE_H_
#include "console/simBase.h"
#endif
#ifndef _DYNAMIC_CONSOLETYPES_H_
#include "console/dynamicTypes.h"
#endif
#include "gfx/gfxDevice.h"
#include "platform/event.h"
class GBitmap;
class SFXTrack;
/// Represents a single GUI event.
///
/// This is passed around to all the relevant controls so they know what's going on.
struct GuiEvent
{
U16 ascii; ///< ascii character code 'a', 'A', 'b', '*', etc (if device==keyboard) - possibly a uchar or something
U8 modifier; ///< SI_LSHIFT, etc
InputObjectInstances keyCode; ///< for unprintables, 'tab', 'return', ...
Point2I mousePoint; ///< for mouse events
U8 mouseClickCount; ///< to determine double clicks, etc...
U8 mouseAxis; ///< mousewheel axis (0 == X, 1 == Y)
F32 fval; ///< used for mousewheel events
GuiEvent()
: ascii( 0 ),
modifier( 0 ),
keyCode( KEY_NULL ),
mousePoint( 0, 0 ),
mouseClickCount( 0 ),
mouseAxis( 0 ),
fval( 0.f ) {}
};
/// Represent a mouse event with a 3D position and vector.
///
/// This event used by the EditTSCtrl derived controls.
struct Gui3DMouseEvent : public GuiEvent
{
Point3F vec;
Point3F pos;
Gui3DMouseEvent()
: vec( 0.f, 0.f, 0.f ),
pos( 0.f, 0.f, 0.f ) {}
};
/// @name Docking Flag
/// @{
/// @brief Docking Options available to all GuiControl subclasses.
namespace Docking
{
enum DockingType
{
dockNone = BIT(0), ///< Do not align this control to it's parent, let the control specify it's position/extent (default)
dockClient = BIT(1), ///< Align this control to the client area available in the parent
dockTop = BIT(2), ///< Align this control to the topmost border of it's parent (Width will be parent width)
dockBottom = BIT(3), ///< Align this control to the bottommost border of it's parent (Width will be parent width)
dockLeft = BIT(4), ///< Align this control to the leftmost border of it's parent (Height will be parent height)
dockRight = BIT(5), ///< Align this control to the rightmost border of it's parent (Height will be parent height)
dockInvalid = BIT(6), ///< Default NOT specified docking mode, this allows old sizing to takeover when needed by controls
dockAny = dockClient | dockTop | dockBottom | dockLeft | dockRight
};
};
typedef Docking::DockingType GuiDockingType;
DefineEnumType( GuiDockingType );
/// @}
/// @name Margin Padding Structure
/// @{
struct RectSpacingI
{
S32 left;
S32 top;
S32 bottom;
S32 right;
RectSpacingI() { left = right = top = bottom = 0; };
RectSpacingI( S32 in_top, S32 in_bottom, S32 in_left, S32 in_right )
{
top = in_top;
bottom = in_bottom;
left = in_left;
right = in_right;
}
void setAll( S32 value ) { left = right = top = bottom = value; };
void set( S32 in_top, S32 in_bottom, S32 in_left, S32 in_right )
{
top = in_top;
bottom = in_bottom;
left = in_left;
right = in_right;
}
void insetRect( RectI &rectRef )
{
// Inset by padding
rectRef.point.x += left;
rectRef.point.y += top;
rectRef.extent.x -= (left + right );
rectRef.extent.y -= (bottom + top );
}
void expandRect( RectI &rectRef )
{
// Inset by padding
rectRef.point.x -= left;
rectRef.point.y -= top;
rectRef.extent.x += (left + right );
rectRef.extent.y += (bottom + top );
}
};
DECLARE_STRUCT( RectSpacingI );
DefineConsoleType( TypeRectSpacingI, RectSpacingI );
/// @}
/// @name Axis-Aligned Edge Structure
/// @{
///
struct Edge
{
Point2F normal; ///< The Normal of this edge
Point2I position;///< The Position of the edge
Point2I extent; ///< The X/Y extents of the edge
F32 margin; ///< The Size of the edge
Edge(): normal(0.f,0.f),
position(0,0),
extent(0,0),
margin(1.f){};
Edge( const Point2I &inPoint, const Point2F &inNormal )
{
normal = inNormal;
margin = 2.f;
if( normal.x == 1.f || normal.x == -1.f )
{
// Vertical Edge
position.x = inPoint.x;
position.y = 0;
extent.x = 1;
extent.y = 1;
}
else if( normal.y == 1.f || normal.y == -1.f )
{
// Horizontal Edge
position.y = inPoint.y;
position.x = 0;
extent.x = 1;
extent.y = 1;
}
else
AssertFatal(false,"Edge point constructor cannot construct an Edge without an axis-aligned normal.");
}
// Copy Constructor
Edge( const Edge &inEdge )
{
normal = inEdge.normal;
position = inEdge.position;
extent = inEdge.extent;
margin = inEdge.margin;
}
// RectI cast operator overload
operator const RectI() const
{
if( normal.x == 1.f || normal.x == -1.f )
{
// Vertical Edge
RectI retRect = RectI( position.x, position.y, 1, position.y + extent.y );
// Expand Rect by Margin along the X Axis
retRect.inset(-margin,0);
return retRect;
}
else if( normal.y == 1.f || normal.y == -1.f )
{
// Horizontal Edge
RectI retRect = RectI( position.x, position.y , position.x + extent.x, 1 );
// Expand Rect by Margin along the Y Axis
retRect.inset(0,-margin);
return retRect;
}
// CodeReview this code only deals with axis-aligned edges [6/8/2007 justind]
AssertFatal(false,"Edge cast operator cannot construct a Rect from an Edge that is not axis-aligned.");
return RectI( 0,0,0,0 );
}
inline bool hit( const Edge &inEdge ) const
{
const RectI thisRect = *this;
const RectI thatRect = inEdge;
return thisRect.overlaps( thatRect );
}
};
/// @}
struct EdgeRectI
{
Edge left;
Edge top;
Edge bottom;
Edge right;
EdgeRectI(){ }
EdgeRectI( const RectI &inRect, F32 inMargin )
{
// Left Edge
left.normal = Point2F( -1.f, 0.f );
left.position.x= inRect.point.x;
left.position.y= 0;
left.extent = Point2I(inRect.point.y, inRect.point.y + inRect.extent.y);
left.margin = inMargin;
// Right Edge
right.normal = Point2F( 1.f, 0.f );
right.position.x = inRect.point.x + inRect.extent.x;
right.position.y = 0;
right.extent = Point2I(inRect.point.y, inRect.point.y + inRect.extent.y);
right.margin = inMargin;
// Top Edge
top.normal = Point2F( 0.f, 1.f );
top.position.y = inRect.point.y;
top.position.x = 0;
top.extent = Point2I(inRect.point.x + inRect.extent.x, inRect.point.x);
top.margin = inMargin;
// Bottom Edge
bottom.normal = Point2F( 0.f, -1.f );
bottom.position.y= inRect.point.y + inRect.extent.y;
bottom.position.x=0;
bottom.extent = Point2I(inRect.point.x + inRect.extent.x, inRect.point.x);
bottom.margin = inMargin;
}
// Copy constructor
EdgeRectI( const EdgeRectI &inEdgeRect )
{
left = inEdgeRect.left;
right = inEdgeRect.right;
top = inEdgeRect.top;
bottom = inEdgeRect.bottom;
}
};
/// Represents the Sizing Options for a GuiControl
struct ControlSizing
{
ControlSizing()
{
mDocking = Docking::dockInvalid;
mPadding.setAll( 0 );
mInternalPadding.setAll( 0 );
// Default anchors to full top/left
mAnchorBottom = false;
mAnchorLeft = true;
mAnchorTop = true;
mAnchorRight = false;
};
S32 mDocking; ///< Docking Flag
RectSpacingI mPadding; ///< Padding for each side of the control to have as spacing between other controls
/// For example 1,1,1,1 would mean one pixel at least of spacing between this control and the
/// one next to it.
RectSpacingI mInternalPadding; ///< Interior Spacing of the control
/// @name Anchoring
/// @{
/// @brief Anchors are applied to @b ONLY controls that are children of any derivative of a
/// GuiContainer control. Anchors are applied when a parent is resized and a child
/// element should be resized to accommodate the new parent extent
///
/// Anchors are specified as true or false and control whether a certain edge of a control
/// will be locked to a certain edge of a parent, when the parent resizes. Anchors are specified
/// as a Mask and therefore you may lock any number of edges to a parent container and when the parent
/// is resized, any locked edges on a control will remain the same distance from the parent edge it
/// is locked to, after the resize happens.
///
bool mAnchorTop; ///< Anchor to the Top edge of the parent when created
bool mAnchorBottom; ///< Anchor to the Bottom edge of the parent when created
bool mAnchorLeft; ///< Anchor to the Left edge of the parent when created
bool mAnchorRight; ///< Anchor to the Right edge of the parent when created
/// @}
};
class GuiCursor : public SimObject
{
private:
typedef SimObject Parent;
StringTableEntry mBitmapName;
Point2I mHotSpot;
Point2F mRenderOffset;
Point2I mExtent;
GFXTexHandle mTextureObject;
public:
Point2I getHotSpot() { return mHotSpot; }
Point2I getExtent() { return mExtent; }
DECLARE_CONOBJECT(GuiCursor);
GuiCursor(void);
~GuiCursor(void);
static void initPersistFields();
bool onAdd(void);
void onRemove();
void render(const Point2I &pos);
};
/// A GuiControlProfile is used by every GuiObject and is akin to a
/// datablock. It is used to control information that does not change
/// or is unlikely to change during execution of a program. It is also
/// a level of abstraction between script and GUI control so that you can
/// use the same control, say a button, and have it look completly different
/// just with a different profile.
class GuiControlProfile : public SimObject
{
private:
typedef SimObject Parent;
public:
static StringTableEntry sFontCacheDirectory; ///< Directory where Torque will store font *.uft files.
U32 mUseCount; ///< Total number of controls currently referencing this profile.
U32 mLoadCount; ///< Number of controls in woken state using this profile; resources for the profile are loaded when this is >0.
bool mTabable; ///< True if this object is accessable from using the tab key
bool mCanKeyFocus; ///< True if the object can be given keyboard focus (in other words, made a first responder @see GuiControl)
bool mModal; ///< True if this is a Modeless dialog meaning it will pass input through instead of taking it all
bool mOpaque; ///< True if this object is not translucent, and should draw a fill
ColorI mFillColor; ///< Fill color, this is used to fill the bounds of the control if it is opaque
ColorI mFillColorHL; ///< This is used instead of mFillColor if the object is highlighted
ColorI mFillColorNA; ///< This is used instead of mFillColor if the object is not active or disabled
ColorI mFillColorSEL; ///< This is used instead of mFillColor if the object is selected
S32 mBorder; ///< For most controls, if mBorder is > 0 a border will be drawn, some controls use this to draw different types of borders however @see guiDefaultControlRender.cc
S32 mBorderThickness; ///< Border thickness
ColorI mBorderColor; ///< Border color, used to draw a border around the bounds if border is enabled
ColorI mBorderColorHL; ///< Used instead of mBorderColor when the object is highlighted
ColorI mBorderColorNA; ///< Used instead of mBorderColor when the object is not active or disabled
ColorI mBevelColorHL; ///< Used for the high-light part of the bevel
ColorI mBevelColorLL; ///< Used for the low-light part of the bevel
// font members
StringTableEntry mFontType; ///< Font face name for the control
S32 mFontSize; ///< Font size for the control
enum {
BaseColor = 0,
ColorHL,
ColorNA,
ColorSEL,
ColorUser0,
ColorUser1,
ColorUser2,
ColorUser3,
ColorUser4,
ColorUser5,
};
ColorI mFontColors[10]; ///< Array of font colors used for drawText with escape characters for changing color mid-string
ColorI& mFontColor; ///< Main font color
ColorI& mFontColorHL; ///< Highlighted font color
ColorI& mFontColorNA; ///< Font color when object is not active/disabled
ColorI& mFontColorSEL; ///< Font color when object/text is selected
FontCharset mFontCharset; ///< Font character set
Resource<GFont> mFont; ///< Font resource
enum AlignmentType
{
LeftJustify,
RightJustify,
CenterJustify,
TopJustify,
BottomJustify
};
AlignmentType mAlignment; ///< Horizontal text alignment
bool mAutoSizeWidth; ///< Auto-size the width-bounds of the control to fit it's contents
bool mAutoSizeHeight; ///< Auto-size the height-bounds of the control to fit it's contents
bool mReturnTab; ///< Used in GuiTextEditCtrl to specify if a tab-event should be simulated when return is pressed.
bool mNumbersOnly; ///< For text controls, true if this should only accept numerical data
bool mMouseOverSelected; ///< True if this object should be "selected" while the mouse is over it
ColorI mCursorColor; ///< Color for the blinking cursor in text fields (for example)
Point2I mTextOffset; ///< Text offset for the control
// bitmap members
StringTableEntry mBitmapName; ///< Bitmap file name for the bitmap of the control
bool mUseBitmapArray; ///< Flag to use the bitmap array or to fallback to non-array rendering
GFXTexHandle mTextureObject;
Vector<RectI> mBitmapArrayRects; ///< Used for controls which use an array of bitmaps such as checkboxes
// sound members
SimObjectPtr< SFXTrack > mSoundButtonDown; ///< Sound played when the object is "down" ie a button is pushed
SimObjectPtr< SFXTrack > mSoundButtonOver; ///< Sound played when the mouse is over the object
StringTableEntry mChildrenProfileName; ///< The name of the profile to use for the children controls
/// Returns our children profile (and finds the profile if it hasn't been set yet)
GuiControlProfile* getChildrenProfile();
/// Category name for editing in the Gui Editor.
String mCategory;
/// Sets the children profile for this profile
///
/// @see GuiControlProfile
/// @param prof Tooltip profile to apply
void setChildrenProfile(GuiControlProfile *prof);
protected:
GuiControlProfile* mChildrenProfile; ///< Profile used with children controls (such as the scroll bar on a popup menu) when defined.
static bool protectedSetBitmap( void *object, const char *index, const char *data );
static bool protectedSetSoundButtonDown( void* object, const char* index, const char* data );
static bool protectedSetSoundButtonOver( void* object, const char* index, const char* data );
static const char* protectedGetSoundButtonDown( void* object, const char* data );
static const char* protectedGetSoundButtonOver( void* object, const char* data );
public:
DECLARE_CONOBJECT(GuiControlProfile);
GuiControlProfile();
~GuiControlProfile();
static void initPersistFields();
bool onAdd();
void onStaticModified(const char* slotName, const char* newValue = NULL );
/// Called when mProfileForChildren is deleted
virtual void onDeleteNotify(SimObject *object);
/// This method creates an array of bitmaps from one single bitmap with
/// separator color. The separator color is whatever color is in pixel 0,0
/// of the bitmap. For an example see darkWindow.png and some of the other
/// UI textures. It returns the number of bitmaps in the array it created
/// It also stores the sizes in the mBitmapArrayRects vector.
S32 constructBitmapArray();
/// This method returns the ith bitmap array rect, first ensuring that i is a
/// valid index into mBitmapArrayRects. If the vector is empty, we call
/// constructBitmapArray() automatically. If it is still empty, we return a
/// zeroed RectI.
RectI getBitmapArrayRect(U32 i);
///
bool isInUse() const { return ( mUseCount != 0 ); }
void incUseCount() { mUseCount ++; }
void decUseCount() { if( mUseCount > 0 ) mUseCount --; }
void incLoadCount();
void decLoadCount();
bool loadFont();
void setBitmapHandle(GFXTexHandle handle);
};
typedef GuiControlProfile::AlignmentType GuiAlignmentType;
DefineEnumType( GuiAlignmentType );
typedef FontCharset GuiFontCharset;
DefineEnumType( GuiFontCharset );
GFX_DeclareTextureProfile(GFXGuiCursorProfile);
GFX_DeclareTextureProfile(GFXDefaultGUIProfile);
#endif //_GUITYPES_H