guiArrayCtrl.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "console/console.h"
  23. #include "graphics/dgl.h"
  24. #include "platform/event.h"
  25. #include "gui/containers/guiScrollCtrl.h"
  26. #include "gui/guiArrayCtrl.h"
  27. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  28. GuiArrayCtrl::GuiArrayCtrl()
  29. {
  30. mActive = true;
  31. mCellSize.set(80, 30);
  32. mSize = Point2I(5, 30);
  33. mSelectedCell.set(-1, -1);
  34. mMouseOverCell.set(-1, -1);
  35. }
  36. bool GuiArrayCtrl::onWake()
  37. {
  38. if (! Parent::onWake())
  39. return false;
  40. //get the font
  41. mFont = mProfile->getFont(mFontSizeAdjust);
  42. return true;
  43. }
  44. void GuiArrayCtrl::onSleep()
  45. {
  46. Parent::onSleep();
  47. mFont = NULL;
  48. }
  49. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  50. void GuiArrayCtrl::setSize(Point2I newSize)
  51. {
  52. mSize = newSize;
  53. Point2I newExtent(newSize.x * mCellSize.x, newSize.y * mCellSize.y);
  54. resize(mBounds.point, newExtent);
  55. }
  56. void GuiArrayCtrl::getScrollDimensions(S32 &cell_size, S32 &num_cells)
  57. {
  58. cell_size = mCellSize.y;
  59. num_cells = mSize.y;
  60. }
  61. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  62. bool GuiArrayCtrl::cellSelected(Point2I cell)
  63. {
  64. if (cell.x < 0 || cell.x >= mSize.x || cell.y < 0 || cell.y >= mSize.y)
  65. {
  66. mSelectedCell = Point2I(-1,-1);
  67. return false;
  68. }
  69. mSelectedCell = cell;
  70. scrollSelectionVisible();
  71. onCellSelected(cell);
  72. setUpdate();
  73. return true;
  74. }
  75. void GuiArrayCtrl::onCellSelected(Point2I cell)
  76. {
  77. Con::executef(this, 3, "onSelect", Con::getFloatArg(cell.x), Con::getFloatArg(cell.y));
  78. //call the console function
  79. execConsoleCallback();
  80. }
  81. // Called when a cell is highlighted
  82. void GuiArrayCtrl::onCellHighlighted(Point2I cell)
  83. {
  84. // Do nothing
  85. }
  86. void GuiArrayCtrl::setSelectedCell(Point2I cell)
  87. {
  88. cellSelected(cell);
  89. }
  90. Point2I GuiArrayCtrl::getSelectedCell()
  91. {
  92. return mSelectedCell;
  93. }
  94. void GuiArrayCtrl::scrollSelectionVisible()
  95. {
  96. scrollCellVisible(mSelectedCell);
  97. }
  98. void GuiArrayCtrl::scrollCellVisible(Point2I cell)
  99. {
  100. //make sure we have a parent
  101. //make sure we have a valid cell selected
  102. GuiScrollCtrl *parent = dynamic_cast<GuiScrollCtrl*>(getParent());
  103. if(!parent || cell.x < 0 || cell.y < 0)
  104. return;
  105. RectI cellBounds(cell.x * mCellSize.x, cell.y * mCellSize.y, mCellSize.x, mCellSize.y);
  106. parent->scrollRectVisible(cellBounds);
  107. }
  108. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  109. void GuiArrayCtrl::onRender(Point2I offset, const RectI &updateRect)
  110. {
  111. //make sure we have a parent
  112. GuiControl *parent = getParent();
  113. if (! parent)
  114. return;
  115. S32 i, j;
  116. RectI headerClip;
  117. RectI clipRect = dglGetClipRect();
  118. Point2I parentOffset = parent->localToGlobalCoord(Point2I(0, 0));
  119. //save the original for clipping the row headers
  120. RectI origClipRect = clipRect;
  121. for (j = 0; j < mSize.y; j++)
  122. {
  123. //skip until we get to a visible row
  124. if ((j + 1) * mCellSize.y + offset.y < updateRect.point.y)
  125. continue;
  126. //break once we've reached the last visible row
  127. if(j * mCellSize.y + offset.y >= updateRect.point.y + updateRect.extent.y)
  128. break;
  129. //render the cells for the row
  130. for (i = 0; i < mSize.x; i++)
  131. {
  132. //skip past columns off the left edge
  133. if ((i + 1) * mCellSize.x + offset.x < updateRect.point.x)
  134. continue;
  135. //break once past the last visible column
  136. if (i * mCellSize.x + offset.x >= updateRect.point.x + updateRect.extent.x)
  137. break;
  138. S32 cellx = offset.x + i * mCellSize.x;
  139. S32 celly = offset.y + j * mCellSize.y;
  140. RectI cellClip(cellx, celly, mCellSize.x, mCellSize.y);
  141. //make sure the cell is within the update region
  142. if (cellClip.intersect(clipRect))
  143. {
  144. //set the clip rect
  145. dglSetClipRect(cellClip);
  146. //render the cell
  147. onRenderCell(Point2I(cellx, celly), Point2I(i, j),
  148. i == mSelectedCell.x && j == mSelectedCell.y,
  149. i == mMouseOverCell.x && j == mMouseOverCell.y);
  150. }
  151. }
  152. }
  153. }
  154. void GuiArrayCtrl::onTouchDown(const GuiEvent &event)
  155. {
  156. if ( !mActive || !mAwake || !mVisible )
  157. return;
  158. //let the guiControl method take care of the rest
  159. Parent::onTouchDown(event);
  160. Point2I pt = globalToLocalCoord(event.mousePoint);
  161. Point2I cell(
  162. (pt.x < 0 ? -1 : pt.x / mCellSize.x),
  163. (pt.y < 0 ? -1 : pt.y / mCellSize.y)
  164. );
  165. if (cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
  166. {
  167. //store the previously selected cell
  168. Point2I prevSelected = mSelectedCell;
  169. //select the new cell
  170. cellSelected(Point2I(cell.x, cell.y));
  171. //if we double clicked on the *same* cell, evaluate the altConsole Command
  172. if ( ( event.mouseClickCount > 1 ) && ( prevSelected == mSelectedCell ) && mAltConsoleCommand[0] )
  173. Con::evaluate( mAltConsoleCommand, false );
  174. }
  175. }
  176. void GuiArrayCtrl::onTouchEnter(const GuiEvent &event)
  177. {
  178. Point2I pt = globalToLocalCoord(event.mousePoint);
  179. //get the cell
  180. Point2I cell((pt.x < 0 ? -1 : pt.x / mCellSize.x), (pt.y < 0 ? -1 : pt.y / mCellSize.y));
  181. if (cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
  182. {
  183. mMouseOverCell = cell;
  184. setUpdateRegion(Point2I(cell.x * mCellSize.x, cell.y * mCellSize.y), mCellSize );
  185. onCellHighlighted(mMouseOverCell);
  186. }
  187. }
  188. void GuiArrayCtrl::onTouchLeave(const GuiEvent & /*event*/)
  189. {
  190. setUpdateRegion(Point2I(mMouseOverCell.x * mCellSize.x, mMouseOverCell.y * mCellSize.y), mCellSize);
  191. mMouseOverCell.set(-1,-1);
  192. onCellHighlighted(mMouseOverCell);
  193. }
  194. void GuiArrayCtrl::onTouchDragged(const GuiEvent &event)
  195. {
  196. // for the array control, the behaviour of onMouseDragged is the same
  197. // as on mouse moved - basically just recalc the currend mouse over cell
  198. // and set the update regions if necessary
  199. GuiArrayCtrl::onTouchMove(event);
  200. }
  201. void GuiArrayCtrl::onTouchMove(const GuiEvent &event)
  202. {
  203. Point2I pt = globalToLocalCoord(event.mousePoint);
  204. Point2I cell((pt.x < 0 ? -1 : pt.x / mCellSize.x), (pt.y < 0 ? -1 : pt.y / mCellSize.y));
  205. if (cell.x != mMouseOverCell.x || cell.y != mMouseOverCell.y)
  206. {
  207. if (mMouseOverCell.x != -1)
  208. {
  209. setUpdateRegion(Point2I(mMouseOverCell.x * mCellSize.x, mMouseOverCell.y * mCellSize.y), mCellSize);
  210. }
  211. if (cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
  212. {
  213. setUpdateRegion(Point2I(cell.x * mCellSize.x, cell.y * mCellSize.y), mCellSize);
  214. mMouseOverCell = cell;
  215. }
  216. else
  217. mMouseOverCell.set(-1,-1);
  218. }
  219. onCellHighlighted(mMouseOverCell);
  220. }
  221. bool GuiArrayCtrl::onKeyDown(const GuiEvent &event)
  222. {
  223. //if this control is a dead end, kill the event
  224. if ((! mVisible) || (! mActive) || (! mAwake)) return true;
  225. //get the parent
  226. S32 pageSize = 1;
  227. GuiControl *parent = getParent();
  228. if (parent && mCellSize.y > 0)
  229. {
  230. pageSize = getMax(1, (parent->mBounds.extent.y / mCellSize.y) - 1);
  231. }
  232. Point2I delta(0,0);
  233. switch (event.keyCode)
  234. {
  235. case KEY_LEFT:
  236. delta.set(-1, 0);
  237. break;
  238. case KEY_RIGHT:
  239. delta.set(1, 0);
  240. break;
  241. case KEY_UP:
  242. delta.set(0, -1);
  243. break;
  244. case KEY_DOWN:
  245. delta.set(0, 1);
  246. break;
  247. case KEY_PAGE_UP:
  248. delta.set(0, -pageSize);
  249. break;
  250. case KEY_PAGE_DOWN:
  251. delta.set(0, pageSize);
  252. break;
  253. case KEY_HOME:
  254. cellSelected( Point2I( 0, 0 ) );
  255. return( true );
  256. case KEY_END:
  257. cellSelected( Point2I( 0, mSize.y - 1 ) );
  258. return( true );
  259. default:
  260. return Parent::onKeyDown(event);
  261. }
  262. if (mSize.x < 1 || mSize.y < 1)
  263. return true;
  264. //select the first cell if no previous cell was selected
  265. if (mSelectedCell.x == -1 || mSelectedCell.y == -1)
  266. {
  267. cellSelected(Point2I(0,0));
  268. return true;
  269. }
  270. //select the cell
  271. Point2I cell = mSelectedCell;
  272. cell.x = getMax(0, getMin(mSize.x - 1, cell.x + delta.x));
  273. cell.y = getMax(0, getMin(mSize.y - 1, cell.y + delta.y));
  274. cellSelected(cell);
  275. return true;
  276. }
  277. void GuiArrayCtrl::onRightMouseDown(const GuiEvent &event)
  278. {
  279. if ( !mActive || !mAwake || !mVisible )
  280. return;
  281. Parent::onRightMouseDown( event );
  282. Point2I pt = globalToLocalCoord( event.mousePoint );
  283. Point2I cell((pt.x < 0 ? -1 : pt.x / mCellSize.x), (pt.y < 0 ? -1 : pt.y / mCellSize.y));
  284. if (cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
  285. {
  286. char buf[32];
  287. dSprintf( buf, sizeof( buf ), "%d %d", event.mousePoint.x, event.mousePoint.y );
  288. // Pass it to the console:
  289. Con::executef(this, 4, "onRightMouseDown", Con::getIntArg(cell.x), Con::getIntArg(cell.y), buf);
  290. }
  291. }