PageRenderTime 47ms CodeModel.GetById 17ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llhints.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 426 lines | 342 code | 47 blank | 37 comment | 24 complexity | 18cf510ce847ace020bddee34aab85ce MD5 | raw file
  1/**
  2 * @file llhints.cpp
  3 * @brief Hint popups for displaying context sensitive help in a UI overlay
  4 *
  5 * $LicenseInfo:firstyear=2000&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
 28#include "llviewerprecompiledheaders.h" // must be first include
 29
 30#include "llhints.h"
 31
 32#include "llbutton.h"
 33#include "lltextbox.h"
 34#include "llviewerwindow.h"
 35#include "llviewercontrol.h"
 36#include "lliconctrl.h"
 37#include "llsdparam.h"
 38
 39class LLHintPopup : public LLPanel
 40{
 41public:
 42
 43	typedef enum e_popup_direction
 44	{
 45		LEFT,
 46		TOP,
 47		RIGHT,
 48		BOTTOM,
 49		TOP_RIGHT
 50	} EPopupDirection;
 51
 52	struct PopupDirections : public LLInitParam::TypeValuesHelper<LLHintPopup::EPopupDirection, PopupDirections>
 53	{
 54		static void declareValues()
 55		{
 56			declare("left", LLHintPopup::LEFT);
 57			declare("right", LLHintPopup::RIGHT);
 58			declare("top", LLHintPopup::TOP);
 59			declare("bottom", LLHintPopup::BOTTOM);
 60			declare("top_right", LLHintPopup::TOP_RIGHT);
 61		}
 62	};
 63
 64	struct TargetParams : public LLInitParam::Block<TargetParams>
 65	{
 66		Mandatory<std::string>	target;
 67		Mandatory<EPopupDirection, PopupDirections> direction;
 68
 69		TargetParams()
 70		:	target("target"),
 71			direction("direction")
 72		{}
 73	};
 74
 75	struct Params : public LLInitParam::Block<Params, LLPanel::Params>
 76	{
 77		Mandatory<LLNotificationPtr>	notification;
 78		Optional<TargetParams>			target_params;
 79		Optional<S32>					distance;
 80		Optional<LLUIImage*>			left_arrow,
 81										up_arrow,
 82										right_arrow,
 83										down_arrow,
 84										lower_left_arrow,
 85										hint_image;
 86				
 87		Optional<S32>					left_arrow_offset,
 88										up_arrow_offset,
 89										right_arrow_offset,
 90										down_arrow_offset;
 91		Optional<F32>					fade_in_time,
 92										fade_out_time;
 93
 94		Params()
 95		:	distance("distance"),
 96			left_arrow("left_arrow"),
 97			up_arrow("up_arrow"),
 98			right_arrow("right_arrow"),
 99			down_arrow("down_arrow"),
100			lower_left_arrow("lower_left_arrow"),
101			hint_image("hint_image"),
102			left_arrow_offset("left_arrow_offset"),
103			up_arrow_offset("up_arrow_offset"),
104			right_arrow_offset("right_arrow_offset"),
105			down_arrow_offset("down_arrow_offset"),
106			fade_in_time("fade_in_time"),
107			fade_out_time("fade_out_time")
108		{}
109	};
110
111	LLHintPopup(const Params&);
112
113	/*virtual*/ BOOL postBuild();
114
115	void onClickClose() 
116	{ 
117		if (!mHidden) 
118		{
119			hide(); 
120			LLNotifications::instance().cancel(mNotification);
121		}
122	}
123	void draw();
124	void hide() { if(!mHidden) {mHidden = true; mFadeTimer.reset();} }
125
126private:
127	LLNotificationPtr	mNotification;
128	std::string			mTarget;
129	EPopupDirection		mDirection;
130	S32					mDistance;
131	LLUIImagePtr		mArrowLeft,
132						mArrowUp,
133						mArrowRight,
134						mArrowDown,
135						mArrowDownAndLeft;
136	S32					mArrowLeftOffset,
137						mArrowUpOffset,
138						mArrowRightOffset,
139						mArrowDownOffset;
140	LLFrameTimer		mFadeTimer;
141	F32					mFadeInTime,
142						mFadeOutTime;
143	bool				mHidden;
144};
145
146static LLDefaultChildRegistry::Register<LLHintPopup> r("hint_popup");
147
148
149LLHintPopup::LLHintPopup(const LLHintPopup::Params& p)
150:	mNotification(p.notification),
151	mDirection(TOP),
152	mDistance(p.distance),
153	mArrowLeft(p.left_arrow),
154	mArrowUp(p.up_arrow),
155	mArrowRight(p.right_arrow),
156	mArrowDown(p.down_arrow),
157	mArrowDownAndLeft(p.lower_left_arrow),
158	mArrowLeftOffset(p.left_arrow_offset),
159	mArrowUpOffset(p.up_arrow_offset),
160	mArrowRightOffset(p.right_arrow_offset),
161	mArrowDownOffset(p.down_arrow_offset),
162	mHidden(false),
163	mFadeInTime(p.fade_in_time),
164	mFadeOutTime(p.fade_out_time),
165	LLPanel(p)
166{
167	if (p.target_params.isProvided())
168	{
169		mDirection = p.target_params.direction;
170		mTarget = p.target_params.target;
171	}
172	if (p.hint_image.isProvided())
173	{
174		buildFromFile("panel_hint_image.xml", NULL, p);
175		getChild<LLIconCtrl>("hint_image")->setImage(p.hint_image());
176	}
177	else
178	{
179		buildFromFile( "panel_hint.xml", NULL, p);
180	}
181}
182
183BOOL LLHintPopup::postBuild()
184{
185	LLTextBox& hint_text = getChildRef<LLTextBox>("hint_text");
186	hint_text.setText(mNotification->getMessage());
187	
188	getChild<LLButton>("close")->setClickedCallback(boost::bind(&LLHintPopup::onClickClose, this));
189	getChild<LLTextBox>("hint_title")->setText(mNotification->getLabel());
190
191	LLRect text_bounds = hint_text.getTextBoundingRect();
192	S32 delta_height = text_bounds.getHeight() - hint_text.getRect().getHeight();
193	reshape(getRect().getWidth(), getRect().getHeight() + delta_height);
194	hint_text.reshape(hint_text.getRect().getWidth(), hint_text.getRect().getHeight() + delta_height);
195//	hint_text.translate(0, -delta_height);
196	return TRUE;
197}
198
199void LLHintPopup::draw()
200{
201	F32 alpha = 1.f;
202	if (mHidden)
203	{
204		alpha = clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, mFadeOutTime, 1.f, 0.f);
205		if (alpha == 0.f)
206		{
207			die();
208			return;
209		}
210	}
211	else
212	{
213		alpha = clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, mFadeInTime, 0.f, 1.f);
214	}
215	
216	LLIconCtrl* hint_icon = findChild<LLIconCtrl>("hint_image");
217
218	if (hint_icon)
219	{
220		LLUIImagePtr hint_image = hint_icon->getImage();
221		S32 image_height = hint_image.isNull() ? 0 : hint_image->getHeight();
222		S32 image_width = hint_image.isNull() ? 0 : hint_image->getWidth();
223
224		LLView* layout_stack = hint_icon->getParent()->getParent();
225		S32 delta_height = image_height - layout_stack->getRect().getHeight();
226		hint_icon->getParent()->reshape(image_width, hint_icon->getParent()->getRect().getHeight());
227		layout_stack->reshape(layout_stack->getRect().getWidth(), image_height);
228		layout_stack->translate(0, -delta_height);
229
230		LLRect hint_rect = getLocalRect();
231		reshape(hint_rect.getWidth(), hint_rect.getHeight() + delta_height);
232	}
233
234	{	LLViewDrawContext context(alpha); 
235
236		if (mTarget.empty())
237		{
238			// just draw contents, no arrow, in default position
239			LLPanel::draw();
240		}
241		else 
242		{
243			LLView* targetp = LLHints::getHintTarget(mTarget).get();
244			if (!targetp)
245			{
246				// target widget is no longer valid, go away
247				die();
248			}
249			else if (!targetp->isInVisibleChain()) 
250			{
251				// if target is invisible, don't draw, but keep alive in case widget comes back
252				// but do make it so that it allows mouse events to pass through
253				setEnabled(false);
254				setMouseOpaque(false);
255			}
256			else
257			{
258				// revert back enabled and mouse opaque state in case we disabled it before
259				setEnabled(true);
260				setMouseOpaque(true);
261
262				LLRect target_rect;
263				targetp->localRectToOtherView(targetp->getLocalRect(), &target_rect, getParent());
264
265				LLRect my_local_rect = getLocalRect();
266				LLRect my_rect;
267				LLRect arrow_rect;
268				LLUIImagePtr arrow_imagep;
269
270				switch(mDirection)
271				{
272				case LEFT:
273					my_rect.setCenterAndSize(	target_rect.mLeft - (my_local_rect.getWidth() / 2 + mDistance), 
274												target_rect.getCenterY(), 
275												my_local_rect.getWidth(), 
276												my_local_rect.getHeight());
277					if (mArrowRight)
278					{
279						arrow_rect.setCenterAndSize(my_local_rect.mRight + mArrowRight->getWidth() / 2 + mArrowRightOffset,
280													my_local_rect.getCenterY(),
281													mArrowRight->getWidth(), 
282													mArrowRight->getHeight());
283						arrow_imagep = mArrowRight;
284					}
285					break;
286				case TOP:
287					my_rect.setCenterAndSize(	target_rect.getCenterX(), 
288												target_rect.mTop + (my_local_rect.getHeight() / 2 + mDistance), 
289												my_local_rect.getWidth(), 
290												my_local_rect.getHeight());
291					if (mArrowDown)
292					{
293						arrow_rect.setCenterAndSize(my_local_rect.getCenterX(),
294													my_local_rect.mBottom - mArrowDown->getHeight() / 2 + mArrowDownOffset,
295													mArrowDown->getWidth(), 
296													mArrowDown->getHeight());
297						arrow_imagep = mArrowDown;
298					}
299					break;
300				case RIGHT:
301					my_rect.setCenterAndSize(	target_rect.mRight + (my_local_rect.getWidth() / 2 + mDistance), 
302												target_rect.getCenterY(),
303												my_local_rect.getWidth(), 
304												my_local_rect.getHeight());
305					if (mArrowLeft)
306					{
307						arrow_rect.setCenterAndSize(my_local_rect.mLeft - mArrowLeft->getWidth() / 2 + mArrowLeftOffset,
308													my_local_rect.getCenterY(),
309													mArrowLeft->getWidth(), 
310													mArrowLeft->getHeight());
311						arrow_imagep = mArrowLeft;
312					}
313					break;
314				case BOTTOM:
315					my_rect.setCenterAndSize(	target_rect.getCenterX(), 
316												target_rect.mBottom - (my_local_rect.getHeight() / 2 + mDistance),
317												my_local_rect.getWidth(), 
318												my_local_rect.getHeight());
319					if (mArrowUp)
320					{
321						arrow_rect.setCenterAndSize(my_local_rect.getCenterX(),
322													my_local_rect.mTop + mArrowUp->getHeight() / 2 + mArrowUpOffset,
323													mArrowUp->getWidth(), 
324													mArrowUp->getHeight());
325						arrow_imagep = mArrowUp;
326					}
327					break;
328				case TOP_RIGHT:
329					my_rect.setCenterAndSize(	target_rect.mRight + (my_local_rect.getWidth() / 2),
330												target_rect.mTop + (my_local_rect.getHeight() / 2 + mDistance),
331												my_local_rect.getWidth(), 
332												my_local_rect.getHeight());
333					if (mArrowDownAndLeft)
334					{
335						arrow_rect.setCenterAndSize(my_local_rect.mLeft + mArrowDownAndLeft->getWidth() / 2 + mArrowLeftOffset,
336													my_local_rect.mBottom - mArrowDownAndLeft->getHeight() / 2 + mArrowDownOffset,
337													mArrowDownAndLeft->getWidth(), 
338													mArrowDownAndLeft->getHeight());
339						arrow_imagep = mArrowDownAndLeft;
340					}
341				}
342				setShape(my_rect);
343				LLPanel::draw();
344
345				if (arrow_imagep) arrow_imagep->draw(arrow_rect, LLColor4(1.f, 1.f, 1.f, alpha));
346			}
347		}
348	}
349}
350
351
352LLRegistry<std::string, LLHandle<LLView> > LLHints::sTargetRegistry;
353std::map<LLNotificationPtr, class LLHintPopup*> LLHints::sHints;
354
355//static
356void LLHints::show(LLNotificationPtr hint)
357{
358	LLHintPopup::Params p(LLUICtrlFactory::getDefaultParams<LLHintPopup>());
359
360	LLParamSDParser parser;
361	parser.readSD(hint->getPayload(), p, true);
362	p.notification = hint;
363
364	if (p.validateBlock())
365	{
366		LLHintPopup* popup = new LLHintPopup(p);
367
368		sHints[hint] = popup;
369
370		LLView* hint_holder = gViewerWindow->getHintHolder();
371		if (hint_holder)
372		{
373			hint_holder->addChild(popup);
374			popup->centerWithin(hint_holder->getLocalRect());
375		}
376	}
377}
378
379//static
380void LLHints::hide(LLNotificationPtr hint)
381{
382	hint_map_t::iterator found_it = sHints.find(hint);
383	if (found_it != sHints.end())
384	{
385		found_it->second->hide();
386		sHints.erase(found_it);
387	}
388}
389
390//static
391void LLHints::registerHintTarget(const std::string& name, LLHandle<LLView> target)
392{
393	sTargetRegistry.defaultRegistrar().replace(name, target);
394}
395
396//static 
397LLHandle<LLView> LLHints::getHintTarget(const std::string& name)
398{
399	LLHandle<LLView>* handlep = sTargetRegistry.getValue(name);
400	if (handlep) 
401	{
402		return *handlep;
403	}
404	else
405	{
406		return LLHandle<LLView>();
407	}
408}
409
410//static
411void LLHints::initClass()
412{
413	sRegister.reference();
414
415	LLControlVariablePtr control = gSavedSettings.getControl("EnableUIHints");
416	control->getSignal()->connect(boost::bind(&showHints, _2));
417	gViewerWindow->getHintHolder()->setVisible(control->getValue().asBoolean());
418
419}
420
421//staic
422void LLHints::showHints(const LLSD& show)
423{
424	bool visible = show.asBoolean();
425	gViewerWindow->getHintHolder()->setVisible(visible);
426}