//----------------------------------------------------------------------------- // Copyright (c) 2013 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 "console/console.h" #include "graphics/dgl.h" #include "platform/event.h" #include "gui/containers/guiScrollCtrl.h" #include "gui/guiArrayCtrl.h" // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- // GuiArrayCtrl::GuiArrayCtrl() { mActive = true; mCellSize.set(80, 30); mSize = Point2I(5, 30); mSelectedCell.set(-1, -1); mMouseOverCell.set(-1, -1); } bool GuiArrayCtrl::onWake() { if (! Parent::onWake()) return false; //get the font mFont = mProfile->getFont(mFontSizeAdjust); return true; } void GuiArrayCtrl::onSleep() { Parent::onSleep(); mFont = NULL; } // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- // void GuiArrayCtrl::setSize(Point2I newSize) { mSize = newSize; Point2I newExtent(newSize.x * mCellSize.x, newSize.y * mCellSize.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 execConsoleCallback(); } // 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::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 = dglGetClipRect(); Point2I parentOffset = parent->localToGlobalCoord(Point2I(0, 0)); //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 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::onTouchDown(const GuiEvent &event) { if ( !mActive || !mAwake || !mVisible ) return; //let the guiControl method take care of the rest Parent::onTouchDown(event); Point2I pt = globalToLocalCoord(event.mousePoint); 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::onTouchEnter(const GuiEvent &event) { Point2I pt = globalToLocalCoord(event.mousePoint); //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, cell.y * mCellSize.y), mCellSize ); onCellHighlighted(mMouseOverCell); } } void GuiArrayCtrl::onTouchLeave(const GuiEvent & /*event*/) { setUpdateRegion(Point2I(mMouseOverCell.x * mCellSize.x, mMouseOverCell.y * mCellSize.y), mCellSize); mMouseOverCell.set(-1,-1); onCellHighlighted(mMouseOverCell); } void GuiArrayCtrl::onTouchDragged(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::onTouchMove(event); } void GuiArrayCtrl::onTouchMove(const GuiEvent &event) { Point2I pt = globalToLocalCoord(event.mousePoint); 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, mMouseOverCell.y * mCellSize.y), mCellSize); } if (cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y) { setUpdateRegion(Point2I(cell.x * mCellSize.x, cell.y * mCellSize.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 ); 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); } }