PageRenderTime 25ms CodeModel.GetById 2ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llui/lldraghandle.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 386 lines | 215 code | 56 blank | 115 comment | 14 complexity | 2bacc5d9dfe5c66903373c2fc719a542 MD5 | raw file
  1/** 
  2 * @file lldraghandle.cpp
  3 * @brief LLDragHandle 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// A widget for dragging a view around the screen using the mouse.
 28
 29#include "linden_common.h"
 30
 31#include "lldraghandle.h"
 32
 33#include "llmath.h"
 34
 35//#include "llviewerwindow.h"
 36#include "llui.h"
 37#include "llmenugl.h"
 38#include "lltextbox.h"
 39#include "llcontrol.h"
 40#include "llfontgl.h"
 41#include "llwindow.h"
 42#include "llfocusmgr.h"
 43#include "lluictrlfactory.h"
 44
 45const S32 LEADING_PAD = 5;
 46const S32 TITLE_HPAD = 8;
 47const S32 BORDER_PAD = 1;
 48const S32 LEFT_PAD = BORDER_PAD + TITLE_HPAD + LEADING_PAD;
 49const S32 RIGHT_PAD = BORDER_PAD + 32; // HACK: space for close btn and minimize btn
 50
 51S32 LLDragHandle::sSnapMargin = 5;
 52
 53LLDragHandle::LLDragHandle(const LLDragHandle::Params& p)
 54:	LLView(p),
 55	mDragLastScreenX( 0 ),
 56	mDragLastScreenY( 0 ),
 57	mLastMouseScreenX( 0 ),
 58	mLastMouseScreenY( 0 ),
 59	mTitleBox( NULL ),
 60	mMaxTitleWidth( 0 ),
 61	mForeground( TRUE ),
 62	mDragHighlightColor(p.drag_highlight_color()),
 63	mDragShadowColor(p.drag_shadow_color())
 64
 65{
 66	static LLUICachedControl<S32> snap_margin ("SnapMargin", 0);
 67	sSnapMargin = snap_margin;
 68}
 69
 70LLDragHandle::~LLDragHandle()
 71{
 72	removeChild(mTitleBox);
 73	delete mTitleBox;
 74}
 75
 76void LLDragHandle::initFromParams(const LLDragHandle::Params& p)
 77{
 78	LLView::initFromParams(p);
 79	setTitle( p.label );
 80}
 81
 82void LLDragHandle::setTitleVisible(BOOL visible) 
 83{ 
 84	if(mTitleBox)
 85	{
 86		mTitleBox->setVisible(visible); 
 87	}
 88}
 89
 90void LLDragHandleTop::setTitle(const std::string& title)
 91{
 92	std::string trimmed_title = title;
 93	LLStringUtil::trim(trimmed_title);
 94
 95	if( mTitleBox )
 96	{
 97		mTitleBox->setText(trimmed_title);
 98	}
 99	else
100	{
101		const LLFontGL* font = LLFontGL::getFontSansSerif();
102		LLTextBox::Params params;
103		params.name("Drag Handle Title");
104		params.rect(getRect());
105		params.initial_value(trimmed_title);
106		params.font(font);
107		params.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT | FOLLOWS_RIGHT);
108		params.font_shadow(LLFontGL::DROP_SHADOW_SOFT);
109		params.use_ellipses = true;
110		params.parse_urls = false; //cancel URL replacement in floater title
111		mTitleBox = LLUICtrlFactory::create<LLTextBox> (params);
112		addChild( mTitleBox );
113	}
114	
115	reshapeTitleBox();
116}
117
118
119std::string LLDragHandleTop::getTitle() const
120{
121	return mTitleBox == NULL ? LLStringUtil::null : mTitleBox->getText();
122}
123
124
125void LLDragHandleLeft::setTitle(const std::string& )
126{
127	if( mTitleBox )
128	{
129		removeChild(mTitleBox);
130		delete mTitleBox;
131		mTitleBox = NULL;
132	}
133	/* no title on left edge */
134}
135
136
137std::string LLDragHandleLeft::getTitle() const
138{
139	return LLStringUtil::null;
140}
141
142
143void LLDragHandleTop::draw()
144{
145	/* Disable lines.  Can drag anywhere in most windows.  JC
146	if( getVisible() && getEnabled() && mForeground) 
147	{
148		const S32 BORDER_PAD = 2;
149		const S32 HPAD = 2;
150		const S32 VPAD = 2;
151		S32 left = BORDER_PAD + HPAD;
152		S32 top = getRect().getHeight() - 2 * VPAD;
153		S32 right = getRect().getWidth() - HPAD;
154//		S32 bottom = VPAD;
155
156		// draw lines for drag areas
157
158		const S32 LINE_SPACING = (DRAG_HANDLE_HEIGHT - 2 * VPAD) / 4;
159		S32 line = top - LINE_SPACING;
160
161		LLRect title_rect = mTitleBox->getRect();
162		S32 title_right = title_rect.mLeft + mTitleWidth;
163		BOOL show_right_side = title_right < getRect().getWidth();
164
165		for( S32 i=0; i<4; i++ )
166		{
167			gl_line_2d(left, line+1, title_rect.mLeft - LEADING_PAD, line+1, mDragHighlightColor);
168			if( show_right_side )
169			{
170				gl_line_2d(title_right, line+1, right, line+1, mDragHighlightColor);
171			}
172
173			gl_line_2d(left, line, title_rect.mLeft - LEADING_PAD, line, mDragShadowColor);
174			if( show_right_side )
175			{
176				gl_line_2d(title_right, line, right, line, mDragShadowColor);
177			}
178			line -= LINE_SPACING;
179		}
180	}
181	*/
182
183	// Colorize the text to match the frontmost state
184	if (mTitleBox)
185	{
186		mTitleBox->setEnabled(getForeground());
187	}
188
189	LLView::draw();
190}
191
192
193// assumes GL state is set for 2D
194void LLDragHandleLeft::draw()
195{
196	/* Disable lines.  Can drag anywhere in most windows. JC
197	if( getVisible() && getEnabled() && mForeground ) 
198	{
199		const S32 BORDER_PAD = 2;
200//		const S32 HPAD = 2;
201		const S32 VPAD = 2;
202		const S32 LINE_SPACING = 3;
203
204		S32 left = BORDER_PAD + LINE_SPACING;
205		S32 top = getRect().getHeight() - 2 * VPAD;
206//		S32 right = getRect().getWidth() - HPAD;
207		S32 bottom = VPAD;
208 
209		// draw lines for drag areas
210
211		// no titles yet
212		//LLRect title_rect = mTitleBox->getRect();
213		//S32 title_right = title_rect.mLeft + mTitleWidth;
214		//BOOL show_right_side = title_right < getRect().getWidth();
215
216		S32 line = left;
217		for( S32 i=0; i<4; i++ )
218		{
219			gl_line_2d(line, top, line, bottom, mDragHighlightColor);
220
221			gl_line_2d(line+1, top, line+1, bottom, mDragShadowColor);
222
223			line += LINE_SPACING;
224		}
225	}
226	*/
227
228	// Colorize the text to match the frontmost state
229	if (mTitleBox)
230	{
231		mTitleBox->setEnabled(getForeground());
232	}
233
234	LLView::draw();
235}
236
237void LLDragHandleTop::reshapeTitleBox()
238{
239	static LLUICachedControl<S32> title_vpad("UIFloaterTitleVPad", 0);
240	if( ! mTitleBox)
241	{
242		return;
243	}
244	const LLFontGL* font = LLFontGL::getFontSansSerif();
245	S32 title_width = getRect().getWidth();
246	title_width -= LEFT_PAD + 2 * BORDER_PAD + getButtonsRect().getWidth();
247	S32 title_height = llround(font->getLineHeight());
248	LLRect title_rect;
249	title_rect.setLeftTopAndSize( 
250		LEFT_PAD, 
251		getRect().getHeight() - title_vpad,
252		title_width,
253		title_height);
254
255	// calls reshape on mTitleBox
256	mTitleBox->setShape( title_rect );
257}
258
259void LLDragHandleTop::reshape(S32 width, S32 height, BOOL called_from_parent)
260{
261	LLView::reshape(width, height, called_from_parent);
262	reshapeTitleBox();
263}
264
265void LLDragHandleLeft::reshape(S32 width, S32 height, BOOL called_from_parent)
266{
267	LLView::reshape(width, height, called_from_parent);
268}
269
270//-------------------------------------------------------------
271// UI event handling
272//-------------------------------------------------------------
273
274BOOL LLDragHandle::handleMouseDown(S32 x, S32 y, MASK mask)
275{
276	// Route future Mouse messages here preemptively.  (Release on mouse up.)
277	// No handler needed for focus lost since this clas has no state that depends on it.
278	gFocusMgr.setMouseCapture(this);
279
280	localPointToScreen(x, y, &mDragLastScreenX, &mDragLastScreenY);
281	mLastMouseScreenX = mDragLastScreenX;
282	mLastMouseScreenY = mDragLastScreenY;
283
284	// Note: don't pass on to children
285	return TRUE;
286}
287
288
289BOOL LLDragHandle::handleMouseUp(S32 x, S32 y, MASK mask)
290{
291	if( hasMouseCapture() )
292	{
293		// Release the mouse
294		gFocusMgr.setMouseCapture( NULL );
295	}
296
297	// Note: don't pass on to children
298	return TRUE;
299}
300
301
302BOOL LLDragHandle::handleHover(S32 x, S32 y, MASK mask)
303{
304	BOOL	handled = FALSE;
305
306	// We only handle the click if the click both started and ended within us
307	if( hasMouseCapture() )
308	{
309		S32 screen_x;
310		S32 screen_y;
311		localPointToScreen(x, y, &screen_x, &screen_y);
312
313		// Resize the parent
314		S32 delta_x = screen_x - mDragLastScreenX;
315		S32 delta_y = screen_y - mDragLastScreenY;
316
317		// if dragging a docked floater we want to undock
318		if (((LLFloater*)getParent())->isDocked())
319		{
320			const S32 SLOP = 12;
321
322			if (delta_y <= -SLOP || 
323				delta_y >= SLOP)
324			{
325				((LLFloater*)getParent())->setDocked(false, false);
326				return TRUE;
327			}
328			else
329			{
330				return FALSE;
331			}
332		}
333
334		LLRect original_rect = getParent()->getRect();
335		LLRect translated_rect = getParent()->getRect();
336		translated_rect.translate(delta_x, delta_y);
337		// temporarily slam dragged window to new position
338		getParent()->setRect(translated_rect);
339		S32 pre_snap_x = getParent()->getRect().mLeft;
340		S32 pre_snap_y = getParent()->getRect().mBottom;
341		mDragLastScreenX = screen_x;
342		mDragLastScreenY = screen_y;
343
344		LLRect new_rect;
345		LLCoordGL mouse_dir;
346		// use hysteresis on mouse motion to preserve user intent when mouse stops moving
347		mouse_dir.mX = (screen_x == mLastMouseScreenX) ? mLastMouseDir.mX : screen_x - mLastMouseScreenX;
348		mouse_dir.mY = (screen_y == mLastMouseScreenY) ? mLastMouseDir.mY : screen_y - mLastMouseScreenY;
349		mLastMouseDir = mouse_dir;
350		mLastMouseScreenX = screen_x;
351		mLastMouseScreenY = screen_y;
352
353		LLView* snap_view = getParent()->findSnapRect(new_rect, mouse_dir, SNAP_PARENT_AND_SIBLINGS, sSnapMargin);
354
355		getParent()->setSnappedTo(snap_view);
356		delta_x = new_rect.mLeft - pre_snap_x;
357		delta_y = new_rect.mBottom - pre_snap_y;
358		translated_rect.translate(delta_x, delta_y);
359
360		// restore original rect so delta are detected, then call user reshape method to handle snapped floaters, etc
361		getParent()->setRect(original_rect);
362		getParent()->setShape(translated_rect, true);
363
364		mDragLastScreenX += delta_x;
365		mDragLastScreenY += delta_y;
366
367		getWindow()->setCursor(UI_CURSOR_ARROW);
368		lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" <<llendl;		
369		handled = TRUE;
370	}
371	else
372	{
373		getWindow()->setCursor(UI_CURSOR_ARROW);
374		lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl;		
375		handled = TRUE;
376	}
377
378	// Note: don't pass on to children
379
380	return handled;
381}
382
383void LLDragHandle::setValue(const LLSD& value)
384{
385	setTitle(value.asString());
386}