Torque3D Documentation / _generateds / guiArrayCtrl.cpp

guiArrayCtrl.cpp

Engine/source/gui/core/guiArrayCtrl.cpp

More...

Public Functions

ConsoleDocClass(GuiArrayCtrl , "@brief Abstract base class <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> controls that store and display multiple elements in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">view.\n\n</a>" "You cannot actually instantiate this class. Instead you can use its <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">childre:\n\n</a>" "- <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiConsole\n</a>" "- <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTextListCtrl\n</a>" "- <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTreeViewCtrl\n</a>" "- <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">DbgFileView\n</a>" "- <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">CreatorTree\n</a>" "This base class is primarily used by other internal classes or those dedicated <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">editors.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiCore\n</a>" "@internal" )
IMPLEMENT_CALLBACK(GuiArrayCtrl , onCellHighlighted , void , (const Point2I &cell) , (cell) , "Call when <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> cell in the array is highlighted (moused over).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@param @cell Coordinates of the cell" )
IMPLEMENT_CALLBACK(GuiArrayCtrl , onCellSelected , void , (const Point2I &cell) , (cell) , "Call when <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> cell in the array is selected (clicked).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@param @cell Coordinates of the cell" )

Detailed Description

Public Functions

ConsoleDocClass(GuiArrayCtrl , "@brief Abstract base class <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> controls that store and display multiple elements in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">view.\n\n</a>" "You cannot actually instantiate this class. Instead you can use its <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">childre:\n\n</a>" "- <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiConsole\n</a>" "- <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTextListCtrl\n</a>" "- <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTreeViewCtrl\n</a>" "- <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">DbgFileView\n</a>" "- <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">CreatorTree\n</a>" "This base class is primarily used by other internal classes or those dedicated <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">editors.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiCore\n</a>" "@internal" )

IMPLEMENT_CALLBACK(GuiArrayCtrl , onCellHighlighted , void , (const Point2I &cell) , (cell) , "Call when <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> cell in the array is highlighted (moused over).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@param @cell Coordinates of the cell" )

IMPLEMENT_CALLBACK(GuiArrayCtrl , onCellSelected , void , (const Point2I &cell) , (cell) , "Call when <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> cell in the array is selected (clicked).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@param @cell Coordinates of the cell" )

IMPLEMENT_CONOBJECT(GuiArrayCtrl )

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "gui/core/guiArrayCtrl.h"
 26
 27#include "console/console.h"
 28#include "console/engineAPI.h"
 29#include "gui/containers/guiScrollCtrl.h"
 30#include "gfx/gfxDrawUtil.h"
 31#include "gui/core/guiDefaultControlRender.h"
 32
 33
 34IMPLEMENT_CONOBJECT(GuiArrayCtrl);
 35
 36ConsoleDocClass( GuiArrayCtrl,
 37   "@brief Abstract base class for controls that store and display multiple elements in a single view.\n\n"
 38
 39   "You cannot actually instantiate this class. Instead you can use its childre:\n\n"
 40
 41   "- GuiConsole\n"
 42   "- GuiTextListCtrl\n"
 43   "- GuiTreeViewCtrl\n"
 44   "- DbgFileView\n"
 45   "- CreatorTree\n"
 46
 47   "This base class is primarily used by other internal classes or those dedicated to editors.\n\n"
 48
 49   "@ingroup GuiCore\n"
 50
 51   "@internal"
 52);
 53
 54IMPLEMENT_CALLBACK( GuiArrayCtrl, onCellSelected, void, ( const Point2I& cell ), ( cell ),
 55   "Call when a cell in the array is selected (clicked).\n\n"
 56   "@param @cell Coordinates of the cell"
 57);
 58IMPLEMENT_CALLBACK( GuiArrayCtrl, onCellHighlighted, void, ( const Point2I& cell ), ( cell ),
 59   "Call when a cell in the array is highlighted (moused over).\n\n"
 60   "@param @cell Coordinates of the cell"
 61);
 62
 63//-----------------------------------------------------------------------------
 64
 65GuiArrayCtrl::GuiArrayCtrl()
 66{
 67   mActive = true;
 68
 69   mCellSize.set(80, 30);
 70   mSize = Point2I(5, 30);
 71   mSelectedCell.set(-1, -1);
 72   mMouseOverCell.set(-1, -1);
 73   mHeaderDim.set(0, 0);
 74   mIsContainer = true;
 75}
 76
 77//-----------------------------------------------------------------------------
 78
 79bool GuiArrayCtrl::onWake()
 80{
 81   if (! Parent::onWake())
 82      return false;
 83
 84   //get the font
 85   mFont = mProfile->mFont;
 86
 87   return true;
 88}
 89
 90//-----------------------------------------------------------------------------
 91
 92void GuiArrayCtrl::onSleep()
 93{
 94   Parent::onSleep();
 95   mFont = NULL;
 96}
 97
 98//-----------------------------------------------------------------------------
 99
100void GuiArrayCtrl::setSize(Point2I newSize)
101{
102   mSize = newSize;
103   Point2I newExtent(newSize.x * mCellSize.x + mHeaderDim.x, newSize.y * mCellSize.y + mHeaderDim.y);
104
105   setExtent(newExtent);
106}
107
108//-----------------------------------------------------------------------------
109
110void GuiArrayCtrl::getScrollDimensions(S32 &cell_size, S32 &num_cells)
111{
112   cell_size = mCellSize.y;
113   num_cells = mSize.y;
114}
115
116//-----------------------------------------------------------------------------
117
118bool GuiArrayCtrl::cellSelected(Point2I cell)
119{
120   if (cell.x < 0 || cell.x >= mSize.x || cell.y < 0 || cell.y >= mSize.y)
121   {
122      mSelectedCell = Point2I(-1,-1);
123      return false;
124   }
125
126   mSelectedCell = cell;
127   scrollSelectionVisible();
128   onCellSelected(cell);
129   setUpdate();
130   return true;
131}
132
133//-----------------------------------------------------------------------------
134
135void GuiArrayCtrl::onCellSelected(Point2I cell)
136{
137   // [rene, 21-Jan-11 ] clashes with callbacks defined in derived classes
138   Con::executef(this, "onSelect", Con::getFloatArg(cell.x), Con::getFloatArg(cell.y));
139
140   onCellSelected_callback( cell );
141
142   //call the console function
143   execConsoleCallback();
144}
145
146//-----------------------------------------------------------------------------
147
148void GuiArrayCtrl::onCellHighlighted(Point2I cell)
149{
150   onCellHighlighted_callback( cell );
151}
152
153//-----------------------------------------------------------------------------
154
155void GuiArrayCtrl::setSelectedCell(Point2I cell)
156{
157   cellSelected(cell);
158}
159
160//-----------------------------------------------------------------------------
161
162Point2I GuiArrayCtrl::getSelectedCell()
163{
164   return mSelectedCell;
165}
166
167//-----------------------------------------------------------------------------
168
169void GuiArrayCtrl::scrollSelectionVisible()
170{
171   scrollCellVisible(mSelectedCell);
172}
173
174//-----------------------------------------------------------------------------
175
176void GuiArrayCtrl::scrollCellVisible(Point2I cell)
177{
178   //make sure we have a parent
179   //make sure we have a valid cell selected
180   GuiScrollCtrl *parent = dynamic_cast<GuiScrollCtrl*>(getParent());
181   if(!parent || cell.x < 0 || cell.y < 0)
182      return;
183
184   RectI cellBounds(cell.x * mCellSize.x, cell.y * mCellSize.y, mCellSize.x, mCellSize.y);
185   parent->scrollRectVisible(cellBounds);
186}
187
188//-----------------------------------------------------------------------------
189
190void GuiArrayCtrl::onRenderColumnHeaders(Point2I offset, Point2I parentOffset, Point2I headerDim)
191{
192   if (mProfile->mBorder)
193   {
194      RectI cellR(offset.x + headerDim.x, parentOffset.y, getWidth() - headerDim.x, headerDim.y);
195      GFX->getDrawUtil()->drawRectFill(cellR, mProfile->mBorderColor);
196   }
197}
198
199//-----------------------------------------------------------------------------
200
201void GuiArrayCtrl::onRenderRowHeader(Point2I offset, Point2I parentOffset, Point2I headerDim, Point2I cell)
202{
203   ColorI color;
204   RectI cellR;
205   if (cell.x % 2)
206      color.set(255, 0, 0, 255);
207   else
208      color.set(0, 255, 0, 255);
209
210   cellR.point.set(parentOffset.x, offset.y);
211   cellR.extent.set(headerDim.x, mCellSize.y);
212   GFX->getDrawUtil()->drawRectFill(cellR, color);
213}
214
215//-----------------------------------------------------------------------------
216
217void GuiArrayCtrl::onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver)
218{
219   ColorI color(255 * (cell.x % 2), 255 * (cell.y % 2), 255 * ((cell.x + cell.y) % 2), 255);
220   if (selected)
221   {
222      color.set(255, 0, 0, 255);
223   }
224   else if (mouseOver)
225   {
226      color.set(0, 0, 255, 255);
227   }
228
229   //draw the cell
230   RectI cellR(offset.x, offset.y, mCellSize.x, mCellSize.y);
231   GFX->getDrawUtil()->drawRectFill(cellR, color);
232}
233
234//-----------------------------------------------------------------------------
235
236void GuiArrayCtrl::onRender(Point2I offset, const RectI &updateRect)
237{
238   // The unmodified offset which was passed into this method.
239   const Point2I inOffset( offset );
240
241   //Parent::onRender( offset, updateRect );
242
243   // We render our fill, borders, and child controls ourself.
244   // This allows us to render child controls after we render cells,
245   // so child controls appear on-top, as they should.   
246
247   // Render our fill and borders.
248   // This code from GuiControl::onRender().
249   {      
250      RectI ctrlRect(offset, getExtent());
251
252      //if opaque, fill the update rect with the fill color
253      if ( mProfile->mOpaque )
254         GFX->getDrawUtil()->drawRectFill(ctrlRect, mProfile->mFillColor);
255
256      //if there's a border, draw the border
257      if ( mProfile->mBorder )
258         renderBorder(ctrlRect, mProfile);
259   }
260
261   //make sure we have a parent
262   GuiControl *parent = getParent();
263   if (! parent)
264      return;
265
266   S32 i, j;
267   RectI headerClip;
268   RectI clipRect(updateRect.point, updateRect.extent);
269
270   Point2I parentOffset = parent->localToGlobalCoord(Point2I(0, 0));
271
272   //if we have column headings
273   if (mHeaderDim.y > 0)
274   {
275      headerClip.point.x =   parentOffset.x + mHeaderDim.x;
276      headerClip.point.y =   parentOffset.y;
277      headerClip.extent.x =  clipRect.extent.x;// - headerClip.point.x; // This seems to fix some strange problems with some Gui's, bug? -pw
278      headerClip.extent.y =  mHeaderDim.y;
279
280      if (headerClip.intersect(clipRect))
281      {
282         GFX->setClipRect(headerClip);
283
284         //now render the header
285         onRenderColumnHeaders(offset, parentOffset, mHeaderDim);
286
287         clipRect.point.y += headerClip.extent.y;
288         clipRect.extent.y -= headerClip.extent.y;
289      }
290      offset.y += mHeaderDim.y;
291   }
292
293   //if we have row headings
294   if (mHeaderDim.x > 0)
295   {
296      clipRect.point.x = getMax(clipRect.point.x, parentOffset.x + mHeaderDim.x);
297      offset.x += mHeaderDim.x;
298   }
299
300   //save the original for clipping the row headers
301   RectI origClipRect = clipRect;
302
303   for (j = 0; j < mSize.y; j++)
304   {
305      //skip until we get to a visible row
306      if ((j + 1) * mCellSize.y + offset.y < updateRect.point.y)
307         continue;
308
309      //break once we've reached the last visible row
310      if(j * mCellSize.y + offset.y >= updateRect.point.y + updateRect.extent.y)
311         break;
312
313      //render the header
314      if (mHeaderDim.x > 0)
315      {
316         headerClip.point.x = parentOffset.x;
317         headerClip.extent.x = mHeaderDim.x;
318         headerClip.point.y = offset.y + j * mCellSize.y;
319         headerClip.extent.y = mCellSize.y;
320         if (headerClip.intersect(origClipRect))
321         {
322            GFX->setClipRect(headerClip);
323
324            //render the row header
325            onRenderRowHeader(Point2I(0, offset.y + j * mCellSize.y),
326                              Point2I(parentOffset.x, offset.y + j * mCellSize.y),
327                              mHeaderDim, Point2I(0, j));
328         }
329      }
330
331      //render the cells for the row
332      for (i = 0; i < mSize.x; i++)
333      {
334         //skip past columns off the left edge
335         if ((i + 1) * mCellSize.x + offset.x < updateRect.point.x)
336            continue;
337
338         //break once past the last visible column
339         if (i * mCellSize.x + offset.x >= updateRect.point.x + updateRect.extent.x)
340            break;
341
342         S32 cellx = offset.x + i * mCellSize.x;
343         S32 celly = offset.y + j * mCellSize.y;
344
345         RectI cellClip(cellx, celly, mCellSize.x, mCellSize.y);
346
347         //make sure the cell is within the update region
348         if (cellClip.intersect(clipRect))
349         {
350            //set the clip rect
351            GFX->setClipRect(cellClip);
352
353            //render the cell
354            onRenderCell(Point2I(cellx, celly), Point2I(i, j),
355               i == mSelectedCell.x && j == mSelectedCell.y,
356               i == mMouseOverCell.x && j == mMouseOverCell.y);
357         }
358      }
359   }
360
361   // Done rendering cells.
362   // Render child controls, if any, on top.
363   renderChildControls( inOffset, updateRect );
364}
365
366//-----------------------------------------------------------------------------
367
368void GuiArrayCtrl::onMouseDown( const GuiEvent &event )
369{
370   if ( !mActive || !mAwake || !mVisible )
371      return;
372}
373
374//-----------------------------------------------------------------------------
375
376void GuiArrayCtrl::onMouseUp( const GuiEvent &event )
377{
378   if ( !mActive || !mAwake || !mVisible )
379      return;
380
381   //let the guiControl method take care of the rest
382   Parent::onMouseUp(event);
383
384   Point2I pt = globalToLocalCoord(event.mousePoint);
385   pt.x -= mHeaderDim.x; pt.y -= mHeaderDim.y;
386   Point2I cell(
387         (pt.x < 0 ? -1 : pt.x / mCellSize.x), 
388         (pt.y < 0 ? -1 : pt.y / mCellSize.y)
389      );
390
391   if (cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
392   {
393      //store the previously selected cell
394      Point2I prevSelected = mSelectedCell;
395
396      //select the new cell
397      cellSelected(Point2I(cell.x, cell.y));
398
399      //if we double clicked on the *same* cell, evaluate the altConsole Command
400      if ( ( event.mouseClickCount > 1 ) && ( prevSelected == mSelectedCell ) )
401         execAltConsoleCallback();
402   }
403}
404
405//-----------------------------------------------------------------------------
406
407void GuiArrayCtrl::onMouseEnter(const GuiEvent &event)
408{
409   Point2I pt = globalToLocalCoord(event.mousePoint);
410   pt.x -= mHeaderDim.x; pt.y -= mHeaderDim.y;
411
412   //get the cell
413   Point2I cell((pt.x < 0 ? -1 : pt.x / mCellSize.x), (pt.y < 0 ? -1 : pt.y / mCellSize.y));
414   if (cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
415   {
416      mMouseOverCell = cell;
417      setUpdateRegion(Point2I(cell.x * mCellSize.x + mHeaderDim.x,
418                              cell.y * mCellSize.y + mHeaderDim.y), mCellSize );
419     onCellHighlighted(mMouseOverCell);
420   }
421}
422
423//-----------------------------------------------------------------------------
424
425void GuiArrayCtrl::onMouseLeave(const GuiEvent & /*event*/)
426{
427   setUpdateRegion(Point2I(mMouseOverCell.x * mCellSize.x + mHeaderDim.x,
428                           mMouseOverCell.y * mCellSize.y + mHeaderDim.y), mCellSize);
429   mMouseOverCell.set(-1,-1);
430   onCellHighlighted(mMouseOverCell);
431}
432
433//-----------------------------------------------------------------------------
434
435void GuiArrayCtrl::onMouseDragged(const GuiEvent &event)
436{
437   // for the array control, the behavior of onMouseDragged is the same
438   // as on mouse moved - basically just recalc the current mouse over cell
439   // and set the update regions if necessary
440   GuiArrayCtrl::onMouseMove(event);
441}
442
443//-----------------------------------------------------------------------------
444
445void GuiArrayCtrl::onMouseMove(const GuiEvent &event)
446{
447   Point2I pt = globalToLocalCoord(event.mousePoint);
448   pt.x -= mHeaderDim.x; pt.y -= mHeaderDim.y;
449   Point2I cell((pt.x < 0 ? -1 : pt.x / mCellSize.x), (pt.y < 0 ? -1 : pt.y / mCellSize.y));
450   if (cell.x != mMouseOverCell.x || cell.y != mMouseOverCell.y)
451   {
452      if (mMouseOverCell.x != -1)
453      {
454         setUpdateRegion(Point2I(mMouseOverCell.x * mCellSize.x + mHeaderDim.x,
455                           mMouseOverCell.y * mCellSize.y + mHeaderDim.y), mCellSize);
456      }
457
458      if (cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
459      {
460         setUpdateRegion(Point2I(cell.x * mCellSize.x + mHeaderDim.x,
461                           cell.y * mCellSize.y + mHeaderDim.y), mCellSize);
462         mMouseOverCell = cell;
463      }
464      else
465         mMouseOverCell.set(-1,-1);
466   }
467   onCellHighlighted(mMouseOverCell);
468}
469
470//-----------------------------------------------------------------------------
471
472bool GuiArrayCtrl::onKeyDown(const GuiEvent &event)
473{
474   //if this control is a dead end, kill the event
475   if ((! mVisible) || (! mActive) || (! mAwake)) return true;
476
477   //get the parent
478   S32 pageSize = 1;
479   GuiControl *parent = getParent();
480   if (parent && mCellSize.y > 0)
481   {
482      pageSize = getMax(1, (parent->getHeight() / mCellSize.y) - 1);
483   }
484
485   Point2I delta(0,0);
486   switch (event.keyCode)
487   {
488      case KEY_LEFT:
489         delta.set(-1, 0);
490         break;
491      case KEY_RIGHT:
492         delta.set(1, 0);
493         break;
494      case KEY_UP:
495         delta.set(0, -1);
496         break;
497      case KEY_DOWN:
498         delta.set(0, 1);
499         break;
500      case KEY_PAGE_UP:
501         delta.set(0, -pageSize);
502         break;
503      case KEY_PAGE_DOWN:
504         delta.set(0, pageSize);
505         break;
506      case KEY_HOME:
507         cellSelected( Point2I( 0, 0 ) );
508         return( true );
509      case KEY_END:
510         cellSelected( Point2I( 0, mSize.y - 1 ) );
511         return( true );
512      default:
513         return Parent::onKeyDown(event);
514   }
515   if (mSize.x < 1 || mSize.y < 1)
516      return true;
517
518   //select the first cell if no previous cell was selected
519   if (mSelectedCell.x == -1 || mSelectedCell.y == -1)
520   {
521      cellSelected(Point2I(0,0));
522      return true;
523   }
524
525   //select the cell
526   Point2I cell = mSelectedCell;
527   cell.x = getMax(0, getMin(mSize.x - 1, cell.x + delta.x));
528   cell.y = getMax(0, getMin(mSize.y - 1, cell.y + delta.y));
529   cellSelected(cell);
530
531   return true;
532}
533
534//-----------------------------------------------------------------------------
535
536void GuiArrayCtrl::onRightMouseDown(const GuiEvent &event)
537{
538   if ( !mActive || !mAwake || !mVisible )
539      return;
540
541   Parent::onRightMouseDown( event );
542
543   Point2I cell;
544   if( _findHitCell( event.mousePoint, cell ) )
545   {
546      char buf[32];
547      dSprintf( buf, sizeof( buf ), "%d %d", event.mousePoint.x, event.mousePoint.y );
548
549      // [rene, 21-Jan-11 ] clashes with callbacks defined in derived classes
550
551      // Pass it to the console:
552      Con::executef(this, "onRightMouseDown", Con::getIntArg(cell.x), Con::getIntArg(cell.y), buf);
553   }
554}
555
556//-----------------------------------------------------------------------------
557
558bool GuiArrayCtrl::_findHitCell( const Point2I& pos, Point2I& cellOut )
559{
560   Point2I pt = globalToLocalCoord( pos );
561   pt.x -= mHeaderDim.x; pt.y -= mHeaderDim.y;
562   Point2I cell( ( pt.x < 0 ? -1 : pt.x / mCellSize.x ), ( pt.y < 0 ? -1 : pt.y / mCellSize.y ) );
563   if( cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y )
564   {
565      cellOut = cell;
566      return true;
567   }
568
569   return false;
570}
571