//----------------------------------------------------------------------------- // 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(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); } }