aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llui/llresizehandle.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llui/llresizehandle.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llui/llresizehandle.cpp')
-rw-r--r--linden/indra/llui/llresizehandle.cpp340
1 files changed, 340 insertions, 0 deletions
diff --git a/linden/indra/llui/llresizehandle.cpp b/linden/indra/llui/llresizehandle.cpp
new file mode 100644
index 0000000..fc15bcc
--- /dev/null
+++ b/linden/indra/llui/llresizehandle.cpp
@@ -0,0 +1,340 @@
1/**
2 * @file llresizehandle.cpp
3 * @brief LLResizeHandle base class
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "llresizehandle.h"
31
32#include "llfocusmgr.h"
33#include "llmath.h"
34#include "llui.h"
35#include "llmenugl.h"
36#include "llcontrol.h"
37#include "llfloater.h"
38#include "llwindow.h"
39
40const S32 RESIZE_BORDER_WIDTH = 3;
41
42LLResizeHandle::LLResizeHandle( const LLString& name, const LLRect& rect, S32 min_width, S32 min_height, ECorner corner )
43 :
44 LLView( name, rect, TRUE ),
45 mDragStartScreenX( 0 ),
46 mDragStartScreenY( 0 ),
47 mLastMouseScreenX( 0 ),
48 mLastMouseScreenY( 0 ),
49 mImage( NULL ),
50 mMinWidth( min_width ),
51 mMinHeight( min_height ),
52 mCorner( corner )
53{
54 setSaveToXML(false);
55
56 if( RIGHT_BOTTOM == mCorner)
57 {
58 LLUUID image_id(LLUI::sConfigGroup->getString("UIImgResizeBottomRightUUID"));
59 mImage = LLUI::sImageProvider->getUIImageByID(image_id);
60 }
61
62 switch( mCorner )
63 {
64 case LEFT_TOP: setFollows( FOLLOWS_LEFT | FOLLOWS_TOP ); break;
65 case LEFT_BOTTOM: setFollows( FOLLOWS_LEFT | FOLLOWS_BOTTOM ); break;
66 case RIGHT_TOP: setFollows( FOLLOWS_RIGHT | FOLLOWS_TOP ); break;
67 case RIGHT_BOTTOM: setFollows( FOLLOWS_RIGHT | FOLLOWS_BOTTOM ); break;
68 }
69}
70
71EWidgetType LLResizeHandle::getWidgetType() const
72{
73 return WIDGET_TYPE_RESIZE_HANDLE;
74}
75
76LLString LLResizeHandle::getWidgetTag() const
77{
78 return LL_RESIZE_HANDLE_TAG;
79}
80
81BOOL LLResizeHandle::handleMouseDown(S32 x, S32 y, MASK mask)
82{
83 BOOL handled = FALSE;
84 if( getVisible() && pointInHandle(x, y) )
85 {
86 handled = TRUE;
87 if( mEnabled )
88 {
89 // Route future Mouse messages here preemptively. (Release on mouse up.)
90 // No handler needed for focus lost since this clas has no state that depends on it.
91 gFocusMgr.setMouseCapture( this, NULL );
92
93 localPointToScreen(x, y, &mDragStartScreenX, &mDragStartScreenY);
94 mLastMouseScreenX = mDragStartScreenX;
95 mLastMouseScreenY = mDragStartScreenY;
96 }
97 }
98
99 return handled;
100}
101
102
103BOOL LLResizeHandle::handleMouseUp(S32 x, S32 y, MASK mask)
104{
105 BOOL handled = FALSE;
106
107 if( gFocusMgr.getMouseCapture() == this )
108 {
109 // Release the mouse
110 gFocusMgr.setMouseCapture( NULL, NULL );
111 handled = TRUE;
112 }
113 else
114 if( getVisible() && pointInHandle(x, y) )
115 {
116 handled = TRUE;
117 }
118
119 return handled;
120}
121
122
123BOOL LLResizeHandle::handleHover(S32 x, S32 y, MASK mask)
124{
125 BOOL handled = FALSE;
126
127 // We only handle the click if the click both started and ended within us
128 if( gFocusMgr.getMouseCapture() == this )
129 {
130 // Make sure the mouse in still over the application. We don't want to make the parent
131 // so big that we can't see the resize handle any more.
132
133 S32 screen_x;
134 S32 screen_y;
135 localPointToScreen(x, y, &screen_x, &screen_y);
136 const LLRect& valid_rect = gFloaterView->getRect(); // Assumes that the parent is a floater.
137 screen_x = llclamp( screen_x, valid_rect.mLeft, valid_rect.mRight );
138 screen_y = llclamp( screen_y, valid_rect.mBottom, valid_rect.mTop );
139
140 LLView* parentView = getParent();
141 if( parentView )
142 {
143 // Resize the parent
144 LLRect parent_rect = parentView->getRect();
145 LLRect scaled_rect = parent_rect;
146 S32 delta_x = screen_x - mDragStartScreenX;
147 S32 delta_y = screen_y - mDragStartScreenY;
148 LLCoordGL mouse_dir;
149 // use hysteresis on mouse motion to preserve user intent when mouse stops moving
150 mouse_dir.mX = (screen_x == mLastMouseScreenX) ? mLastMouseDir.mX : screen_x - mLastMouseScreenX;
151 mouse_dir.mY = (screen_y == mLastMouseScreenY) ? mLastMouseDir.mY : screen_y - mLastMouseScreenY;
152 mLastMouseScreenX = screen_x;
153 mLastMouseScreenY = screen_y;
154 mLastMouseDir = mouse_dir;
155
156 S32 x_multiple = 1;
157 S32 y_multiple = 1;
158 switch( mCorner )
159 {
160 case LEFT_TOP:
161 x_multiple = -1;
162 y_multiple = 1;
163 break;
164 case LEFT_BOTTOM:
165 x_multiple = -1;
166 y_multiple = -1;
167 break;
168 case RIGHT_TOP:
169 x_multiple = 1;
170 y_multiple = 1;
171 break;
172 case RIGHT_BOTTOM:
173 x_multiple = 1;
174 y_multiple = -1;
175 break;
176 }
177
178 S32 new_width = parent_rect.getWidth() + x_multiple * delta_x;
179 if( new_width < mMinWidth )
180 {
181 new_width = mMinWidth;
182 delta_x = x_multiple * (mMinWidth - parent_rect.getWidth());
183 }
184
185 S32 new_height = parent_rect.getHeight() + y_multiple * delta_y;
186 if( new_height < mMinHeight )
187 {
188 new_height = mMinHeight;
189 delta_y = y_multiple * (mMinHeight - parent_rect.getHeight());
190 }
191
192 switch( mCorner )
193 {
194 case LEFT_TOP:
195 scaled_rect.translate(delta_x, 0);
196 break;
197 case LEFT_BOTTOM:
198 scaled_rect.translate(delta_x, delta_y);
199 break;
200 case RIGHT_TOP:
201 break;
202 case RIGHT_BOTTOM:
203 scaled_rect.translate(0, delta_y);
204 break;
205 }
206
207 // temporarily set new parent rect
208 scaled_rect.mRight = scaled_rect.mLeft + new_width;
209 scaled_rect.mTop = scaled_rect.mBottom + new_height;
210 parentView->setRect(scaled_rect);
211
212 S32 snap_delta_x = 0;
213 S32 snap_delta_y = 0;
214
215 LLView* snap_view = NULL;
216 LLView* test_view = NULL;
217
218 // now do snapping
219 switch(mCorner)
220 {
221 case LEFT_TOP:
222 snap_view = parentView->findSnapEdge(snap_delta_x, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
223 snap_delta_x -= scaled_rect.mLeft;
224 test_view = parentView->findSnapEdge(snap_delta_y, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
225 snap_delta_y -= scaled_rect.mTop;
226 if (!snap_view)
227 {
228 snap_view = test_view;
229 }
230 scaled_rect.mLeft += snap_delta_x;
231 scaled_rect.mTop += snap_delta_y;
232 break;
233 case LEFT_BOTTOM:
234 snap_view = parentView->findSnapEdge(snap_delta_x, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
235 snap_delta_x -= scaled_rect.mLeft;
236 test_view = parentView->findSnapEdge(snap_delta_y, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
237 snap_delta_y -= scaled_rect.mBottom;
238 if (!snap_view)
239 {
240 snap_view = test_view;
241 }
242 scaled_rect.mLeft += snap_delta_x;
243 scaled_rect.mBottom += snap_delta_y;
244 break;
245 case RIGHT_TOP:
246 snap_view = parentView->findSnapEdge(snap_delta_x, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
247 snap_delta_x -= scaled_rect.mRight;
248 test_view = parentView->findSnapEdge(snap_delta_y, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
249 snap_delta_y -= scaled_rect.mTop;
250 if (!snap_view)
251 {
252 snap_view = test_view;
253 }
254 scaled_rect.mRight += snap_delta_x;
255 scaled_rect.mTop += snap_delta_y;
256 break;
257 case RIGHT_BOTTOM:
258 snap_view = parentView->findSnapEdge(snap_delta_x, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
259 snap_delta_x -= scaled_rect.mRight;
260 test_view = parentView->findSnapEdge(snap_delta_y, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
261 snap_delta_y -= scaled_rect.mBottom;
262 if (!snap_view)
263 {
264 snap_view = test_view;
265 }
266 scaled_rect.mRight += snap_delta_x;
267 scaled_rect.mBottom += snap_delta_y;
268 break;
269 }
270
271 parentView->snappedTo(snap_view);
272
273 // reset parent rect
274 parentView->setRect(parent_rect);
275
276 // translate and scale to new shape
277 parentView->reshape(scaled_rect.getWidth(), scaled_rect.getHeight(), FALSE);
278 parentView->translate(scaled_rect.mLeft - parentView->getRect().mLeft, scaled_rect.mBottom - parentView->getRect().mBottom);
279
280 screen_x = mDragStartScreenX + delta_x + snap_delta_x;
281 screen_y = mDragStartScreenY + delta_y + snap_delta_y;
282 mDragStartScreenX = screen_x;
283 mDragStartScreenY = screen_y;
284 }
285
286 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active) " << llendl;
287 handled = TRUE;
288 }
289 else
290 if( getVisible() && pointInHandle( x, y ) )
291 {
292 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive) " << llendl;
293 handled = TRUE;
294 }
295
296 if( handled )
297 {
298 switch( mCorner )
299 {
300 case RIGHT_BOTTOM:
301 case LEFT_TOP:
302 getWindow()->setCursor(UI_CURSOR_SIZENWSE);
303 break;
304 case LEFT_BOTTOM:
305 case RIGHT_TOP:
306 getWindow()->setCursor(UI_CURSOR_SIZENESW);
307 break;
308 }
309 }
310
311 return handled;
312}
313
314// assumes GL state is set for 2D
315void LLResizeHandle::draw()
316{
317 if( mImage.notNull() && getVisible() && (RIGHT_BOTTOM == mCorner) )
318 {
319 gl_draw_image( 0, 0, mImage );
320 }
321}
322
323
324BOOL LLResizeHandle::pointInHandle( S32 x, S32 y )
325{
326 if( pointInView(x, y) )
327 {
328 const S32 TOP_BORDER = (mRect.getHeight() - RESIZE_BORDER_WIDTH);
329 const S32 RIGHT_BORDER = (mRect.getWidth() - RESIZE_BORDER_WIDTH);
330
331 switch( mCorner )
332 {
333 case LEFT_TOP: return (x <= RESIZE_BORDER_WIDTH) || (y >= TOP_BORDER);
334 case LEFT_BOTTOM: return (x <= RESIZE_BORDER_WIDTH) || (y <= RESIZE_BORDER_WIDTH);
335 case RIGHT_TOP: return (x >= RIGHT_BORDER) || (y >= TOP_BORDER);
336 case RIGHT_BOTTOM: return TRUE;
337 }
338 }
339 return FALSE;
340}