PageRenderTime 100ms CodeModel.GetById 32ms app.highlight 60ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/llui/lluictrl.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1062 lines | 845 code | 121 blank | 96 comment | 123 complexity | f16a4a490656e264caf104206161c97a MD5 | raw file
   1/** 
   2 * @file lluictrl.cpp
   3 * @author James Cook, Richard Nelson, Tom Yedwab
   4 * @brief Abstract base class for UI controls
   5 *
   6 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
   7 * Second Life Viewer Source Code
   8 * Copyright (C) 2010, Linden Research, Inc.
   9 * 
  10 * This library is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU Lesser General Public
  12 * License as published by the Free Software Foundation;
  13 * version 2.1 of the License only.
  14 * 
  15 * This library is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18 * Lesser General Public License for more details.
  19 * 
  20 * You should have received a copy of the GNU Lesser General Public
  21 * License along with this library; if not, write to the Free Software
  22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  23 * 
  24 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  25 * $/LicenseInfo$
  26 */
  27
  28#include "linden_common.h"
  29
  30#define LLUICTRL_CPP
  31#include "lluictrl.h"
  32
  33#include "llfocusmgr.h"
  34#include "llpanel.h"
  35#include "lluictrlfactory.h"
  36
  37static LLDefaultChildRegistry::Register<LLUICtrl> r("ui_ctrl");
  38
  39F32 LLUICtrl::sActiveControlTransparency = 1.0f;
  40F32 LLUICtrl::sInactiveControlTransparency = 1.0f;
  41
  42// Compiler optimization, generate extern template
  43template class LLUICtrl* LLView::getChild<class LLUICtrl>(
  44	const std::string& name, BOOL recurse) const;
  45
  46LLUICtrl::CallbackParam::CallbackParam()
  47:	name("name"),
  48	function_name("function"),
  49	parameter("parameter"),
  50	control_name("control") // Shortcut to control -> "control_name" for backwards compatability			
  51{
  52	addSynonym(parameter, "userdata");
  53}
  54
  55LLUICtrl::EnableControls::EnableControls()
  56:	enabled("enabled_control"),
  57	disabled("disabled_control")
  58{}
  59
  60LLUICtrl::ControlVisibility::ControlVisibility()
  61:	visible("visibility_control"),
  62	invisible("invisibility_control")
  63{
  64	addSynonym(visible, "visiblity_control");
  65	addSynonym(invisible, "invisiblity_control");
  66}
  67
  68LLUICtrl::Params::Params()
  69:	tab_stop("tab_stop", true),
  70	chrome("chrome", false),
  71	requests_front("requests_front", false),
  72	label("label"),
  73	initial_value("value"),
  74	init_callback("init_callback"),
  75	commit_callback("commit_callback"),
  76	validate_callback("validate_callback"),
  77	mouseenter_callback("mouseenter_callback"),
  78	mouseleave_callback("mouseleave_callback"),
  79	control_name("control_name"),
  80	font("font", LLFontGL::getFontSansSerif()),
  81	font_halign("halign"),
  82	font_valign("valign"),
  83	length("length"), 	// ignore LLXMLNode cruft
  84	type("type")   		// ignore LLXMLNode cruft
  85{
  86	addSynonym(initial_value, "initial_value");
  87}
  88
  89// NOTE: the LLFocusableElement implementation has been moved from here to llfocusmgr.cpp.
  90
  91//static 
  92const LLUICtrl::Params& LLUICtrl::getDefaultParams()
  93{
  94	return LLUICtrlFactory::getDefaultParams<LLUICtrl>();
  95}
  96
  97
  98LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel) 
  99:	LLView(p),
 100	mIsChrome(FALSE),
 101	mRequestsFront(p.requests_front),
 102	mTabStop(FALSE),
 103	mTentative(FALSE),
 104    mViewModel(viewmodel),
 105	mControlVariable(NULL),
 106	mEnabledControlVariable(NULL),
 107	mDisabledControlVariable(NULL),
 108	mMakeVisibleControlVariable(NULL),
 109	mMakeInvisibleControlVariable(NULL),
 110	mCommitSignal(NULL),
 111	mValidateSignal(NULL),
 112	mMouseEnterSignal(NULL),
 113	mMouseLeaveSignal(NULL),
 114	mMouseDownSignal(NULL),
 115	mMouseUpSignal(NULL),
 116	mRightMouseDownSignal(NULL),
 117	mRightMouseUpSignal(NULL),
 118	mDoubleClickSignal(NULL),
 119	mTransparencyType(TT_DEFAULT)
 120{
 121}
 122
 123void LLUICtrl::initFromParams(const Params& p)
 124{
 125	LLView::initFromParams(p);
 126
 127	mRequestsFront = p.requests_front;
 128
 129	setIsChrome(p.chrome);
 130	setControlName(p.control_name);
 131	if(p.enabled_controls.isProvided())
 132	{
 133		if (p.enabled_controls.enabled.isChosen())
 134		{
 135			LLControlVariable* control = findControl(p.enabled_controls.enabled);
 136			if (control)
 137				setEnabledControlVariable(control);
 138		}
 139		else if(p.enabled_controls.disabled.isChosen())
 140		{
 141			LLControlVariable* control = findControl(p.enabled_controls.disabled);
 142			if (control)
 143				setDisabledControlVariable(control);
 144		}
 145	}
 146	if(p.controls_visibility.isProvided())
 147	{
 148		if (p.controls_visibility.visible.isChosen())
 149		{
 150			LLControlVariable* control = findControl(p.controls_visibility.visible);
 151			if (control)
 152				setMakeVisibleControlVariable(control);
 153		}
 154		else if (p.controls_visibility.invisible.isChosen())
 155		{
 156			LLControlVariable* control = findControl(p.controls_visibility.invisible);
 157			if (control)
 158				setMakeInvisibleControlVariable(control);
 159		}
 160	}
 161
 162	setTabStop(p.tab_stop);
 163
 164	if (p.initial_value.isProvided() 
 165		&& !p.control_name.isProvided())
 166	{
 167        setValue(p.initial_value);
 168	}
 169	
 170	if (p.commit_callback.isProvided())
 171	{
 172		setCommitCallback(initCommitCallback(p.commit_callback));
 173	}
 174	
 175	if (p.validate_callback.isProvided())
 176	{
 177		setValidateCallback(initEnableCallback(p.validate_callback));
 178	}
 179	
 180	if (p.init_callback.isProvided())
 181	{
 182		if (p.init_callback.function.isProvided())
 183		{
 184			p.init_callback.function()(this, p.init_callback.parameter);
 185		}
 186		else
 187		{
 188			commit_callback_t* initfunc = (CommitCallbackRegistry::getValue(p.init_callback.function_name));
 189			if (initfunc)
 190			{
 191				(*initfunc)(this, p.init_callback.parameter);
 192			}
 193		}
 194	}
 195
 196	if(p.mouseenter_callback.isProvided())
 197	{
 198		setMouseEnterCallback(initCommitCallback(p.mouseenter_callback));
 199	}
 200
 201	if(p.mouseleave_callback.isProvided())
 202	{
 203		setMouseLeaveCallback(initCommitCallback(p.mouseleave_callback));
 204	}
 205}
 206
 207
 208LLUICtrl::~LLUICtrl()
 209{
 210	gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit()
 211
 212	if( gFocusMgr.getTopCtrl() == this )
 213	{
 214		llwarns << "UI Control holding top ctrl deleted: " << getName() << ".  Top view removed." << llendl;
 215		gFocusMgr.removeTopCtrlWithoutCallback( this );
 216	}
 217
 218	delete mCommitSignal;
 219	delete mValidateSignal;
 220	delete mMouseEnterSignal;
 221	delete mMouseLeaveSignal;
 222	delete mMouseDownSignal;
 223	delete mMouseUpSignal;
 224	delete mRightMouseDownSignal;
 225	delete mRightMouseUpSignal;
 226	delete mDoubleClickSignal;
 227}
 228
 229void default_commit_handler(LLUICtrl* ctrl, const LLSD& param)
 230{}
 231
 232bool default_enable_handler(LLUICtrl* ctrl, const LLSD& param)
 233{
 234	return true;
 235}
 236
 237
 238LLUICtrl::commit_signal_t::slot_type LLUICtrl::initCommitCallback(const CommitCallbackParam& cb)
 239{
 240	if (cb.function.isProvided())
 241	{
 242		if (cb.parameter.isProvided())
 243			return boost::bind(cb.function(), _1, cb.parameter);
 244		else
 245			return cb.function();
 246	}
 247	else
 248	{
 249		std::string function_name = cb.function_name;
 250		commit_callback_t* func = (CommitCallbackRegistry::getValue(function_name));
 251		if (func)
 252		{
 253			if (cb.parameter.isProvided())
 254				return boost::bind((*func), _1, cb.parameter);
 255			else
 256				return commit_signal_t::slot_type(*func);
 257		}
 258		else if (!function_name.empty())
 259		{
 260			llwarns << "No callback found for: '" << function_name << "' in control: " << getName() << llendl;
 261		}			
 262	}
 263	return default_commit_handler;
 264}
 265
 266LLUICtrl::enable_signal_t::slot_type LLUICtrl::initEnableCallback(const EnableCallbackParam& cb)
 267{
 268	// Set the callback function
 269	if (cb.function.isProvided())
 270	{
 271		if (cb.parameter.isProvided())
 272			return boost::bind(cb.function(), this, cb.parameter);
 273		else
 274			return cb.function();
 275	}
 276	else
 277	{
 278		enable_callback_t* func = (EnableCallbackRegistry::getValue(cb.function_name));
 279		if (func)
 280		{
 281			if (cb.parameter.isProvided())
 282				return boost::bind((*func), this, cb.parameter);
 283			else
 284				return enable_signal_t::slot_type(*func);
 285		}
 286	}
 287	return default_enable_handler;
 288}
 289
 290// virtual
 291void LLUICtrl::onMouseEnter(S32 x, S32 y, MASK mask)
 292{
 293	if (mMouseEnterSignal)
 294	{
 295		(*mMouseEnterSignal)(this, getValue());
 296	}
 297}
 298
 299// virtual
 300void LLUICtrl::onMouseLeave(S32 x, S32 y, MASK mask)
 301{
 302	if(mMouseLeaveSignal)
 303	{
 304		(*mMouseLeaveSignal)(this, getValue());
 305	}
 306}
 307
 308//virtual 
 309BOOL LLUICtrl::handleMouseDown(S32 x, S32 y, MASK mask)
 310{
 311	BOOL handled  = LLView::handleMouseDown(x,y,mask);
 312	if (mMouseDownSignal)
 313	{
 314		(*mMouseDownSignal)(this,x,y,mask);
 315	}
 316	return handled;
 317}
 318
 319//virtual
 320BOOL LLUICtrl::handleMouseUp(S32 x, S32 y, MASK mask)
 321{
 322	BOOL handled  = LLView::handleMouseUp(x,y,mask);
 323	if (mMouseUpSignal)
 324	{
 325		(*mMouseUpSignal)(this,x,y,mask);
 326	}
 327	return handled;
 328}
 329
 330//virtual
 331BOOL LLUICtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
 332{
 333	BOOL handled  = LLView::handleRightMouseDown(x,y,mask);
 334	if (mRightMouseDownSignal)
 335	{
 336		(*mRightMouseDownSignal)(this,x,y,mask);
 337	}
 338	return handled;
 339}
 340
 341//virtual
 342BOOL LLUICtrl::handleRightMouseUp(S32 x, S32 y, MASK mask)
 343{
 344	BOOL handled  = LLView::handleRightMouseUp(x,y,mask);
 345	if(mRightMouseUpSignal)
 346	{
 347		(*mRightMouseUpSignal)(this,x,y,mask);
 348	}
 349	return handled;
 350}
 351
 352BOOL LLUICtrl::handleDoubleClick(S32 x, S32 y, MASK mask)
 353{
 354	BOOL handled = LLView::handleDoubleClick(x, y, mask);
 355	if (mDoubleClickSignal)
 356	{
 357		(*mDoubleClickSignal)(this, x, y, mask);
 358	}
 359	return handled;
 360}
 361
 362// can't tab to children of a non-tab-stop widget
 363BOOL LLUICtrl::canFocusChildren() const
 364{
 365	return hasTabStop();
 366}
 367
 368
 369void LLUICtrl::onCommit()
 370{
 371	if (mCommitSignal)
 372	(*mCommitSignal)(this, getValue());
 373}
 374
 375//virtual
 376BOOL LLUICtrl::isCtrl() const
 377{
 378	return TRUE;
 379}
 380
 381//virtual 
 382void LLUICtrl::setValue(const LLSD& value)
 383{
 384    mViewModel->setValue(value);
 385}
 386
 387//virtual
 388LLSD LLUICtrl::getValue() const
 389{
 390	return mViewModel->getValue();
 391}
 392
 393/// When two widgets are displaying the same data (e.g. during a skin
 394/// change), share their ViewModel.
 395void    LLUICtrl::shareViewModelFrom(const LLUICtrl& other)
 396{
 397    // Because mViewModel is an LLViewModelPtr, this assignment will quietly
 398    // dispose of the previous LLViewModel -- unless it's already shared by
 399    // somebody else.
 400    mViewModel = other.mViewModel;
 401}
 402
 403//virtual
 404LLViewModel* LLUICtrl::getViewModel() const
 405{
 406	return mViewModel;
 407}
 408
 409//virtual
 410BOOL LLUICtrl::postBuild()
 411{
 412	//
 413	// Find all of the children that want to be in front and move them to the front
 414	//
 415
 416	if (getChildCount() > 0)
 417	{
 418		std::vector<LLUICtrl*> childrenToMoveToFront;
 419
 420		for (LLView::child_list_const_iter_t child_it = beginChild(); child_it != endChild(); ++child_it)
 421		{
 422			LLUICtrl* uictrl = dynamic_cast<LLUICtrl*>(*child_it);
 423
 424			if (uictrl && uictrl->mRequestsFront)
 425			{
 426				childrenToMoveToFront.push_back(uictrl);
 427			}
 428		}
 429
 430		for (std::vector<LLUICtrl*>::iterator it = childrenToMoveToFront.begin(); it != childrenToMoveToFront.end(); ++it)
 431		{
 432			sendChildToFront(*it);
 433		}
 434	}
 435
 436	return LLView::postBuild();
 437}
 438
 439bool LLUICtrl::setControlValue(const LLSD& value)
 440{
 441	if (mControlVariable)
 442	{
 443		mControlVariable->set(value);
 444		return true;
 445	}
 446	return false;
 447}
 448
 449void LLUICtrl::setControlVariable(LLControlVariable* control)
 450{
 451	if (mControlVariable)
 452	{
 453		//RN: this will happen in practice, should we try to avoid it?
 454		//llwarns << "setControlName called twice on same control!" << llendl;
 455		mControlConnection.disconnect(); // disconnect current signal
 456		mControlVariable = NULL;
 457	}
 458	
 459	if (control)
 460	{
 461		mControlVariable = control;
 462		mControlConnection = mControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("value")));
 463		setValue(mControlVariable->getValue());
 464	}
 465}
 466
 467//virtual
 468void LLUICtrl::setControlName(const std::string& control_name, LLView *context)
 469{
 470	if (context == NULL)
 471	{
 472		context = this;
 473	}
 474
 475	// Register new listener
 476	if (!control_name.empty())
 477	{
 478		LLControlVariable* control = context->findControl(control_name);
 479		setControlVariable(control);
 480	}
 481}
 482
 483void LLUICtrl::setEnabledControlVariable(LLControlVariable* control)
 484{
 485	if (mEnabledControlVariable)
 486	{
 487		mEnabledControlConnection.disconnect(); // disconnect current signal
 488		mEnabledControlVariable = NULL;
 489	}
 490	if (control)
 491	{
 492		mEnabledControlVariable = control;
 493		mEnabledControlConnection = mEnabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("enabled")));
 494		setEnabled(mEnabledControlVariable->getValue().asBoolean());
 495	}
 496}
 497
 498void LLUICtrl::setDisabledControlVariable(LLControlVariable* control)
 499{
 500	if (mDisabledControlVariable)
 501	{
 502		mDisabledControlConnection.disconnect(); // disconnect current signal
 503		mDisabledControlVariable = NULL;
 504	}
 505	if (control)
 506	{
 507		mDisabledControlVariable = control;
 508		mDisabledControlConnection = mDisabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("disabled")));
 509		setEnabled(!(mDisabledControlVariable->getValue().asBoolean()));
 510	}
 511}
 512
 513void LLUICtrl::setMakeVisibleControlVariable(LLControlVariable* control)
 514{
 515	if (mMakeVisibleControlVariable)
 516	{
 517		mMakeVisibleControlConnection.disconnect(); // disconnect current signal
 518		mMakeVisibleControlVariable = NULL;
 519	}
 520	if (control)
 521	{
 522		mMakeVisibleControlVariable = control;
 523		mMakeVisibleControlConnection = mMakeVisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("visible")));
 524		setVisible(mMakeVisibleControlVariable->getValue().asBoolean());
 525	}
 526}
 527
 528void LLUICtrl::setMakeInvisibleControlVariable(LLControlVariable* control)
 529{
 530	if (mMakeInvisibleControlVariable)
 531	{
 532		mMakeInvisibleControlConnection.disconnect(); // disconnect current signal
 533		mMakeInvisibleControlVariable = NULL;
 534	}
 535	if (control)
 536	{
 537		mMakeInvisibleControlVariable = control;
 538		mMakeInvisibleControlConnection = mMakeInvisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("invisible")));
 539		setVisible(!(mMakeInvisibleControlVariable->getValue().asBoolean()));
 540	}
 541}
 542// static
 543bool LLUICtrl::controlListener(const LLSD& newvalue, LLHandle<LLUICtrl> handle, std::string type)
 544{
 545	LLUICtrl* ctrl = handle.get();
 546	if (ctrl)
 547	{
 548		if (type == "value")
 549		{
 550			ctrl->setValue(newvalue);
 551			return true;
 552		}
 553		else if (type == "enabled")
 554		{
 555			ctrl->setEnabled(newvalue.asBoolean());
 556			return true;
 557		}
 558		else if(type =="disabled")
 559		{
 560			ctrl->setEnabled(!newvalue.asBoolean());
 561			return true;
 562		}
 563		else if (type == "visible")
 564		{
 565			ctrl->setVisible(newvalue.asBoolean());
 566			return true;
 567		}
 568		else if (type == "invisible")
 569		{
 570			ctrl->setVisible(!newvalue.asBoolean());
 571			return true;
 572		}
 573	}
 574	return false;
 575}
 576
 577// virtual
 578BOOL LLUICtrl::setTextArg( const std::string& key, const LLStringExplicit& text ) 
 579{ 
 580	return FALSE; 
 581}
 582
 583// virtual
 584BOOL LLUICtrl::setLabelArg( const std::string& key, const LLStringExplicit& text ) 
 585{ 
 586	return FALSE; 
 587}
 588
 589// virtual
 590LLCtrlSelectionInterface* LLUICtrl::getSelectionInterface()	
 591{ 
 592	return NULL; 
 593}
 594
 595// virtual
 596LLCtrlListInterface* LLUICtrl::getListInterface()				
 597{ 
 598	return NULL; 
 599}
 600
 601// virtual
 602LLCtrlScrollInterface* LLUICtrl::getScrollInterface()			
 603{ 
 604	return NULL; 
 605}
 606
 607BOOL LLUICtrl::hasFocus() const
 608{
 609	return (gFocusMgr.childHasKeyboardFocus(this));
 610}
 611
 612void LLUICtrl::setFocus(BOOL b)
 613{
 614	// focus NEVER goes to ui ctrls that are disabled!
 615	if (!getEnabled())
 616	{
 617		return;
 618	}
 619	if( b )
 620	{
 621		if (!hasFocus())
 622		{
 623			gFocusMgr.setKeyboardFocus( this );
 624		}
 625	}
 626	else
 627	{
 628		if( gFocusMgr.childHasKeyboardFocus(this))
 629		{
 630			gFocusMgr.setKeyboardFocus( NULL );
 631		}
 632	}
 633}
 634
 635// virtual
 636void LLUICtrl::setTabStop( BOOL b )	
 637{ 
 638	mTabStop = b;
 639}
 640
 641// virtual
 642BOOL LLUICtrl::hasTabStop() const		
 643{ 
 644	return mTabStop;
 645}
 646
 647// virtual
 648BOOL LLUICtrl::acceptsTextInput() const
 649{ 
 650	return FALSE; 
 651}
 652
 653//virtual
 654BOOL LLUICtrl::isDirty() const
 655{
 656	return mViewModel->isDirty();
 657};
 658
 659//virtual
 660void LLUICtrl::resetDirty()
 661{
 662    mViewModel->resetDirty();
 663}
 664
 665// virtual
 666void LLUICtrl::onTabInto()				
 667{
 668}
 669
 670// virtual
 671void LLUICtrl::clear()					
 672{
 673}
 674
 675// virtual
 676void LLUICtrl::setIsChrome(BOOL is_chrome)
 677{
 678	mIsChrome = is_chrome; 
 679}
 680
 681// virtual
 682BOOL LLUICtrl::getIsChrome() const
 683{ 
 684	LLView* parent_ctrl = getParent();
 685	while(parent_ctrl)
 686	{
 687		if(parent_ctrl->isCtrl())
 688		{
 689			break;	
 690		}
 691		parent_ctrl = parent_ctrl->getParent();
 692	}
 693	
 694	if(parent_ctrl)
 695	{
 696		return mIsChrome || ((LLUICtrl*)parent_ctrl)->getIsChrome();
 697	}
 698	else
 699	{
 700		return mIsChrome ; 
 701	}
 702}
 703
 704// this comparator uses the crazy disambiguating logic of LLCompareByTabOrder,
 705// but to switch up the order so that children that have the default tab group come first
 706// and those that are prior to the default tab group come last
 707class CompareByDefaultTabGroup: public LLCompareByTabOrder
 708{
 709public:
 710	CompareByDefaultTabGroup(const LLView::child_tab_order_t& order, S32 default_tab_group):
 711			LLCompareByTabOrder(order),
 712			mDefaultTabGroup(default_tab_group) {}
 713private:
 714	/*virtual*/ bool compareTabOrders(const LLView::tab_order_t & a, const LLView::tab_order_t & b) const
 715	{
 716		S32 ag = a.first; // tab group for a
 717		S32 bg = b.first; // tab group for b
 718		// these two ifs have the effect of moving elements prior to the default tab group to the end of the list 
 719		// (still sorted relative to each other, though)
 720		if(ag < mDefaultTabGroup && bg >= mDefaultTabGroup) return false;
 721		if(bg < mDefaultTabGroup && ag >= mDefaultTabGroup) return true;
 722		return a < b;  // sort correctly if they're both on the same side of the default tab group
 723	}
 724	S32 mDefaultTabGroup;
 725};
 726
 727
 728// Sorter for plugging into the query.
 729// I'd have defined it local to the one method that uses it but that broke the VS 05 compiler. -MG
 730class LLUICtrl::DefaultTabGroupFirstSorter : public LLQuerySorter, public LLSingleton<DefaultTabGroupFirstSorter>
 731{
 732public:
 733	/*virtual*/ void operator() (LLView * parent, viewList_t &children) const
 734	{	
 735		children.sort(CompareByDefaultTabGroup(parent->getCtrlOrder(), parent->getDefaultTabGroup()));
 736	}
 737};
 738
 739LLFastTimer::DeclareTimer FTM_FOCUS_FIRST_ITEM("Focus First Item");
 740
 741BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash)
 742{
 743	LLFastTimer _(FTM_FOCUS_FIRST_ITEM);
 744	// try to select default tab group child
 745	LLCtrlQuery query = getTabOrderQuery();
 746	// sort things such that the default tab group is at the front
 747	query.setSorter(DefaultTabGroupFirstSorter::getInstance());
 748	child_list_t result = query(this);
 749	if(result.size() > 0)
 750	{
 751		LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.front());
 752		if(!ctrl->hasFocus())
 753		{
 754			ctrl->setFocus(TRUE);
 755			ctrl->onTabInto();  
 756			if(focus_flash)
 757			{
 758				gFocusMgr.triggerFocusFlash();
 759			}
 760		}
 761		return TRUE;
 762	}	
 763	// search for text field first
 764	if(prefer_text_fields)
 765	{
 766		LLCtrlQuery query = getTabOrderQuery();
 767		query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
 768		child_list_t result = query(this);
 769		if(result.size() > 0)
 770		{
 771			LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.front());
 772			if(!ctrl->hasFocus())
 773			{
 774				ctrl->setFocus(TRUE);
 775				ctrl->onTabInto();  
 776				gFocusMgr.triggerFocusFlash();
 777			}
 778			return TRUE;
 779		}
 780	}
 781	// no text field found, or we don't care about text fields
 782	result = getTabOrderQuery().run(this);
 783	if(result.size() > 0)
 784	{
 785		LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.front());
 786		if(!ctrl->hasFocus())
 787		{
 788			ctrl->setFocus(TRUE);
 789			ctrl->onTabInto();  
 790			gFocusMgr.triggerFocusFlash();
 791		}
 792		return TRUE;
 793	}	
 794	return FALSE;
 795}
 796
 797BOOL LLUICtrl::focusLastItem(BOOL prefer_text_fields)
 798{
 799	// search for text field first
 800	if(prefer_text_fields)
 801	{
 802		LLCtrlQuery query = getTabOrderQuery();
 803		query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
 804		child_list_t result = query(this);
 805		if(result.size() > 0)
 806		{
 807			LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back());
 808			if(!ctrl->hasFocus())
 809			{
 810				ctrl->setFocus(TRUE);
 811				ctrl->onTabInto();  
 812				gFocusMgr.triggerFocusFlash();
 813			}
 814			return TRUE;
 815		}
 816	}
 817	// no text field found, or we don't care about text fields
 818	child_list_t result = getTabOrderQuery().run(this);
 819	if(result.size() > 0)
 820	{
 821		LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back());
 822		if(!ctrl->hasFocus())
 823		{
 824			ctrl->setFocus(TRUE);
 825			ctrl->onTabInto();  
 826			gFocusMgr.triggerFocusFlash();
 827		}
 828		return TRUE;
 829	}	
 830	return FALSE;
 831}
 832
 833BOOL LLUICtrl::focusNextItem(BOOL text_fields_only)
 834{
 835	// this assumes that this method is called on the focus root.
 836	LLCtrlQuery query = getTabOrderQuery();
 837	static LLUICachedControl<bool> tab_to_text_fields_only ("TabToTextFieldsOnly", false);
 838	if(text_fields_only || tab_to_text_fields_only)
 839	{
 840		query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
 841	}
 842	child_list_t result = query(this);
 843	return focusNext(result);
 844}
 845
 846BOOL LLUICtrl::focusPrevItem(BOOL text_fields_only)
 847{
 848	// this assumes that this method is called on the focus root.
 849	LLCtrlQuery query = getTabOrderQuery();
 850	static LLUICachedControl<bool> tab_to_text_fields_only ("TabToTextFieldsOnly", false);
 851	if(text_fields_only || tab_to_text_fields_only)
 852	{
 853		query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
 854	}
 855	child_list_t result = query(this);
 856	return focusPrev(result);
 857}
 858
 859LLUICtrl* LLUICtrl::findRootMostFocusRoot()
 860{
 861	LLUICtrl* focus_root = NULL;
 862	LLUICtrl* next_view = this;
 863	while(next_view && next_view->hasTabStop())
 864	{
 865		if (next_view->isFocusRoot())
 866		{
 867			focus_root = next_view;
 868		}
 869		next_view = next_view->getParentUICtrl();
 870	}
 871
 872	return focus_root;
 873}
 874
 875// Skip over any parents that are not LLUICtrl's
 876//  Used in focus logic since only LLUICtrl elements can have focus
 877LLUICtrl* LLUICtrl::getParentUICtrl() const
 878{
 879	LLView* parent = getParent();
 880	while (parent)
 881	{
 882		if (parent->isCtrl())
 883		{
 884			return (LLUICtrl*)(parent);
 885		}
 886		else
 887		{
 888			parent =  parent->getParent();
 889		}
 890	}
 891	return NULL;
 892}
 893
 894bool LLUICtrl::findHelpTopic(std::string& help_topic_out)
 895{
 896	LLUICtrl* ctrl = this;
 897
 898	// search back through the control's parents for a panel
 899	// or tab with a help_topic string defined
 900	while (ctrl)
 901	{
 902		LLPanel *panel = dynamic_cast<LLPanel *>(ctrl);
 903
 904		if (panel)
 905		{
 906			// does the panel have a sub-panel with a help topic?
 907			LLPanel *subpanel = panel->childGetVisiblePanelWithHelp();
 908			if (subpanel)
 909			{
 910				help_topic_out = subpanel->getHelpTopic();
 911				return true; // success (subpanel)
 912			}
 913
 914			// does the panel have an active tab with a help topic?
 915			LLPanel *tab = panel->childGetVisibleTabWithHelp();
 916			if (tab)
 917			{
 918				help_topic_out = tab->getHelpTopic();
 919				return true; // success (tab)
 920			}
 921
 922			// otherwise, does the panel have a help topic itself?
 923			if (!panel->getHelpTopic().empty())
 924			{
 925				help_topic_out = panel->getHelpTopic();
 926				return true; // success (panel)
 927			}		
 928		}
 929
 930		ctrl = ctrl->getParentUICtrl();
 931	}
 932
 933	return false; // no help topic found
 934}
 935
 936// *TODO: Deprecate; for backwards compatability only:
 937boost::signals2::connection LLUICtrl::setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data)
 938{
 939	return setCommitCallback( boost::bind(cb, _1, data));
 940}
 941boost::signals2::connection LLUICtrl::setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb )
 942{
 943	if (!mValidateSignal) mValidateSignal = new enable_signal_t();
 944	return mValidateSignal->connect(boost::bind(cb, _2));
 945}
 946
 947// virtual
 948void LLUICtrl::setTentative(BOOL b)									
 949{ 
 950	mTentative = b; 
 951}
 952
 953// virtual
 954BOOL LLUICtrl::getTentative() const									
 955{ 
 956	return mTentative; 
 957}
 958
 959// virtual
 960void LLUICtrl::setColor(const LLColor4& color)							
 961{ }
 962
 963F32 LLUICtrl::getCurrentTransparency()
 964{
 965	F32 alpha = 0;
 966
 967	switch(mTransparencyType)
 968	{
 969	case TT_DEFAULT:
 970		alpha = getDrawContext().mAlpha;
 971		break;
 972
 973	case TT_ACTIVE:
 974		alpha = sActiveControlTransparency;
 975		break;
 976
 977	case TT_INACTIVE:
 978		alpha = sInactiveControlTransparency;
 979		break;
 980
 981	case TT_FADING:
 982		alpha = sInactiveControlTransparency / 2;
 983		break;
 984	}
 985
 986	return alpha;
 987}
 988
 989void LLUICtrl::setTransparencyType(ETypeTransparency type)
 990{
 991	mTransparencyType = type;
 992}
 993
 994boost::signals2::connection LLUICtrl::setCommitCallback(const CommitCallbackParam& cb)
 995{
 996	return setCommitCallback(initCommitCallback(cb));
 997}
 998
 999boost::signals2::connection LLUICtrl::setValidateCallback(const EnableCallbackParam& cb)
1000{
1001	return setValidateCallback(initEnableCallback(cb));
1002}
1003
1004boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::slot_type& cb ) 
1005{ 
1006	if (!mCommitSignal) mCommitSignal = new commit_signal_t();
1007	return mCommitSignal->connect(cb); 
1008}
1009
1010boost::signals2::connection LLUICtrl::setValidateCallback( const enable_signal_t::slot_type& cb ) 
1011{ 
1012	if (!mValidateSignal) mValidateSignal = new enable_signal_t();
1013	return mValidateSignal->connect(cb); 
1014}
1015
1016boost::signals2::connection LLUICtrl::setMouseEnterCallback( const commit_signal_t::slot_type& cb ) 
1017{ 
1018	if (!mMouseEnterSignal) mMouseEnterSignal = new commit_signal_t();
1019	return mMouseEnterSignal->connect(cb); 
1020}
1021
1022boost::signals2::connection LLUICtrl::setMouseLeaveCallback( const commit_signal_t::slot_type& cb ) 
1023{ 
1024	if (!mMouseLeaveSignal) mMouseLeaveSignal = new commit_signal_t();
1025	return mMouseLeaveSignal->connect(cb); 
1026}
1027
1028boost::signals2::connection LLUICtrl::setMouseDownCallback( const mouse_signal_t::slot_type& cb ) 
1029{ 
1030	if (!mMouseDownSignal) mMouseDownSignal = new mouse_signal_t();
1031	return mMouseDownSignal->connect(cb); 
1032}
1033
1034boost::signals2::connection LLUICtrl::setMouseUpCallback( const mouse_signal_t::slot_type& cb ) 
1035{ 
1036	if (!mMouseUpSignal) mMouseUpSignal = new mouse_signal_t();
1037	return mMouseUpSignal->connect(cb); 
1038}
1039
1040boost::signals2::connection LLUICtrl::setRightMouseDownCallback( const mouse_signal_t::slot_type& cb ) 
1041{ 
1042	if (!mRightMouseDownSignal) mRightMouseDownSignal = new mouse_signal_t();
1043	return mRightMouseDownSignal->connect(cb); 
1044}
1045
1046boost::signals2::connection LLUICtrl::setRightMouseUpCallback( const mouse_signal_t::slot_type& cb ) 
1047{ 
1048	if (!mRightMouseUpSignal) mRightMouseUpSignal = new mouse_signal_t();
1049	return mRightMouseUpSignal->connect(cb); 
1050}
1051
1052boost::signals2::connection LLUICtrl::setDoubleClickCallback( const mouse_signal_t::slot_type& cb ) 
1053{ 
1054	if (!mDoubleClickSignal) mDoubleClickSignal = new mouse_signal_t();
1055	return mDoubleClickSignal->connect(cb); 
1056}
1057
1058void LLUICtrl::addInfo(LLSD & info)
1059{
1060	LLView::addInfo(info);
1061	info["value"] = getValue();
1062}