PageRenderTime 33ms CodeModel.GetById 14ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llui/llresizebar.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 299 lines | 219 code | 41 blank | 39 comment | 14 complexity | 30e2d1a91fc601037a81f9a8c7d5d798 MD5 | raw file
  1/** 
  2 * @file llresizebar.cpp
  3 * @brief LLResizeBar base class
  4 *
  5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "linden_common.h"
 28
 29#include "llresizebar.h"
 30
 31#include "llmath.h"
 32#include "llui.h"
 33#include "llmenugl.h"
 34#include "llfocusmgr.h"
 35#include "llwindow.h"
 36
 37LLResizeBar::LLResizeBar(const LLResizeBar::Params& p)
 38:	LLView(p),
 39	mDragLastScreenX( 0 ),
 40	mDragLastScreenY( 0 ),
 41	mLastMouseScreenX( 0 ),
 42	mLastMouseScreenY( 0 ),
 43	mMinSize( p.min_size ),
 44	mMaxSize( p.max_size ),
 45	mSide( p.side ),
 46	mSnappingEnabled(p.snapping_enabled),
 47	mAllowDoubleClickSnapping(p.allow_double_click_snapping),
 48	mResizingView(p.resizing_view)
 49{
 50	setFollowsNone();
 51	// set up some generically good follow code.
 52	switch( mSide )
 53	{
 54	case LEFT:
 55		setFollowsLeft();
 56		setFollowsTop();
 57		setFollowsBottom();
 58		break;
 59	case TOP:
 60		setFollowsTop();
 61		setFollowsLeft();
 62		setFollowsRight();
 63		break;
 64	case RIGHT:
 65		setFollowsRight();
 66		setFollowsTop();
 67		setFollowsBottom();
 68		break;
 69	case BOTTOM:
 70		setFollowsBottom();
 71		setFollowsLeft();
 72		setFollowsRight();
 73		break;
 74	default:
 75		break;
 76	}
 77}
 78
 79
 80BOOL LLResizeBar::handleMouseDown(S32 x, S32 y, MASK mask)
 81{
 82	if (!canResize()) return FALSE;
 83
 84	// Route future Mouse messages here preemptively.  (Release on mouse up.)
 85	// No handler needed for focus lost since this clas has no state that depends on it.
 86	gFocusMgr.setMouseCapture( this );
 87
 88	localPointToScreen(x, y, &mDragLastScreenX, &mDragLastScreenY);
 89	mLastMouseScreenX = mDragLastScreenX;
 90	mLastMouseScreenY = mDragLastScreenY;
 91
 92	return TRUE;
 93}
 94
 95
 96BOOL LLResizeBar::handleMouseUp(S32 x, S32 y, MASK mask)
 97{
 98	BOOL	handled = FALSE;
 99
100	if( hasMouseCapture() )
101	{
102		// Release the mouse
103		gFocusMgr.setMouseCapture( NULL );
104		handled = TRUE;
105	}
106	else
107	{
108		handled = TRUE;
109	}
110	return handled;
111}
112
113
114BOOL LLResizeBar::handleHover(S32 x, S32 y, MASK mask)
115{
116	BOOL	handled = FALSE;
117
118	// We only handle the click if the click both started and ended within us
119	if( hasMouseCapture() )
120	{
121		S32 screen_x;
122		S32 screen_y;
123		localPointToScreen(x, y, &screen_x, &screen_y);
124		
125		S32 delta_x = screen_x - mDragLastScreenX;
126		S32 delta_y = screen_y - mDragLastScreenY;
127				
128		LLCoordGL mouse_dir;
129		// use hysteresis on mouse motion to preserve user intent when mouse stops moving
130		mouse_dir.mX = (screen_x == mLastMouseScreenX) ? mLastMouseDir.mX : screen_x - mLastMouseScreenX;
131		mouse_dir.mY = (screen_y == mLastMouseScreenY) ? mLastMouseDir.mY : screen_y - mLastMouseScreenY;
132		mLastMouseDir = mouse_dir;
133		mLastMouseScreenX = screen_x;
134		mLastMouseScreenY = screen_y;
135
136		// Make sure the mouse in still over the application.  We don't want to make the parent
137		// so big that we can't see the resize handle any more.
138		LLRect valid_rect = getRootView()->getRect();
139		
140		if( valid_rect.localPointInRect( screen_x, screen_y ) && mResizingView )
141		{
142			// undock floater when user resize it
143			LLFloater* parent = dynamic_cast<LLFloater*>( getParent());
144			if (parent && parent->isDocked())
145			{
146				parent->setDocked( false, false);
147			}
148
149			// Resize the parent
150			LLRect orig_rect = mResizingView->getRect();
151			LLRect scaled_rect = orig_rect;
152				
153			S32 new_width = orig_rect.getWidth();
154			S32 new_height = orig_rect.getHeight();
155
156			switch( mSide )
157			{
158			case LEFT:
159				new_width = llclamp(orig_rect.getWidth() - delta_x, mMinSize, mMaxSize);
160				delta_x = orig_rect.getWidth() - new_width;
161				scaled_rect.translate(delta_x, 0);
162				break;
163
164			case TOP:
165				new_height = llclamp(orig_rect.getHeight() + delta_y, mMinSize, mMaxSize);
166				delta_y = new_height - orig_rect.getHeight();
167				break;
168			
169			case RIGHT:
170				new_width = llclamp(orig_rect.getWidth() + delta_x, mMinSize, mMaxSize);
171				delta_x = new_width - orig_rect.getWidth();
172				break;
173		
174			case BOTTOM:
175				new_height = llclamp(orig_rect.getHeight() - delta_y, mMinSize, mMaxSize);
176				delta_y = orig_rect.getHeight() - new_height;
177				scaled_rect.translate(0, delta_y);
178				break;
179			}
180
181			notifyParent(LLSD().with("action", "resize")
182				.with("view_name", mResizingView->getName())
183				.with("new_height", new_height)
184				.with("new_width", new_width));
185
186			scaled_rect.mTop = scaled_rect.mBottom + new_height;
187			scaled_rect.mRight = scaled_rect.mLeft + new_width;
188			mResizingView->setRect(scaled_rect);
189
190			LLView* snap_view = NULL;
191
192			if (mSnappingEnabled)
193			{
194				static LLUICachedControl<S32> snap_margin ("SnapMargin", 0);
195				switch( mSide )
196				{
197				case LEFT:
198					snap_view = mResizingView->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, snap_margin);
199					break;
200				case TOP:
201					snap_view = mResizingView->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, snap_margin);
202					break;
203				case RIGHT:
204					snap_view = mResizingView->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, snap_margin);
205					break;
206				case BOTTOM:
207					snap_view = mResizingView->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, snap_margin);
208					break;
209				}
210			}
211
212			// register "snap" behavior with snapped view
213			mResizingView->setSnappedTo(snap_view);
214
215			// restore original rectangle so the appropriate changes are detected
216			mResizingView->setRect(orig_rect);
217			// change view shape as user operation
218			mResizingView->setShape(scaled_rect, true);
219
220			// update last valid mouse cursor position based on resized view's actual size
221			LLRect new_rect = mResizingView->getRect();
222			switch(mSide)
223			{
224			case LEFT:
225				mDragLastScreenX += new_rect.mLeft - orig_rect.mLeft;
226				break;
227			case RIGHT:
228				mDragLastScreenX += new_rect.mRight - orig_rect.mRight;
229				break;
230			case TOP:
231				mDragLastScreenY += new_rect.mTop - orig_rect.mTop;
232				break;
233			case BOTTOM:
234				mDragLastScreenY += new_rect.mBottom- orig_rect.mBottom;
235				break;
236			default:
237				break;
238			}
239		}
240
241		handled = TRUE;
242	}
243	else
244	{
245		handled = TRUE;
246	}
247
248	if( handled && canResize() )
249	{
250		switch( mSide )
251		{
252		case LEFT:
253		case RIGHT:
254			getWindow()->setCursor(UI_CURSOR_SIZEWE);
255			break;
256
257		case TOP:
258		case BOTTOM:
259			getWindow()->setCursor(UI_CURSOR_SIZENS);
260			break;
261		}
262	}
263
264	return handled;
265} // end LLResizeBar::handleHover
266
267BOOL LLResizeBar::handleDoubleClick(S32 x, S32 y, MASK mask)
268{
269	LLRect orig_rect = mResizingView->getRect();
270	LLRect scaled_rect = orig_rect;
271
272	if (mSnappingEnabled && mAllowDoubleClickSnapping)
273	{
274		switch( mSide )
275		{
276		case LEFT:
277			mResizingView->findSnapEdge(scaled_rect.mLeft, LLCoordGL(0, 0), SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, S32_MAX);
278			scaled_rect.mLeft = scaled_rect.mRight - llclamp(scaled_rect.getWidth(), mMinSize, mMaxSize);
279			break;
280		case TOP:
281			mResizingView->findSnapEdge(scaled_rect.mTop, LLCoordGL(0, 0), SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, S32_MAX);
282			scaled_rect.mTop = scaled_rect.mBottom + llclamp(scaled_rect.getHeight(), mMinSize, mMaxSize);
283			break;
284		case RIGHT:
285			mResizingView->findSnapEdge(scaled_rect.mRight, LLCoordGL(0, 0), SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, S32_MAX);
286			scaled_rect.mRight = scaled_rect.mLeft + llclamp(scaled_rect.getWidth(), mMinSize, mMaxSize);
287			break;
288		case BOTTOM:
289			mResizingView->findSnapEdge(scaled_rect.mBottom, LLCoordGL(0, 0), SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, S32_MAX);
290			scaled_rect.mBottom = scaled_rect.mTop - llclamp(scaled_rect.getHeight(), mMinSize, mMaxSize);
291			break;
292		}
293
294		mResizingView->setShape(scaled_rect, true);
295	}
296
297	return TRUE;
298}
299