guiRectHandles.cpp 10.0 KB

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