llresizebar.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /**
  2. * @file llresizebar.cpp
  3. * @brief LLResizeBar base class
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "linden_common.h"
  33. #include "llresizebar.h"
  34. #include "llmenugl.h"
  35. #include "llwindow.h"
  36. LLResizeBar::LLResizeBar(const std::string& name, LLView* resizing_viewp,
  37. const LLRect& rect, S32 min_size, S32 max_size,
  38. Side side)
  39. : LLView(name, rect, true),
  40. mResizingView(resizing_viewp),
  41. mDragLastScreenX(0),
  42. mDragLastScreenY(0),
  43. mLastMouseScreenX(0),
  44. mLastMouseScreenY(0),
  45. mMinSize(min_size),
  46. mMaxSize(max_size),
  47. mSide(side),
  48. mSnappingEnabled(true),
  49. mAllowDoubleClickSnapping(true),
  50. mResizing(false)
  51. {
  52. // This is a decorator object: never serialize it.
  53. setSaveToXML(false);
  54. // Set up some generically good follow code.
  55. switch (side)
  56. {
  57. case LEFT:
  58. setFollowsLeft();
  59. setFollowsTop();
  60. setFollowsBottom();
  61. break;
  62. case TOP:
  63. setFollowsTop();
  64. setFollowsLeft();
  65. setFollowsRight();
  66. break;
  67. case RIGHT:
  68. setFollowsRight();
  69. setFollowsTop();
  70. setFollowsBottom();
  71. break;
  72. case BOTTOM:
  73. setFollowsBottom();
  74. setFollowsLeft();
  75. setFollowsRight();
  76. default:
  77. break;
  78. }
  79. setToolTip("Resize"); // *TODO: translate
  80. }
  81. bool LLResizeBar::handleMouseDown(S32 x, S32 y, MASK mask)
  82. {
  83. // Route future Mouse messages here preemptively (release on mouse up).
  84. // No handler needed for focus lost since this clas has no state that
  85. // depends on it.
  86. gFocusMgr.setMouseCapture(this);
  87. localPointToScreen(x, y, &mDragLastScreenX, &mDragLastScreenY);
  88. mLastMouseScreenX = mDragLastScreenX;
  89. mLastMouseScreenY = mDragLastScreenY;
  90. return true;
  91. }
  92. bool LLResizeBar::handleMouseUp(S32 x, S32 y, MASK mask)
  93. {
  94. mResizing = false;
  95. if (hasMouseCapture())
  96. {
  97. // Release the mouse
  98. gFocusMgr.setMouseCapture(NULL);
  99. }
  100. return true; // Always "handled"
  101. }
  102. bool LLResizeBar::handleHover(S32 x, S32 y, MASK mask)
  103. {
  104. mResizing = false;
  105. if (hasMouseCapture())
  106. {
  107. mResizing = true;
  108. S32 screen_x;
  109. S32 screen_y;
  110. localPointToScreen(x, y, &screen_x, &screen_y);
  111. S32 delta_x = screen_x - mDragLastScreenX;
  112. S32 delta_y = screen_y - mDragLastScreenY;
  113. LLCoordGL mouse_dir;
  114. // use hysteresis on mouse motion to preserve user intent when mouse
  115. // stops moving
  116. mouse_dir.mX =
  117. screen_x == mLastMouseScreenX ? mLastMouseDir.mX
  118. : screen_x - mLastMouseScreenX;
  119. mouse_dir.mY =
  120. screen_y == mLastMouseScreenY ? mLastMouseDir.mY
  121. : screen_y - mLastMouseScreenY;
  122. mLastMouseDir = mouse_dir;
  123. mLastMouseScreenX = screen_x;
  124. mLastMouseScreenY = screen_y;
  125. // Make sure the mouse in still over the application. We do not want to
  126. // make the parent so big that we can't see the resize handle any more.
  127. LLRect valid_rect = getRootView()->getRect();
  128. if (valid_rect.localPointInRect(screen_x, screen_y) && mResizingView)
  129. {
  130. // Resize the parent
  131. LLRect orig_rect = mResizingView->getRect();
  132. LLRect scaled_rect = orig_rect;
  133. S32 new_width = orig_rect.getWidth();
  134. S32 new_height = orig_rect.getHeight();
  135. switch (mSide)
  136. {
  137. case LEFT:
  138. new_width = llclamp(orig_rect.getWidth() - delta_x,
  139. mMinSize, mMaxSize);
  140. delta_x = orig_rect.getWidth() - new_width;
  141. scaled_rect.translate(delta_x, 0);
  142. break;
  143. case TOP:
  144. new_height = llclamp(orig_rect.getHeight() + delta_y,
  145. mMinSize, mMaxSize);
  146. delta_y = new_height - orig_rect.getHeight();
  147. break;
  148. case RIGHT:
  149. new_width = llclamp(orig_rect.getWidth() + delta_x,
  150. mMinSize, mMaxSize);
  151. delta_x = new_width - orig_rect.getWidth();
  152. break;
  153. case BOTTOM:
  154. new_height = llclamp(orig_rect.getHeight() - delta_y,
  155. mMinSize, mMaxSize);
  156. delta_y = orig_rect.getHeight() - new_height;
  157. scaled_rect.translate(0, delta_y);
  158. }
  159. scaled_rect.mTop = scaled_rect.mBottom + new_height;
  160. scaled_rect.mRight = scaled_rect.mLeft + new_width;
  161. mResizingView->setRect(scaled_rect);
  162. LLView* snap_viewp = NULL;
  163. if (mSnappingEnabled)
  164. {
  165. switch (mSide)
  166. {
  167. case LEFT:
  168. snap_viewp =
  169. mResizingView->findSnapEdge(scaled_rect.mLeft,
  170. mouse_dir, SNAP_LEFT,
  171. SNAP_PARENT_AND_SIBLINGS,
  172. LLUI::sSnapMargin);
  173. break;
  174. case TOP:
  175. snap_viewp =
  176. mResizingView->findSnapEdge(scaled_rect.mTop,
  177. mouse_dir, SNAP_TOP,
  178. SNAP_PARENT_AND_SIBLINGS,
  179. LLUI::sSnapMargin);
  180. break;
  181. case RIGHT:
  182. snap_viewp =
  183. mResizingView->findSnapEdge(scaled_rect.mRight,
  184. mouse_dir, SNAP_RIGHT,
  185. SNAP_PARENT_AND_SIBLINGS,
  186. LLUI::sSnapMargin);
  187. break;
  188. case BOTTOM:
  189. snap_viewp =
  190. mResizingView->findSnapEdge(scaled_rect.mBottom,
  191. mouse_dir, SNAP_BOTTOM,
  192. SNAP_PARENT_AND_SIBLINGS,
  193. LLUI::sSnapMargin);
  194. }
  195. }
  196. // Register "snap" behavior with snapped view
  197. mResizingView->snappedTo(snap_viewp);
  198. // Restore original rectangle so the appropriate changes are
  199. // detected
  200. mResizingView->setRect(orig_rect);
  201. // Change view shape as user operation
  202. mResizingView->userSetShape(scaled_rect);
  203. // Update last valid mouse cursor position based on resized view's
  204. // actual size
  205. LLRect new_rect = mResizingView->getRect();
  206. switch (mSide)
  207. {
  208. case LEFT:
  209. mDragLastScreenX += new_rect.mLeft - orig_rect.mLeft;
  210. break;
  211. case RIGHT:
  212. mDragLastScreenX += new_rect.mRight - orig_rect.mRight;
  213. break;
  214. case TOP:
  215. mDragLastScreenY += new_rect.mTop - orig_rect.mTop;
  216. break;
  217. case BOTTOM:
  218. mDragLastScreenY += new_rect.mBottom- orig_rect.mBottom;
  219. }
  220. }
  221. }
  222. switch (mSide)
  223. {
  224. case LEFT:
  225. case RIGHT:
  226. gWindowp->setCursor(UI_CURSOR_SIZEWE);
  227. break;
  228. case TOP:
  229. case BOTTOM:
  230. gWindowp->setCursor(UI_CURSOR_SIZENS);
  231. }
  232. return true; // Always "handled".
  233. }
  234. bool LLResizeBar::handleDoubleClick(S32 x, S32 y, MASK mask)
  235. {
  236. if (mSnappingEnabled && mAllowDoubleClickSnapping)
  237. {
  238. LLRect scaled_rect = mResizingView->getRect();
  239. switch (mSide)
  240. {
  241. case LEFT:
  242. mResizingView->findSnapEdge(scaled_rect.mLeft,
  243. LLCoordGL(0, 0), SNAP_LEFT,
  244. SNAP_PARENT_AND_SIBLINGS, S32_MAX);
  245. scaled_rect.mLeft = scaled_rect.mRight -
  246. llclamp(scaled_rect.getWidth(),
  247. mMinSize, mMaxSize);
  248. break;
  249. case TOP:
  250. mResizingView->findSnapEdge(scaled_rect.mTop,
  251. LLCoordGL(0, 0), SNAP_TOP,
  252. SNAP_PARENT_AND_SIBLINGS, S32_MAX);
  253. scaled_rect.mTop = scaled_rect.mBottom +
  254. llclamp(scaled_rect.getHeight(),
  255. mMinSize, mMaxSize);
  256. break;
  257. case RIGHT:
  258. mResizingView->findSnapEdge(scaled_rect.mRight,
  259. LLCoordGL(0, 0), SNAP_RIGHT,
  260. SNAP_PARENT_AND_SIBLINGS, S32_MAX);
  261. scaled_rect.mRight = scaled_rect.mLeft +
  262. llclamp(scaled_rect.getWidth(),
  263. mMinSize, mMaxSize);
  264. break;
  265. case BOTTOM:
  266. mResizingView->findSnapEdge(scaled_rect.mBottom,
  267. LLCoordGL(0, 0), SNAP_BOTTOM,
  268. SNAP_PARENT_AND_SIBLINGS, S32_MAX);
  269. scaled_rect.mBottom = scaled_rect.mTop -
  270. llclamp(scaled_rect.getHeight(),
  271. mMinSize, mMaxSize);
  272. }
  273. mResizingView->userSetShape(scaled_rect);
  274. }
  275. return true; // Always "handled".
  276. }