123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- //-----------------------------------------------------------------------------
- // 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"
- 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);
- 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);
- 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<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->mBorderDefault && mProfile->mBorderDefault->mBorder > 0)
- {
- RectI cellR(offset.x + headerDim.x, parentOffset.y, mBounds.extent.x - headerDim.x, headerDim.y);
- dglDrawRectFill(cellR, mProfile->mBorderDefault->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::onTouchDown(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);
- }
- }
|