Window.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  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 deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // 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 FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "Cursor.h"
  25. #include "InputEvents.h"
  26. #include "Window.h"
  27. #include "DebugNew.h"
  28. static const int DEFAULT_RESIZE_BORDER = 4;
  29. Window::Window(const std::string& name) :
  30. BorderImage(name),
  31. mMovable(false),
  32. mResizable(false),
  33. mResizeBorder(DEFAULT_RESIZE_BORDER, DEFAULT_RESIZE_BORDER, DEFAULT_RESIZE_BORDER, DEFAULT_RESIZE_BORDER),
  34. mDragMode(DRAG_NONE)
  35. {
  36. mBringToFront = true;
  37. mClipChildren = true;
  38. mEnabled = true;
  39. }
  40. Window::~Window()
  41. {
  42. }
  43. void Window::setStyle(const XMLElement& element, ResourceCache* cache)
  44. {
  45. BorderImage::setStyle(element, cache);
  46. if (element.hasChildElement("resizeborder"))
  47. setResizeBorder(element.getChildElement("resizeborder").getIntRect("value"));
  48. if (element.hasChildElement("movable"))
  49. setMovable(element.getChildElement("movable").getBool("enable"));
  50. if (element.hasChildElement("resizable"))
  51. setResizable(element.getChildElement("resizable").getBool("enable"));
  52. }
  53. void Window::onHover(const IntVector2& position, const IntVector2& screenPosition, int buttons, int qualifiers, Cursor* cursor)
  54. {
  55. if (mDragMode == DRAG_NONE)
  56. {
  57. WindowDragMode mode = identifyDragMode(position);
  58. setCursorShape(mode, cursor);
  59. }
  60. else
  61. setCursorShape(mDragMode, cursor);
  62. }
  63. void Window::onDragStart(const IntVector2& position, const IntVector2& screenPosition, int buttons, int qualifiers, Cursor* cursor)
  64. {
  65. if ((buttons != MOUSEB_LEFT) || (!checkAlignment()))
  66. {
  67. mDragMode = DRAG_NONE;
  68. return;
  69. }
  70. mDragStartPosition = screenPosition;
  71. mOriginalPosition = getPosition();
  72. mOriginalSize = getSize();
  73. mDragMode = identifyDragMode(position);
  74. setCursorShape(mDragMode, cursor);
  75. }
  76. void Window::onDragMove(const IntVector2& position, const IntVector2& screenPosition, int buttons, int qualifiers, Cursor* cursor)
  77. {
  78. if (mDragMode == DRAG_NONE)
  79. return;
  80. IntVector2 delta = screenPosition - mDragStartPosition;
  81. switch (mDragMode)
  82. {
  83. case DRAG_MOVE:
  84. setPosition(mOriginalPosition + delta);
  85. break;
  86. case DRAG_RESIZE_TOPLEFT:
  87. setPosition(mOriginalPosition + delta);
  88. setSize(mOriginalSize - delta);
  89. break;
  90. case DRAG_RESIZE_TOP:
  91. setPosition(mOriginalPosition.mX, mOriginalPosition.mY + delta.mY);
  92. setSize(mOriginalSize.mX, mOriginalSize.mY - delta.mY);
  93. break;
  94. case DRAG_RESIZE_TOPRIGHT:
  95. setPosition(mOriginalPosition.mX, mOriginalPosition.mY + delta.mY);
  96. setSize(mOriginalSize.mX + delta.mX, mOriginalSize.mY - delta.mY);
  97. break;
  98. case DRAG_RESIZE_RIGHT:
  99. setSize(mOriginalSize.mX + delta.mX, mOriginalSize.mY);
  100. break;
  101. case DRAG_RESIZE_BOTTOMRIGHT:
  102. setSize(mOriginalSize + delta);
  103. break;
  104. case DRAG_RESIZE_BOTTOM:
  105. setSize(mOriginalSize.mX, mOriginalSize.mY + delta.mY);
  106. break;
  107. case DRAG_RESIZE_BOTTOMLEFT:
  108. setPosition(mOriginalPosition.mX + delta.mX, mOriginalPosition.mY);
  109. setSize(mOriginalSize.mX - delta.mX, mOriginalSize.mY + delta.mY);
  110. break;
  111. case DRAG_RESIZE_LEFT:
  112. setPosition(mOriginalPosition.mX + delta.mX, mOriginalPosition.mY);
  113. setSize(mOriginalSize.mX - delta.mX, mOriginalSize.mY);
  114. break;
  115. }
  116. validatePosition();
  117. setCursorShape(mDragMode, cursor);
  118. }
  119. void Window::onDragEnd(const IntVector2& position, const IntVector2& screenPosition, Cursor* cursor)
  120. {
  121. mDragMode = DRAG_NONE;
  122. }
  123. void Window::setMovable(bool enable)
  124. {
  125. mMovable = enable;
  126. }
  127. void Window::setResizable(bool enable)
  128. {
  129. mResizable = enable;
  130. }
  131. void Window::setResizeBorder(const IntRect& rect)
  132. {
  133. mResizeBorder.mLeft = max(rect.mLeft, 0);
  134. mResizeBorder.mTop = max(rect.mTop, 0);
  135. mResizeBorder.mRight = max(rect.mRight, 0);
  136. mResizeBorder.mBottom = max(rect.mBottom, 0);
  137. }
  138. void Window::setResizeBorder(int left, int top, int right, int bottom)
  139. {
  140. setResizeBorder(IntRect(left, top, right, bottom));
  141. }
  142. WindowDragMode Window::identifyDragMode(const IntVector2& position) const
  143. {
  144. WindowDragMode mode = DRAG_NONE;
  145. // Top row
  146. if (position.mY < mResizeBorder.mTop)
  147. {
  148. if (mMovable)
  149. mode = DRAG_MOVE;
  150. if (mResizable)
  151. {
  152. mode = DRAG_RESIZE_TOP;
  153. if (position.mX < mResizeBorder.mLeft)
  154. mode = DRAG_RESIZE_TOPLEFT;
  155. if (position.mX >= getWidth() - mResizeBorder.mRight)
  156. mode = DRAG_RESIZE_TOPRIGHT;
  157. }
  158. }
  159. // Bottom row
  160. else if (position.mY >= getHeight() - mResizeBorder.mBottom)
  161. {
  162. if (mMovable)
  163. mode = DRAG_MOVE;
  164. if (mResizable)
  165. {
  166. mode = DRAG_RESIZE_BOTTOM;
  167. if (position.mX < mResizeBorder.mLeft)
  168. mode = DRAG_RESIZE_BOTTOMLEFT;
  169. if (position.mX >= getWidth() - mResizeBorder.mRight)
  170. mode = DRAG_RESIZE_BOTTOMRIGHT;
  171. }
  172. }
  173. // Middle
  174. else
  175. {
  176. if (mMovable)
  177. mode = DRAG_MOVE;
  178. if (mResizable)
  179. {
  180. if (position.mX < mResizeBorder.mLeft)
  181. mode = DRAG_RESIZE_LEFT;
  182. if (position.mX >= getWidth() - mResizeBorder.mRight)
  183. mode = DRAG_RESIZE_RIGHT;
  184. }
  185. }
  186. return mode;
  187. }
  188. void Window::setCursorShape(WindowDragMode mode, Cursor* cursor) const
  189. {
  190. switch (mode)
  191. {
  192. case DRAG_RESIZE_TOP:
  193. case DRAG_RESIZE_BOTTOM:
  194. cursor->setShape(CS_RESIZEVERTICAL);
  195. break;
  196. case DRAG_RESIZE_LEFT:
  197. case DRAG_RESIZE_RIGHT:
  198. cursor->setShape(CS_RESIZEHORIZONTAL);
  199. break;
  200. case DRAG_RESIZE_TOPRIGHT:
  201. case DRAG_RESIZE_BOTTOMLEFT:
  202. cursor->setShape(CS_RESIZEDIAGONAL_TOPRIGHT);
  203. break;
  204. case DRAG_RESIZE_TOPLEFT:
  205. case DRAG_RESIZE_BOTTOMRIGHT:
  206. cursor->setShape(CS_RESIZEDIAGONAL_TOPLEFT);
  207. break;
  208. }
  209. }
  210. void Window::validatePosition()
  211. {
  212. // Check that window does not go more than halfway outside its parent in either dimension
  213. if (!mParent)
  214. return;
  215. const IntVector2& parentSize = mParent->getSize();
  216. IntVector2 position = getPosition();
  217. IntVector2 halfSize = getSize() / 2;
  218. position.mX = clamp(position.mX, -halfSize.mX, parentSize.mX - halfSize.mX);
  219. position.mY = clamp(position.mY, -halfSize.mY, parentSize.mY - halfSize.mY);
  220. setPosition(position);
  221. }
  222. bool Window::checkAlignment() const
  223. {
  224. // Only top left-alignment is supported for move and resize
  225. if ((getHorizontalAlignment() == HA_LEFT) && (getVerticalAlignment() == VA_TOP))
  226. return true;
  227. else
  228. return false;
  229. }