guiRectHandles.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 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 "console/consoleTypes.h"
  24. #include "gfx/gfxDevice.h"
  25. #include "gfx/gfxDrawUtil.h"
  26. #include "gui/editor/guiRectHandles.h"
  27. IMPLEMENT_CONOBJECT(GuiRectHandles);
  28. ConsoleDocClass( GuiRectHandles,
  29. "@brief Draws a box with handles for the user to manipulate.\n\n"
  30. "Editor use only.\n\n"
  31. "@internal"
  32. );
  33. //--------------------------------------------------------------------------
  34. GuiRectHandles::GuiRectHandles() : GuiControl()
  35. {
  36. mHandleRect.set(0.0f, 0.0f, 1.0f, 1.0f);
  37. mHandleSize = 10;
  38. mUseCustomColor = false;
  39. mHandleColor.set(100,100,100);
  40. mHitHandle = 0;
  41. }
  42. GuiRectHandles::~GuiRectHandles()
  43. {
  44. }
  45. //--------------------------------------------------------------------------
  46. void GuiRectHandles::initPersistFields()
  47. {
  48. addField("handleRect", TypeRectF, Offset(mHandleRect, GuiRectHandles), "RectF of handle's box." );
  49. addField("handleSize", TypeS32, Offset(mHandleSize, GuiRectHandles), "Size of handles in pixels." );
  50. addField("useCustomColor", TypeBool, Offset(mUseCustomColor, GuiRectHandles), "Use given custom color for handles." );
  51. addField("handleColor", TypeColorI, Offset(mHandleColor, GuiRectHandles), "Use given custom color for handles." );
  52. Parent::initPersistFields();
  53. }
  54. //--------------------------------------------------------------------------
  55. void GuiRectHandles::onMouseUp(const GuiEvent &event)
  56. {
  57. mHitHandle = 0;
  58. }
  59. void GuiRectHandles::onMouseDown(const GuiEvent &event)
  60. {
  61. // The handles range from 0-1, so scale to fit within the
  62. // control's bounds.
  63. const Point2I& extent = getExtent();
  64. Point2I pos(extent.x*mHandleRect.point.x, extent.y*mHandleRect.point.y);
  65. Point2I size(extent.x*mHandleRect.extent.x, extent.y*mHandleRect.extent.y);
  66. RectI box(pos, size);
  67. Point2I localMousePoint = globalToLocalCoord(event.mousePoint);
  68. // Check if mouse is within handle rect
  69. if(!box.pointInRect(localMousePoint))
  70. {
  71. mHitHandle = 0;
  72. return;
  73. }
  74. Point2I normalizedMouse = localMousePoint - pos;
  75. Point2I halfSize = size / 2;
  76. S32 halfHandleSize = mHandleSize / 2;
  77. if(normalizedMouse.y < mHandleSize)
  78. {
  79. // Top handles
  80. if(normalizedMouse.x < mHandleSize)
  81. mHitHandle = 1;
  82. else if(normalizedMouse.x >= (size.x-mHandleSize))
  83. mHitHandle = 3;
  84. else if(normalizedMouse.x >= (halfSize.x-halfHandleSize) && normalizedMouse.x < (halfSize.x+halfHandleSize))
  85. mHitHandle = 2;
  86. }
  87. else if(normalizedMouse.y >= (size.y-mHandleSize))
  88. {
  89. // Bottom handles
  90. if(normalizedMouse.x < mHandleSize)
  91. mHitHandle = 7;
  92. else if(normalizedMouse.x >= (size.x-mHandleSize))
  93. mHitHandle = 5;
  94. else if(normalizedMouse.x >= (halfSize.x-halfHandleSize) && normalizedMouse.x < (halfSize.x+halfHandleSize))
  95. mHitHandle = 6;
  96. }
  97. else if(normalizedMouse.y >= (halfSize.y-halfHandleSize) && normalizedMouse.y < (halfSize.y+halfHandleSize))
  98. {
  99. // Middle handles
  100. if(normalizedMouse.x < mHandleSize)
  101. mHitHandle = 8;
  102. else if(normalizedMouse.x >= (size.x-mHandleSize))
  103. mHitHandle = 4;
  104. else if(normalizedMouse.x >= (halfSize.x-halfHandleSize) && normalizedMouse.x < (halfSize.x+halfHandleSize))
  105. mHitHandle = 9;
  106. }
  107. mHitPoint = localMousePoint;
  108. }
  109. void GuiRectHandles::onMouseDragged(const GuiEvent &event)
  110. {
  111. if(mHitHandle == 0)
  112. return;
  113. // The handles range from 0-1, so scale to fit within the
  114. // control's bounds.
  115. const Point2I& extent = getExtent();
  116. Point2I localMousePoint = globalToLocalCoord(event.mousePoint);
  117. Point2I diffI = localMousePoint - mHitPoint;
  118. Point2F diffF(diffI.x/F32(extent.x), diffI.y/F32(extent.y));
  119. RectF box(mHandleRect);
  120. bool postMoveExtentX = false;
  121. bool postMoveExtentY = false;
  122. bool keepExtent = false;
  123. switch(mHitHandle)
  124. {
  125. case 1:
  126. {
  127. // Top left
  128. box.point += diffF;
  129. postMoveExtentX = true;
  130. postMoveExtentY = true;
  131. break;
  132. }
  133. case 2:
  134. {
  135. // Top middle
  136. box.point.y += diffF.y;
  137. postMoveExtentY = true;
  138. break;
  139. }
  140. case 3:
  141. {
  142. // Top right
  143. box.point.y += diffF.y;
  144. box.extent.x += diffF.x;
  145. postMoveExtentY = true;
  146. break;
  147. }
  148. case 4:
  149. {
  150. // Middle right
  151. box.extent.x += diffF.x;
  152. break;
  153. }
  154. case 5:
  155. {
  156. // Bottom right
  157. box.extent += diffF;
  158. break;
  159. }
  160. case 6:
  161. {
  162. // Bottom middle
  163. box.extent.y += diffF.y;
  164. break;
  165. }
  166. case 7:
  167. {
  168. // Bottom left
  169. box.point.x += diffF.x;
  170. box.extent.y += diffF.y;
  171. postMoveExtentX = true;
  172. break;
  173. }
  174. case 8:
  175. {
  176. // Middle left
  177. box.point.x += diffF.x;
  178. postMoveExtentX = true;
  179. break;
  180. }
  181. case 9:
  182. {
  183. // Centre
  184. box.point += diffF;
  185. keepExtent = true;
  186. break;
  187. }
  188. default:
  189. break;
  190. }
  191. // Position limits
  192. if(box.point.x < 0.0f)
  193. box.point.x = 0.0f;
  194. else if(box.point.x > 1.0f)
  195. box.point.x = 1.0f;
  196. if(box.point.y < 0.0f)
  197. box.point.y = 0.0f;
  198. else if(box.point.y > 1.0f)
  199. box.point.y = 1.0f;
  200. // Move any extent to counter a change in handle position. Do this
  201. // after the limits above to make sure the extent doesn't accidentally
  202. // grow when the position is clamped.
  203. if(postMoveExtentX)
  204. box.extent.x += mHandleRect.point.x - box.point.x;
  205. if(postMoveExtentY)
  206. box.extent.y += mHandleRect.point.y - box.point.y;
  207. // Extent limits
  208. if(box.extent.x < 0.0f)
  209. box.extent.x = 0.0f;
  210. else if(box.extent.x > 1.0f)
  211. box.extent.x = 1.0f;
  212. if(box.point.x+box.extent.x > 1.0f)
  213. {
  214. if(keepExtent)
  215. box.point.x = 1.0f-box.extent.x;
  216. else
  217. box.extent.x = 1.0f-box.point.x;
  218. }
  219. if(box.extent.y < 0.0f)
  220. box.extent.y = 0.0f;
  221. else if(box.extent.y > 1.0f)
  222. box.extent.y = 1.0f;
  223. if(box.point.y+box.extent.y > 1.0f)
  224. {
  225. if(keepExtent)
  226. box.point.y = 1.0f-box.extent.y;
  227. else
  228. box.extent.y = 1.0f-box.point.y;
  229. }
  230. mHandleRect = box;
  231. mHitPoint = localMousePoint;
  232. if( isMethod( "onHandleRectChange" ) )
  233. Con::executef(this, "onHandleRectChange" );
  234. }
  235. //--------------------------------------------------------------------------
  236. void GuiRectHandles::onRender(Point2I offset, const RectI &updateRect)
  237. {
  238. Parent::onRender( offset, updateRect );
  239. ColorI handleColor = mProfile->mBorderColor;
  240. if(mUseCustomColor)
  241. handleColor = mHandleColor;
  242. // The handles range from 0-1, so scale to fit within the
  243. // control's bounds.
  244. const Point2I& extent = getExtent();
  245. Point2I pos(extent.x*mHandleRect.point.x, extent.y*mHandleRect.point.y);
  246. Point2I size(extent.x*mHandleRect.extent.x, extent.y*mHandleRect.extent.y);
  247. RectI box(offset+pos, size);
  248. // Draw border
  249. GFX->getDrawUtil()->drawRect(box, handleColor);
  250. // Draw each handle
  251. Point2I handleSize(mHandleSize, mHandleSize);
  252. RectI handleRect(box.point, handleSize);
  253. GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Upper left
  254. handleRect.point = Point2I(box.point.x+size.x-handleSize.x, box.point.y);
  255. GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Upper right
  256. handleRect.point = Point2I(box.point.x, box.point.y+size.y-handleSize.y);
  257. GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Lower left
  258. handleRect.point = Point2I(box.point.x+size.x-handleSize.x, box.point.y+size.y-handleSize.y);
  259. GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Lower right
  260. Point2I halfSize = size / 2;
  261. Point2I halfHandleSize = handleSize / 2;
  262. handleRect.point = Point2I(box.point.x+halfSize.x-halfHandleSize.x, box.point.y);
  263. GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Upper middle
  264. handleRect.point = Point2I(box.point.x+halfSize.x-halfHandleSize.x, box.point.y+size.y-handleSize.y);
  265. GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Lower middle
  266. handleRect.point = Point2I(box.point.x, box.point.y+halfSize.y-halfHandleSize.y);
  267. GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Left middle
  268. handleRect.point = Point2I(box.point.x+size.x-handleSize.x, box.point.y+halfSize.y-halfHandleSize.y);
  269. GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Right middle
  270. handleRect.point = Point2I(box.point.x+halfSize.x-halfHandleSize.x, box.point.y+halfSize.y-halfHandleSize.y);
  271. GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Middle
  272. renderChildControls(offset, updateRect);
  273. }