tge/engine/gui/core/guiArrayCtrl.cc
2017-04-17 06:17:10 -06:00

435 lines
13 KiB
C++
Executable File

//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "dgl/dgl.h"
#include "platform/event.h"
#include "gui/containers/guiScrollCtrl.h"
#include "gui/core/guiArrayCtrl.h"
IMPLEMENT_CONOBJECT(GuiArrayCtrl);
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
GuiArrayCtrl::GuiArrayCtrl()
{
mActive = true;
mCellSize.set(80, 30);
mSize = Point2I(5, 30);
mSelectedCell.set(-1, -1);
mMouseOverCell.set(-1, -1);
mHeaderDim.set(0, 0);
}
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);
resize(mBounds.point, 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)
{
Con::executef(this, 3, "onSelect", Con::getFloatArg(cell.x), Con::getFloatArg(cell.y));
//call the console function
if (mConsoleCommand[0])
{
char buf[16];
dSprintf(buf, sizeof(buf), "%d", getId());
Con::setVariable("$ThisControl", buf);
Con::evaluate(mConsoleCommand, false);
}
}
// Called when a cell is highlighted
void GuiArrayCtrl::onCellHighlighted(Point2I cell)
{
// Do nothing
}
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, mBounds.extent.x - headerDim.x, headerDim.y);
dglDrawRectFill(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);
dglDrawRectFill(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);
dglDrawRectFill(cellR, color);
}
void GuiArrayCtrl::onRender(Point2I offset, const RectI &updateRect)
{
//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))
{
dglSetClipRect(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))
{
dglSetClipRect(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
dglSetClipRect(cellClip);
//render the cell
onRenderCell(Point2I(cellx, celly), Point2I(i, j),
i == mSelectedCell.x && j == mSelectedCell.y,
i == mMouseOverCell.x && j == mMouseOverCell.y);
}
}
}
}
void GuiArrayCtrl::onMouseDown(const GuiEvent &event)
{
if ( !mActive || !mAwake || !mVisible )
return;
//let the guiControl method take care of the rest
Parent::onMouseDown(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 ) && mAltConsoleCommand[0] )
Con::evaluate( mAltConsoleCommand, false );
}
}
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 behaviour of onMouseDragged is the same
// as on mouse moved - basically just recalc the currend 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->mBounds.extent.y / 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 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)
{
char buf[32];
dSprintf( buf, sizeof( buf ), "%d %d", event.mousePoint.x, event.mousePoint.y );
// Pass it to the console:
Con::executef(this, 4, "onRightMouseDown", Con::getIntArg(cell.x), Con::getIntArg(cell.y), buf);
}
}