PageRenderTime 32ms CodeModel.GetById 11ms app.highlight 17ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/llui/llmodaldialog.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 306 lines | 212 code | 40 blank | 54 comment | 27 complexity | c51aac01fcd2d6dc0a03c452fde5a80a MD5 | raw file
  1/** 
  2 * @file llmodaldialog.cpp
  3 * @brief LLModalDialog base class
  4 *
  5 * $LicenseInfo:firstyear=2002&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 "llmodaldialog.h"
 30
 31#include "llfocusmgr.h"
 32#include "v4color.h"
 33#include "v2math.h"
 34#include "llui.h"
 35#include "llwindow.h"
 36#include "llkeyboard.h"
 37
 38// static
 39std::list<LLModalDialog*> LLModalDialog::sModalStack;
 40
 41LLModalDialog::LLModalDialog( const LLSD& key, BOOL modal )
 42	: LLFloater(key),
 43	  mModal( modal )
 44{
 45	if (modal)
 46	{
 47		setCanMinimize(FALSE);
 48		setCanClose(FALSE);
 49	}
 50	setVisible( FALSE );
 51	setBackgroundVisible(TRUE);
 52	setBackgroundOpaque(TRUE);
 53	centerOnScreen(); // default position
 54	mCloseSignal.connect(boost::bind(&LLModalDialog::stopModal, this));
 55}
 56
 57LLModalDialog::~LLModalDialog()
 58{
 59	// don't unlock focus unless we have it
 60	if (gFocusMgr.childHasKeyboardFocus(this))
 61	{
 62		gFocusMgr.unlockFocus();
 63	}
 64	
 65	std::list<LLModalDialog*>::iterator iter = std::find(sModalStack.begin(), sModalStack.end(), this);
 66	if (iter != sModalStack.end())
 67	{
 68		llerrs << "Attempt to delete dialog while still in sModalStack!" << llendl;
 69	}
 70}
 71
 72// virtual
 73BOOL LLModalDialog::postBuild()
 74{
 75	return LLFloater::postBuild();
 76}
 77
 78// virtual
 79void LLModalDialog::openFloater(const LLSD& key)
 80{
 81	// SJB: Hack! Make sure we don't ever host a modal dialog
 82	LLMultiFloater* thost = LLFloater::getFloaterHost();
 83	LLFloater::setFloaterHost(NULL);
 84	LLFloater::openFloater(key);
 85	LLFloater::setFloaterHost(thost);
 86}
 87
 88void LLModalDialog::reshape(S32 width, S32 height, BOOL called_from_parent)
 89{
 90	LLFloater::reshape(width, height, called_from_parent);
 91	centerOnScreen();
 92}
 93
 94// virtual
 95void LLModalDialog::onOpen(const LLSD& key)
 96{
 97	if (mModal)
 98	{
 99		// If Modal, Hide the active modal dialog
100		if (!sModalStack.empty())
101		{
102			LLModalDialog* front = sModalStack.front();
103			front->setVisible(FALSE);
104		}
105	
106		// This is a modal dialog.  It sucks up all mouse and keyboard operations.
107		gFocusMgr.setMouseCapture( this );
108		LLUI::addPopup(this);
109		setFocus(TRUE);
110
111		sModalStack.push_front( this );
112	}
113}
114
115void LLModalDialog::stopModal()
116{
117	gFocusMgr.unlockFocus();
118	gFocusMgr.releaseFocusIfNeeded( this );
119
120	if (mModal)
121	{
122		std::list<LLModalDialog*>::iterator iter = std::find(sModalStack.begin(), sModalStack.end(), this);
123		if (iter != sModalStack.end())
124		{
125			sModalStack.erase(iter);
126		}
127		else
128		{
129			llwarns << "LLModalDialog::stopModal not in list!" << llendl;
130		}
131	}
132	if (!sModalStack.empty())
133	{
134		LLModalDialog* front = sModalStack.front();
135		front->setVisible(TRUE);
136	}
137}
138
139
140void LLModalDialog::setVisible( BOOL visible )
141{
142	if (mModal)
143	{
144		if( visible )
145		{
146			// This is a modal dialog.  It sucks up all mouse and keyboard operations.
147			gFocusMgr.setMouseCapture( this );
148
149			// The dialog view is a root view
150			LLUI::addPopup(this);
151			setFocus( TRUE );
152		}
153		else
154		{
155			gFocusMgr.releaseFocusIfNeeded( this );
156		}
157	}
158	
159	LLFloater::setVisible( visible );
160}
161
162BOOL LLModalDialog::handleMouseDown(S32 x, S32 y, MASK mask)
163{
164	if (mModal)
165	{
166		if (!LLFloater::handleMouseDown(x, y, mask))
167		{
168			// Click was outside the panel
169			make_ui_sound("UISndInvalidOp");
170		}
171	}
172	else
173	{
174		LLFloater::handleMouseDown(x, y, mask);
175	}
176	return TRUE;
177}
178
179BOOL LLModalDialog::handleHover(S32 x, S32 y, MASK mask)		
180{ 
181	if( childrenHandleHover(x, y, mask) == NULL )
182	{
183		getWindow()->setCursor(UI_CURSOR_ARROW);
184		lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;		
185	}
186	return TRUE;
187}
188
189BOOL LLModalDialog::handleMouseUp(S32 x, S32 y, MASK mask)
190{
191	childrenHandleMouseUp(x, y, mask);
192	return TRUE;
193}
194
195BOOL LLModalDialog::handleScrollWheel(S32 x, S32 y, S32 clicks)
196{
197	childrenHandleScrollWheel(x, y, clicks);
198	return TRUE;
199}
200
201BOOL LLModalDialog::handleDoubleClick(S32 x, S32 y, MASK mask)
202{
203	if (!LLFloater::handleDoubleClick(x, y, mask))
204	{
205		// Click outside the panel
206		make_ui_sound("UISndInvalidOp");
207	}
208	return TRUE;
209}
210
211BOOL LLModalDialog::handleRightMouseDown(S32 x, S32 y, MASK mask)
212{
213	childrenHandleRightMouseDown(x, y, mask);
214	return TRUE;
215}
216
217
218BOOL LLModalDialog::handleKeyHere(KEY key, MASK mask )
219{
220	LLFloater::handleKeyHere(key, mask );
221
222	if (mModal)
223	{
224		// Suck up all keystokes except CTRL-Q.
225		BOOL is_quit = ('Q' == key) && (MASK_CONTROL == mask);
226		return !is_quit;
227	}
228	else
229	{
230		// don't process escape key until message box has been on screen a minimal amount of time
231		// to avoid accidentally destroying the message box when user is hitting escape at the time it appears
232		BOOL enough_time_elapsed = mVisibleTime.getElapsedTimeF32() > 1.0f;
233		if (enough_time_elapsed && key == KEY_ESCAPE)
234		{
235			closeFloater();
236			return TRUE;
237		}
238		return FALSE;
239	}	
240}
241
242// virtual
243void LLModalDialog::draw()
244{
245	static LLUIColor shadow_color = LLUIColorTable::instance().getColor("ColorDropShadow");
246	static LLUICachedControl<S32> shadow_lines ("DropShadowFloater", 0);
247
248	gl_drop_shadow( 0, getRect().getHeight(), getRect().getWidth(), 0,
249		shadow_color, shadow_lines);
250
251	LLFloater::draw();
252	
253	// Focus retrieval moved to LLFloaterView::refresh()
254}
255
256void LLModalDialog::centerOnScreen()
257{
258	LLVector2 window_size = LLUI::getWindowSize();
259	centerWithin(LLRect(0, 0, llround(window_size.mV[VX]), llround(window_size.mV[VY])));
260}
261
262
263// static 
264void LLModalDialog::onAppFocusLost()
265{
266	if( !sModalStack.empty() )
267	{
268		LLModalDialog* instance = LLModalDialog::sModalStack.front();
269		if( gFocusMgr.childHasMouseCapture( instance ) )
270		{
271			gFocusMgr.setMouseCapture( NULL );
272		}
273
274		instance->setFocus(FALSE);
275	}
276}
277
278// static 
279void LLModalDialog::onAppFocusGained()
280{
281	if( !sModalStack.empty() )
282	{
283		LLModalDialog* instance = LLModalDialog::sModalStack.front();
284
285		// This is a modal dialog.  It sucks up all mouse and keyboard operations.
286		gFocusMgr.setMouseCapture( instance );
287		instance->setFocus(TRUE);
288		LLUI::addPopup(instance);
289
290		instance->centerOnScreen();
291	}
292}
293
294void LLModalDialog::shutdownModals()
295{
296	// This method is only for use during app shutdown. ~LLModalDialog()
297	// checks sModalStack, and if the dialog instance is still there, it
298	// crumps with "Attempt to delete dialog while still in sModalStack!" But
299	// at app shutdown, all bets are off. If the user asks to shut down the
300	// app, we shouldn't have to care WHAT's open. Put differently, if a modal
301	// dialog is so crucial that we can't let the user terminate until s/he
302	// addresses it, we should reject a termination request. The current state
303	// of affairs is that we accept it, but then produce an llerrs popup that
304	// simply makes our software look unreliable.
305	sModalStack.clear();
306}