summaryrefslogtreecommitdiff
path: root/indra/llui/lluictrl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui/lluictrl.cpp')
-rw-r--r--indra/llui/lluictrl.cpp2274
1 files changed, 1137 insertions, 1137 deletions
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 8d57a69c6e..4c2ad9d92b 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -1,1137 +1,1137 @@
-/**
- * @file lluictrl.cpp
- * @author James Cook, Richard Nelson, Tom Yedwab
- * @brief Abstract base class for UI controls
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#define LLUICTRL_CPP
-#include "lluictrl.h"
-#include "llviewereventrecorder.h"
-#include "llfocusmgr.h"
-#include "llpanel.h"
-#include "lluictrlfactory.h"
-#include "lltabcontainer.h"
-#include "llaccordionctrltab.h"
-#include "lluiusage.h"
-
-static LLDefaultChildRegistry::Register<LLUICtrl> r("ui_ctrl");
-
-F32 LLUICtrl::sActiveControlTransparency = 1.0f;
-F32 LLUICtrl::sInactiveControlTransparency = 1.0f;
-
-// Compiler optimization, generate extern template
-template class LLUICtrl* LLView::getChild<class LLUICtrl>(
- const std::string& name, bool recurse) const;
-
-LLUICtrl::CallbackParam::CallbackParam()
-: name("name"),
- function_name("function"),
- parameter("parameter"),
- control_name("control") // Shortcut to control -> "control_name" for backwards compatability
-{
- addSynonym(parameter, "userdata");
-}
-
-LLUICtrl::EnableControls::EnableControls()
-: enabled("enabled_control"),
- disabled("disabled_control")
-{}
-
-LLUICtrl::ControlVisibility::ControlVisibility()
-: visible("visibility_control"),
- invisible("invisibility_control")
-{
- addSynonym(visible, "visiblity_control");
- addSynonym(invisible, "invisiblity_control");
-}
-
-LLUICtrl::Params::Params()
-: tab_stop("tab_stop", true),
- chrome("chrome", false),
- requests_front("requests_front", false),
- label("label"),
- initial_value("value"),
- init_callback("init_callback"),
- commit_callback("commit_callback"),
- validate_callback("validate_callback"),
- mouseenter_callback("mouseenter_callback"),
- mouseleave_callback("mouseleave_callback"),
- control_name("control_name"),
- font("font", LLFontGL::getFontSansSerif()),
- font_halign("halign"),
- font_valign("valign"),
- length("length"), // ignore LLXMLNode cruft
- type("type") // ignore LLXMLNode cruft
-{
- addSynonym(initial_value, "initial_value");
-}
-
-// NOTE: the LLFocusableElement implementation has been moved from here to llfocusmgr.cpp.
-
-//static
-const LLUICtrl::Params& LLUICtrl::getDefaultParams()
-{
- return LLUICtrlFactory::getDefaultParams<LLUICtrl>();
-}
-
-
-LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel)
-: LLView(p),
- mIsChrome(false),
- mRequestsFront(p.requests_front),
- mTabStop(false),
- mTentative(false),
- mViewModel(viewmodel),
- mControlVariable(NULL),
- mEnabledControlVariable(NULL),
- mDisabledControlVariable(NULL),
- mMakeVisibleControlVariable(NULL),
- mMakeInvisibleControlVariable(NULL),
- mCommitSignal(NULL),
- mValidateSignal(NULL),
- mMouseEnterSignal(NULL),
- mMouseLeaveSignal(NULL),
- mMouseDownSignal(NULL),
- mMouseUpSignal(NULL),
- mRightMouseDownSignal(NULL),
- mRightMouseUpSignal(NULL),
- mDoubleClickSignal(NULL),
- mTransparencyType(TT_DEFAULT)
-{
-}
-
-void LLUICtrl::initFromParams(const Params& p)
-{
- LLView::initFromParams(p);
-
- mRequestsFront = p.requests_front;
-
- setIsChrome(p.chrome);
- setControlName(p.control_name);
- if(p.enabled_controls.isProvided())
- {
- if (p.enabled_controls.enabled.isChosen())
- {
- LLControlVariable* control = findControl(p.enabled_controls.enabled);
- if (control)
- {
- setEnabledControlVariable(control);
- }
- else
- {
- LL_WARNS() << "Failed to assign 'enabled' control variable to " << getName()
- << ": control " << p.enabled_controls.enabled()
- << " does not exist." << LL_ENDL;
- }
- }
- else if(p.enabled_controls.disabled.isChosen())
- {
- LLControlVariable* control = findControl(p.enabled_controls.disabled);
- if (control)
- {
- setDisabledControlVariable(control);
- }
- else
- {
- LL_WARNS() << "Failed to assign 'disabled' control variable to " << getName()
- << ": control " << p.enabled_controls.disabled()
- << " does not exist." << LL_ENDL;
- }
- }
- }
- if(p.controls_visibility.isProvided())
- {
- if (p.controls_visibility.visible.isChosen())
- {
- LLControlVariable* control = findControl(p.controls_visibility.visible);
- if (control)
- {
- setMakeVisibleControlVariable(control);
- }
- else
- {
- LL_WARNS() << "Failed to assign visibility control variable to " << getName()
- << ": control " << p.controls_visibility.visible()
- << " does not exist." << LL_ENDL;
- }
- }
- else if (p.controls_visibility.invisible.isChosen())
- {
- LLControlVariable* control = findControl(p.controls_visibility.invisible);
- if (control)
- {
- setMakeInvisibleControlVariable(control);
- }
- else
- {
- LL_WARNS() << "Failed to assign invisibility control variable to " << getName()
- << ": control " << p.controls_visibility.invisible()
- << " does not exist." << LL_ENDL;
- }
- }
- }
-
- setTabStop(p.tab_stop);
-
- if (p.initial_value.isProvided()
- && !p.control_name.isProvided())
- {
- setValue(p.initial_value);
- }
-
- if (p.commit_callback.isProvided())
- {
- setCommitCallback(initCommitCallback(p.commit_callback));
- }
-
- if (p.validate_callback.isProvided())
- {
- setValidateCallback(initEnableCallback(p.validate_callback));
- }
-
- if (p.init_callback.isProvided())
- {
- if (p.init_callback.function.isProvided())
- {
- p.init_callback.function()(this, p.init_callback.parameter);
- }
- else
- {
- commit_callback_t* initfunc = (CommitCallbackRegistry::getValue(p.init_callback.function_name));
- if (initfunc)
- {
- (*initfunc)(this, p.init_callback.parameter);
- }
- }
- }
-
- if(p.mouseenter_callback.isProvided())
- {
- setMouseEnterCallback(initCommitCallback(p.mouseenter_callback));
- }
-
- if(p.mouseleave_callback.isProvided())
- {
- setMouseLeaveCallback(initCommitCallback(p.mouseleave_callback));
- }
-}
-
-
-LLUICtrl::~LLUICtrl()
-{
- gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit()
-
- if( gFocusMgr.getTopCtrl() == this )
- {
- LL_WARNS() << "UI Control holding top ctrl deleted: " << getName() << ". Top view removed." << LL_ENDL;
- gFocusMgr.removeTopCtrlWithoutCallback( this );
- }
-
- delete mCommitSignal;
- delete mValidateSignal;
- delete mMouseEnterSignal;
- delete mMouseLeaveSignal;
- delete mMouseDownSignal;
- delete mMouseUpSignal;
- delete mRightMouseDownSignal;
- delete mRightMouseUpSignal;
- delete mDoubleClickSignal;
-}
-
-void default_commit_handler(LLUICtrl* ctrl, const LLSD& param)
-{}
-
-bool default_enable_handler(LLUICtrl* ctrl, const LLSD& param)
-{
- return true;
-}
-
-
-LLUICtrl::commit_signal_t::slot_type LLUICtrl::initCommitCallback(const CommitCallbackParam& cb)
-{
- if (cb.function.isProvided())
- {
- if (cb.parameter.isProvided())
- return boost::bind(cb.function(), _1, cb.parameter);
- else
- return cb.function();
- }
- else
- {
- std::string function_name = cb.function_name;
- setFunctionName(function_name);
- commit_callback_t* func = (CommitCallbackRegistry::getValue(function_name));
- if (func)
- {
- if (cb.parameter.isProvided())
- return boost::bind((*func), _1, cb.parameter);
- else
- return commit_signal_t::slot_type(*func);
- }
- else if (!function_name.empty())
- {
- LL_WARNS() << "No callback found for: '" << function_name << "' in control: " << getName() << LL_ENDL;
- }
- }
- return default_commit_handler;
-}
-
-LLUICtrl::enable_signal_t::slot_type LLUICtrl::initEnableCallback(const EnableCallbackParam& cb)
-{
- // Set the callback function
- if (cb.function.isProvided())
- {
- if (cb.parameter.isProvided())
- return boost::bind(cb.function(), this, cb.parameter);
- else
- return cb.function();
- }
- else
- {
- enable_callback_t* func = (EnableCallbackRegistry::getValue(cb.function_name));
- if (func)
- {
- if (cb.parameter.isProvided())
- return boost::bind((*func), this, cb.parameter);
- else
- return enable_signal_t::slot_type(*func);
- }
- }
- return default_enable_handler;
-}
-
-// virtual
-void LLUICtrl::onMouseEnter(S32 x, S32 y, MASK mask)
-{
- if (mMouseEnterSignal)
- {
- (*mMouseEnterSignal)(this, getValue());
- }
-}
-
-// virtual
-void LLUICtrl::onMouseLeave(S32 x, S32 y, MASK mask)
-{
- if(mMouseLeaveSignal)
- {
- (*mMouseLeaveSignal)(this, getValue());
- }
-}
-
-//virtual
-bool LLUICtrl::handleMouseDown(S32 x, S32 y, MASK mask)
-{
-
- LL_DEBUGS() << "LLUICtrl::handleMouseDown calling LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << LL_ENDL;
-
- bool handled = LLView::handleMouseDown(x,y,mask);
-
- if (mMouseDownSignal)
- {
- (*mMouseDownSignal)(this,x,y,mask);
- }
- LL_DEBUGS() << "LLUICtrl::handleMousedown - handled is returning as: " << handled << " " << LL_ENDL;
-
- if (handled) {
- LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-56,-56,getPathname());
- }
- return handled;
-}
-
-//virtual
-bool LLUICtrl::handleMouseUp(S32 x, S32 y, MASK mask)
-{
-
- LL_DEBUGS() << "LLUICtrl::handleMouseUp calling LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << LL_ENDL;
-
- bool handled = LLView::handleMouseUp(x,y,mask);
- if (handled) {
- LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-56,-56,getPathname());
- }
- if (mMouseUpSignal)
- {
- (*mMouseUpSignal)(this,x,y,mask);
- }
-
- LL_DEBUGS() << "LLUICtrl::handleMouseUp - handled for xui " << getPathname() << " - is returning as: " << handled << " " << LL_ENDL;
-
- return handled;
-}
-
-//virtual
-bool LLUICtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
-{
- bool handled = LLView::handleRightMouseDown(x,y,mask);
- if (mRightMouseDownSignal)
- {
- (*mRightMouseDownSignal)(this,x,y,mask);
- }
- return handled;
-}
-
-//virtual
-bool LLUICtrl::handleRightMouseUp(S32 x, S32 y, MASK mask)
-{
- bool handled = LLView::handleRightMouseUp(x,y,mask);
- if(mRightMouseUpSignal)
- {
- (*mRightMouseUpSignal)(this,x,y,mask);
- }
- return handled;
-}
-
-bool LLUICtrl::handleDoubleClick(S32 x, S32 y, MASK mask)
-{
- bool handled = LLView::handleDoubleClick(x, y, mask);
- if (mDoubleClickSignal)
- {
- (*mDoubleClickSignal)(this, x, y, mask);
- }
- return handled;
-}
-
-// can't tab to children of a non-tab-stop widget
-bool LLUICtrl::canFocusChildren() const
-{
- return hasTabStop();
-}
-
-
-void LLUICtrl::onCommit()
-{
- if (mCommitSignal)
- {
- if (!mFunctionName.empty())
- {
- LL_DEBUGS("UIUsage") << "calling commit function " << mFunctionName << LL_ENDL;
- LLUIUsage::instance().logCommand(mFunctionName);
- LLUIUsage::instance().logControl(getPathname());
- }
- else
- {
- //LL_DEBUGS("UIUsage") << "calling commit function " << "UNKNOWN" << LL_ENDL;
- }
- (*mCommitSignal)(this, getValue());
- }
-}
-
-//virtual
-bool LLUICtrl::isCtrl() const
-{
- return true;
-}
-
-//virtual
-void LLUICtrl::setValue(const LLSD& value)
-{
- mViewModel->setValue(value);
-}
-
-//virtual
-LLSD LLUICtrl::getValue() const
-{
- return mViewModel->getValue();
-}
-
-/// When two widgets are displaying the same data (e.g. during a skin
-/// change), share their ViewModel.
-void LLUICtrl::shareViewModelFrom(const LLUICtrl& other)
-{
- // Because mViewModel is an LLViewModelPtr, this assignment will quietly
- // dispose of the previous LLViewModel -- unless it's already shared by
- // somebody else.
- mViewModel = other.mViewModel;
-}
-
-//virtual
-LLViewModel* LLUICtrl::getViewModel() const
-{
- return mViewModel;
-}
-
-//virtual
-bool LLUICtrl::postBuild()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
- //
- // Find all of the children that want to be in front and move them to the front
- //
-
- if (getChildCount() > 0)
- {
- std::vector<LLUICtrl*> childrenToMoveToFront;
-
- for (LLView::child_list_const_iter_t child_it = beginChild(); child_it != endChild(); ++child_it)
- {
- LLUICtrl* uictrl = dynamic_cast<LLUICtrl*>(*child_it);
-
- if (uictrl && uictrl->mRequestsFront)
- {
- childrenToMoveToFront.push_back(uictrl);
- }
- }
-
- for (std::vector<LLUICtrl*>::iterator it = childrenToMoveToFront.begin(); it != childrenToMoveToFront.end(); ++it)
- {
- sendChildToFront(*it);
- }
- }
-
- return LLView::postBuild();
-}
-
-bool LLUICtrl::setControlValue(const LLSD& value)
-{
- if (mControlVariable)
- {
- mControlVariable->set(value);
- return true;
- }
- return false;
-}
-
-void LLUICtrl::setControlVariable(LLControlVariable* control)
-{
- if (mControlVariable)
- {
- //RN: this will happen in practice, should we try to avoid it?
- //LL_WARNS() << "setControlName called twice on same control!" << LL_ENDL;
- mControlConnection.disconnect(); // disconnect current signal
- mControlVariable = NULL;
- }
-
- if (control)
- {
- mControlVariable = control;
- mControlConnection = mControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("value")));
- setValue(mControlVariable->getValue());
- }
-}
-
-void LLUICtrl::removeControlVariable()
-{
- if (mControlVariable)
- {
- mControlConnection.disconnect();
- mControlVariable = NULL;
- }
-}
-
-//virtual
-void LLUICtrl::setControlName(const std::string& control_name, LLView *context)
-{
- if (context == NULL)
- {
- context = this;
- }
-
- // Register new listener
- if (!control_name.empty())
- {
- LLControlVariable* control = context->findControl(control_name);
- if (!control)
- {
- LL_WARNS() << "Failed to assign control variable to " << getName()
- << ": control "<< control_name << " does not exist." << LL_ENDL;
- }
- setControlVariable(control);
- }
-}
-
-void LLUICtrl::setEnabledControlVariable(LLControlVariable* control)
-{
- if (mEnabledControlVariable)
- {
- mEnabledControlConnection.disconnect(); // disconnect current signal
- mEnabledControlVariable = NULL;
- }
- if (control)
- {
- mEnabledControlVariable = control;
- mEnabledControlConnection = mEnabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("enabled")));
- setEnabled(mEnabledControlVariable->getValue().asBoolean());
- }
-}
-
-void LLUICtrl::setDisabledControlVariable(LLControlVariable* control)
-{
- if (mDisabledControlVariable)
- {
- mDisabledControlConnection.disconnect(); // disconnect current signal
- mDisabledControlVariable = NULL;
- }
- if (control)
- {
- mDisabledControlVariable = control;
- mDisabledControlConnection = mDisabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("disabled")));
- setEnabled(!(mDisabledControlVariable->getValue().asBoolean()));
- }
-}
-
-void LLUICtrl::setMakeVisibleControlVariable(LLControlVariable* control)
-{
- if (mMakeVisibleControlVariable)
- {
- mMakeVisibleControlConnection.disconnect(); // disconnect current signal
- mMakeVisibleControlVariable = NULL;
- }
- if (control)
- {
- mMakeVisibleControlVariable = control;
- mMakeVisibleControlConnection = mMakeVisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("visible")));
- setVisible(mMakeVisibleControlVariable->getValue().asBoolean());
- }
-}
-
-void LLUICtrl::setMakeInvisibleControlVariable(LLControlVariable* control)
-{
- if (mMakeInvisibleControlVariable)
- {
- mMakeInvisibleControlConnection.disconnect(); // disconnect current signal
- mMakeInvisibleControlVariable = NULL;
- }
- if (control)
- {
- mMakeInvisibleControlVariable = control;
- mMakeInvisibleControlConnection = mMakeInvisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("invisible")));
- setVisible(!(mMakeInvisibleControlVariable->getValue().asBoolean()));
- }
-}
-
-void LLUICtrl::setFunctionName(const std::string& function_name)
-{
- mFunctionName = function_name;
-}
-
-// static
-bool LLUICtrl::controlListener(const LLSD& newvalue, LLHandle<LLUICtrl> handle, std::string type)
-{
- LLUICtrl* ctrl = handle.get();
- if (ctrl)
- {
- if (type == "value")
- {
- ctrl->setValue(newvalue);
- return true;
- }
- else if (type == "enabled")
- {
- ctrl->setEnabled(newvalue.asBoolean());
- return true;
- }
- else if(type =="disabled")
- {
- ctrl->setEnabled(!newvalue.asBoolean());
- return true;
- }
- else if (type == "visible")
- {
- ctrl->setVisible(newvalue.asBoolean());
- return true;
- }
- else if (type == "invisible")
- {
- ctrl->setVisible(!newvalue.asBoolean());
- return true;
- }
- }
- return false;
-}
-
-// virtual
-bool LLUICtrl::setTextArg( const std::string& key, const LLStringExplicit& text )
-{
- return false;
-}
-
-// virtual
-bool LLUICtrl::setLabelArg( const std::string& key, const LLStringExplicit& text )
-{
- return false;
-}
-
-// virtual
-LLCtrlSelectionInterface* LLUICtrl::getSelectionInterface()
-{
- return NULL;
-}
-
-// virtual
-LLCtrlListInterface* LLUICtrl::getListInterface()
-{
- return NULL;
-}
-
-// virtual
-LLCtrlScrollInterface* LLUICtrl::getScrollInterface()
-{
- return NULL;
-}
-
-bool LLUICtrl::hasFocus() const
-{
- return (gFocusMgr.childHasKeyboardFocus(this));
-}
-
-void LLUICtrl::setFocus(bool b)
-{
- // focus NEVER goes to ui ctrls that are disabled!
- if (!getEnabled())
- {
- return;
- }
- if( b )
- {
- if (!hasFocus())
- {
- gFocusMgr.setKeyboardFocus( this );
- }
- }
- else
- {
- if( gFocusMgr.childHasKeyboardFocus(this))
- {
- gFocusMgr.setKeyboardFocus( NULL );
- }
- }
-}
-
-// virtual
-void LLUICtrl::setTabStop( bool b )
-{
- mTabStop = b;
-}
-
-// virtual
-bool LLUICtrl::hasTabStop() const
-{
- return mTabStop;
-}
-
-// virtual
-bool LLUICtrl::acceptsTextInput() const
-{
- return false;
-}
-
-//virtual
-bool LLUICtrl::isDirty() const
-{
- return mViewModel->isDirty();
-};
-
-//virtual
-void LLUICtrl::resetDirty()
-{
- mViewModel->resetDirty();
-}
-
-// virtual
-void LLUICtrl::onTabInto()
-{
- onUpdateScrollToChild(this);
-}
-
-// virtual
-void LLUICtrl::clear()
-{
-}
-
-// virtual
-void LLUICtrl::setIsChrome(bool is_chrome)
-{
- mIsChrome = is_chrome;
-}
-
-// virtual
-bool LLUICtrl::getIsChrome() const
-{
- if (mIsChrome)
- return true;
-
- LLView* parent_ctrl = getParent();
- while (parent_ctrl)
- {
- if (parent_ctrl->isCtrl())
- return ((LLUICtrl*)parent_ctrl)->getIsChrome();
-
- parent_ctrl = parent_ctrl->getParent();
- }
-
- return false;
-}
-
-
-bool LLUICtrl::focusFirstItem(bool prefer_text_fields, bool focus_flash)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
- // try to select default tab group child
- LLViewQuery query = getTabOrderQuery();
- child_list_t result = query(this);
- if(result.size() > 0)
- {
- LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back());
- if(!ctrl->hasFocus())
- {
- ctrl->setFocus(true);
- ctrl->onTabInto();
- if(focus_flash)
- {
- gFocusMgr.triggerFocusFlash();
- }
- }
- return true;
- }
- // search for text field first
- if(prefer_text_fields)
- {
- LLViewQuery query = getTabOrderQuery();
- query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
- child_list_t result = query(this);
- if(result.size() > 0)
- {
- LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back());
- if(!ctrl->hasFocus())
- {
- ctrl->setFocus(true);
- ctrl->onTabInto();
- if(focus_flash)
- {
- gFocusMgr.triggerFocusFlash();
- }
- }
- return true;
- }
- }
- // no text field found, or we don't care about text fields
- result = getTabOrderQuery().run(this);
- if(result.size() > 0)
- {
- LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back());
- if(!ctrl->hasFocus())
- {
- ctrl->setFocus(true);
- ctrl->onTabInto();
- if(focus_flash)
- {
- gFocusMgr.triggerFocusFlash();
- }
- }
- return true;
- }
- return false;
-}
-
-
-bool LLUICtrl::focusNextItem(bool text_fields_only)
-{
- // this assumes that this method is called on the focus root.
- LLViewQuery query = getTabOrderQuery();
- static LLUICachedControl<bool> tab_to_text_fields_only ("TabToTextFieldsOnly", false);
- if(text_fields_only || tab_to_text_fields_only)
- {
- query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
- }
- child_list_t result = query(this);
- return focusNext(result);
-}
-
-bool LLUICtrl::focusPrevItem(bool text_fields_only)
-{
- // this assumes that this method is called on the focus root.
- LLViewQuery query = getTabOrderQuery();
- static LLUICachedControl<bool> tab_to_text_fields_only ("TabToTextFieldsOnly", false);
- if(text_fields_only || tab_to_text_fields_only)
- {
- query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
- }
- child_list_t result = query(this);
- return focusPrev(result);
-}
-
-LLUICtrl* LLUICtrl::findRootMostFocusRoot()
-{
- LLUICtrl* focus_root = NULL;
- LLUICtrl* next_view = this;
- while(next_view && next_view->hasTabStop())
- {
- if (next_view->isFocusRoot())
- {
- focus_root = next_view;
- }
- next_view = next_view->getParentUICtrl();
- }
-
- return focus_root;
-}
-
-// Skip over any parents that are not LLUICtrl's
-// Used in focus logic since only LLUICtrl elements can have focus
-LLUICtrl* LLUICtrl::getParentUICtrl() const
-{
- LLView* parent = getParent();
- while (parent)
- {
- if (parent->isCtrl())
- {
- return (LLUICtrl*)(parent);
- }
- else
- {
- parent = parent->getParent();
- }
- }
- return NULL;
-}
-
-bool LLUICtrl::findHelpTopic(std::string& help_topic_out)
-{
- LLUICtrl* ctrl = this;
-
- // search back through the control's parents for a panel
- // or tab with a help_topic string defined
- while (ctrl)
- {
- LLPanel *panel = dynamic_cast<LLPanel *>(ctrl);
-
- if (panel)
- {
-
- LLView *child;
- LLPanel *subpanel = NULL;
-
- // does the panel have a sub-panel with a help topic?
- bfs_tree_iterator_t it = beginTreeBFS();
- // skip ourselves
- ++it;
- for (; it != endTreeBFS(); ++it)
- {
- child = *it;
- // do we have a panel with a help topic?
- LLPanel *panel = dynamic_cast<LLPanel *>(child);
- if (panel && panel->isInVisibleChain() && !panel->getHelpTopic().empty())
- {
- subpanel = panel;
- break;
- }
- }
-
- if (subpanel)
- {
- help_topic_out = subpanel->getHelpTopic();
- return true; // success (subpanel)
- }
-
- // does the panel have an active tab with a help topic?
- LLPanel *tab_panel = NULL;
-
- it = beginTreeBFS();
- // skip ourselves
- ++it;
- for (; it != endTreeBFS(); ++it)
- {
- child = *it;
- LLPanel *curTabPanel = NULL;
-
- // do we have a tab container?
- LLTabContainer *tab = dynamic_cast<LLTabContainer *>(child);
- if (tab && tab->getVisible())
- {
- curTabPanel = tab->getCurrentPanel();
- }
-
- // do we have an accordion tab?
- LLAccordionCtrlTab* accordion = dynamic_cast<LLAccordionCtrlTab *>(child);
- if (accordion && accordion->getDisplayChildren())
- {
- curTabPanel = dynamic_cast<LLPanel *>(accordion->getAccordionView());
- }
-
- // if we found a valid tab, does it have a help topic?
- if (curTabPanel && !curTabPanel->getHelpTopic().empty())
- {
- tab_panel = curTabPanel;
- break;
- }
- }
-
- if (tab_panel)
- {
- help_topic_out = tab_panel->getHelpTopic();
- return true; // success (tab)
- }
-
- // otherwise, does the panel have a help topic itself?
- if (!panel->getHelpTopic().empty())
- {
- help_topic_out = panel->getHelpTopic();
- return true; // success (panel)
- }
- }
-
- ctrl = ctrl->getParentUICtrl();
- }
-
- return false; // no help topic found
-}
-
-// *TODO: Deprecate; for backwards compatability only:
-boost::signals2::connection LLUICtrl::setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data)
-{
- return setCommitCallback( boost::bind(cb, _1, data));
-}
-boost::signals2::connection LLUICtrl::setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb )
-{
- if (!mValidateSignal) mValidateSignal = new enable_signal_t();
-
- return mValidateSignal->connect(boost::bind(cb, _2));
-}
-
-// virtual
-void LLUICtrl::setTentative(bool b)
-{
- mTentative = b;
-}
-
-// virtual
-bool LLUICtrl::getTentative() const
-{
- return mTentative;
-}
-
-// virtual
-void LLUICtrl::setColor(const LLColor4& color)
-{ }
-
-F32 LLUICtrl::getCurrentTransparency()
-{
- F32 alpha = 0;
-
- switch(mTransparencyType)
- {
- case TT_DEFAULT:
- alpha = getDrawContext().mAlpha;
- break;
-
- case TT_ACTIVE:
- alpha = sActiveControlTransparency;
- break;
-
- case TT_INACTIVE:
- alpha = sInactiveControlTransparency;
- break;
-
- case TT_FADING:
- alpha = sInactiveControlTransparency / 2;
- break;
- }
-
- return alpha;
-}
-
-void LLUICtrl::setTransparencyType(ETypeTransparency type)
-{
- mTransparencyType = type;
-}
-
-boost::signals2::connection LLUICtrl::setCommitCallback(const CommitCallbackParam& cb)
-{
- return setCommitCallback(initCommitCallback(cb));
-}
-
-boost::signals2::connection LLUICtrl::setValidateCallback(const EnableCallbackParam& cb)
-{
- return setValidateCallback(initEnableCallback(cb));
-}
-
-boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::slot_type& cb )
-{
- if (!mCommitSignal) mCommitSignal = new commit_signal_t();
-
- return mCommitSignal->connect(cb);
-}
-
-boost::signals2::connection LLUICtrl::setValidateCallback( const enable_signal_t::slot_type& cb )
-{
- if (!mValidateSignal) mValidateSignal = new enable_signal_t();
-
- return mValidateSignal->connect(cb);
-}
-
-boost::signals2::connection LLUICtrl::setMouseEnterCallback( const commit_signal_t::slot_type& cb )
-{
- if (!mMouseEnterSignal) mMouseEnterSignal = new commit_signal_t();
-
- return mMouseEnterSignal->connect(cb);
-}
-
-boost::signals2::connection LLUICtrl::setMouseLeaveCallback( const commit_signal_t::slot_type& cb )
-{
- if (!mMouseLeaveSignal) mMouseLeaveSignal = new commit_signal_t();
-
- return mMouseLeaveSignal->connect(cb);
-}
-
-boost::signals2::connection LLUICtrl::setMouseDownCallback( const mouse_signal_t::slot_type& cb )
-{
- if (!mMouseDownSignal) mMouseDownSignal = new mouse_signal_t();
-
- return mMouseDownSignal->connect(cb);
-}
-
-boost::signals2::connection LLUICtrl::setMouseUpCallback( const mouse_signal_t::slot_type& cb )
-{
- if (!mMouseUpSignal) mMouseUpSignal = new mouse_signal_t();
-
- return mMouseUpSignal->connect(cb);
-}
-
-boost::signals2::connection LLUICtrl::setRightMouseDownCallback( const mouse_signal_t::slot_type& cb )
-{
- if (!mRightMouseDownSignal) mRightMouseDownSignal = new mouse_signal_t();
-
- return mRightMouseDownSignal->connect(cb);
-}
-
-boost::signals2::connection LLUICtrl::setRightMouseUpCallback( const mouse_signal_t::slot_type& cb )
-{
- if (!mRightMouseUpSignal) mRightMouseUpSignal = new mouse_signal_t();
-
- return mRightMouseUpSignal->connect(cb);
-}
-
-boost::signals2::connection LLUICtrl::setDoubleClickCallback( const mouse_signal_t::slot_type& cb )
-{
- if (!mDoubleClickSignal) mDoubleClickSignal = new mouse_signal_t();
-
- return mDoubleClickSignal->connect(cb);
-}
-
-void LLUICtrl::addInfo(LLSD & info)
-{
- LLView::addInfo(info);
- info["value"] = getValue();
-}
+/**
+ * @file lluictrl.cpp
+ * @author James Cook, Richard Nelson, Tom Yedwab
+ * @brief Abstract base class for UI controls
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#define LLUICTRL_CPP
+#include "lluictrl.h"
+#include "llviewereventrecorder.h"
+#include "llfocusmgr.h"
+#include "llpanel.h"
+#include "lluictrlfactory.h"
+#include "lltabcontainer.h"
+#include "llaccordionctrltab.h"
+#include "lluiusage.h"
+
+static LLDefaultChildRegistry::Register<LLUICtrl> r("ui_ctrl");
+
+F32 LLUICtrl::sActiveControlTransparency = 1.0f;
+F32 LLUICtrl::sInactiveControlTransparency = 1.0f;
+
+// Compiler optimization, generate extern template
+template class LLUICtrl* LLView::getChild<class LLUICtrl>(
+ const std::string& name, bool recurse) const;
+
+LLUICtrl::CallbackParam::CallbackParam()
+: name("name"),
+ function_name("function"),
+ parameter("parameter"),
+ control_name("control") // Shortcut to control -> "control_name" for backwards compatability
+{
+ addSynonym(parameter, "userdata");
+}
+
+LLUICtrl::EnableControls::EnableControls()
+: enabled("enabled_control"),
+ disabled("disabled_control")
+{}
+
+LLUICtrl::ControlVisibility::ControlVisibility()
+: visible("visibility_control"),
+ invisible("invisibility_control")
+{
+ addSynonym(visible, "visiblity_control");
+ addSynonym(invisible, "invisiblity_control");
+}
+
+LLUICtrl::Params::Params()
+: tab_stop("tab_stop", true),
+ chrome("chrome", false),
+ requests_front("requests_front", false),
+ label("label"),
+ initial_value("value"),
+ init_callback("init_callback"),
+ commit_callback("commit_callback"),
+ validate_callback("validate_callback"),
+ mouseenter_callback("mouseenter_callback"),
+ mouseleave_callback("mouseleave_callback"),
+ control_name("control_name"),
+ font("font", LLFontGL::getFontEmojiMedium()),
+ font_halign("halign"),
+ font_valign("valign"),
+ length("length"), // ignore LLXMLNode cruft
+ type("type") // ignore LLXMLNode cruft
+{
+ addSynonym(initial_value, "initial_value");
+}
+
+// NOTE: the LLFocusableElement implementation has been moved from here to llfocusmgr.cpp.
+
+//static
+const LLUICtrl::Params& LLUICtrl::getDefaultParams()
+{
+ return LLUICtrlFactory::getDefaultParams<LLUICtrl>();
+}
+
+
+LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel)
+: LLView(p),
+ mIsChrome(false),
+ mRequestsFront(p.requests_front),
+ mTabStop(false),
+ mTentative(false),
+ mViewModel(viewmodel),
+ mControlVariable(NULL),
+ mEnabledControlVariable(NULL),
+ mDisabledControlVariable(NULL),
+ mMakeVisibleControlVariable(NULL),
+ mMakeInvisibleControlVariable(NULL),
+ mCommitSignal(NULL),
+ mValidateSignal(NULL),
+ mMouseEnterSignal(NULL),
+ mMouseLeaveSignal(NULL),
+ mMouseDownSignal(NULL),
+ mMouseUpSignal(NULL),
+ mRightMouseDownSignal(NULL),
+ mRightMouseUpSignal(NULL),
+ mDoubleClickSignal(NULL),
+ mTransparencyType(TT_DEFAULT)
+{
+}
+
+void LLUICtrl::initFromParams(const Params& p)
+{
+ LLView::initFromParams(p);
+
+ mRequestsFront = p.requests_front;
+
+ setIsChrome(p.chrome);
+ setControlName(p.control_name);
+ if(p.enabled_controls.isProvided())
+ {
+ if (p.enabled_controls.enabled.isChosen())
+ {
+ LLControlVariable* control = findControl(p.enabled_controls.enabled);
+ if (control)
+ {
+ setEnabledControlVariable(control);
+ }
+ else
+ {
+ LL_WARNS() << "Failed to assign 'enabled' control variable to " << getName()
+ << ": control " << p.enabled_controls.enabled()
+ << " does not exist." << LL_ENDL;
+ }
+ }
+ else if(p.enabled_controls.disabled.isChosen())
+ {
+ LLControlVariable* control = findControl(p.enabled_controls.disabled);
+ if (control)
+ {
+ setDisabledControlVariable(control);
+ }
+ else
+ {
+ LL_WARNS() << "Failed to assign 'disabled' control variable to " << getName()
+ << ": control " << p.enabled_controls.disabled()
+ << " does not exist." << LL_ENDL;
+ }
+ }
+ }
+ if(p.controls_visibility.isProvided())
+ {
+ if (p.controls_visibility.visible.isChosen())
+ {
+ LLControlVariable* control = findControl(p.controls_visibility.visible);
+ if (control)
+ {
+ setMakeVisibleControlVariable(control);
+ }
+ else
+ {
+ LL_WARNS() << "Failed to assign visibility control variable to " << getName()
+ << ": control " << p.controls_visibility.visible()
+ << " does not exist." << LL_ENDL;
+ }
+ }
+ else if (p.controls_visibility.invisible.isChosen())
+ {
+ LLControlVariable* control = findControl(p.controls_visibility.invisible);
+ if (control)
+ {
+ setMakeInvisibleControlVariable(control);
+ }
+ else
+ {
+ LL_WARNS() << "Failed to assign invisibility control variable to " << getName()
+ << ": control " << p.controls_visibility.invisible()
+ << " does not exist." << LL_ENDL;
+ }
+ }
+ }
+
+ setTabStop(p.tab_stop);
+
+ if (p.initial_value.isProvided()
+ && !p.control_name.isProvided())
+ {
+ setValue(p.initial_value);
+ }
+
+ if (p.commit_callback.isProvided())
+ {
+ setCommitCallback(initCommitCallback(p.commit_callback));
+ }
+
+ if (p.validate_callback.isProvided())
+ {
+ setValidateCallback(initEnableCallback(p.validate_callback));
+ }
+
+ if (p.init_callback.isProvided())
+ {
+ if (p.init_callback.function.isProvided())
+ {
+ p.init_callback.function()(this, p.init_callback.parameter);
+ }
+ else
+ {
+ commit_callback_t* initfunc = (CommitCallbackRegistry::getValue(p.init_callback.function_name));
+ if (initfunc)
+ {
+ (*initfunc)(this, p.init_callback.parameter);
+ }
+ }
+ }
+
+ if(p.mouseenter_callback.isProvided())
+ {
+ setMouseEnterCallback(initCommitCallback(p.mouseenter_callback));
+ }
+
+ if(p.mouseleave_callback.isProvided())
+ {
+ setMouseLeaveCallback(initCommitCallback(p.mouseleave_callback));
+ }
+}
+
+
+LLUICtrl::~LLUICtrl()
+{
+ gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit()
+
+ if( gFocusMgr.getTopCtrl() == this )
+ {
+ LL_WARNS() << "UI Control holding top ctrl deleted: " << getName() << ". Top view removed." << LL_ENDL;
+ gFocusMgr.removeTopCtrlWithoutCallback( this );
+ }
+
+ delete mCommitSignal;
+ delete mValidateSignal;
+ delete mMouseEnterSignal;
+ delete mMouseLeaveSignal;
+ delete mMouseDownSignal;
+ delete mMouseUpSignal;
+ delete mRightMouseDownSignal;
+ delete mRightMouseUpSignal;
+ delete mDoubleClickSignal;
+}
+
+void default_commit_handler(LLUICtrl* ctrl, const LLSD& param)
+{}
+
+bool default_enable_handler(LLUICtrl* ctrl, const LLSD& param)
+{
+ return true;
+}
+
+
+LLUICtrl::commit_signal_t::slot_type LLUICtrl::initCommitCallback(const CommitCallbackParam& cb)
+{
+ if (cb.function.isProvided())
+ {
+ if (cb.parameter.isProvided())
+ return boost::bind(cb.function(), _1, cb.parameter);
+ else
+ return cb.function();
+ }
+ else
+ {
+ std::string function_name = cb.function_name;
+ setFunctionName(function_name);
+ commit_callback_t* func = (CommitCallbackRegistry::getValue(function_name));
+ if (func)
+ {
+ if (cb.parameter.isProvided())
+ return boost::bind((*func), _1, cb.parameter);
+ else
+ return commit_signal_t::slot_type(*func);
+ }
+ else if (!function_name.empty())
+ {
+ LL_WARNS() << "No callback found for: '" << function_name << "' in control: " << getName() << LL_ENDL;
+ }
+ }
+ return default_commit_handler;
+}
+
+LLUICtrl::enable_signal_t::slot_type LLUICtrl::initEnableCallback(const EnableCallbackParam& cb)
+{
+ // Set the callback function
+ if (cb.function.isProvided())
+ {
+ if (cb.parameter.isProvided())
+ return boost::bind(cb.function(), this, cb.parameter);
+ else
+ return cb.function();
+ }
+ else
+ {
+ enable_callback_t* func = (EnableCallbackRegistry::getValue(cb.function_name));
+ if (func)
+ {
+ if (cb.parameter.isProvided())
+ return boost::bind((*func), this, cb.parameter);
+ else
+ return enable_signal_t::slot_type(*func);
+ }
+ }
+ return default_enable_handler;
+}
+
+// virtual
+void LLUICtrl::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ if (mMouseEnterSignal)
+ {
+ (*mMouseEnterSignal)(this, getValue());
+ }
+}
+
+// virtual
+void LLUICtrl::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ if(mMouseLeaveSignal)
+ {
+ (*mMouseLeaveSignal)(this, getValue());
+ }
+}
+
+//virtual
+bool LLUICtrl::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+
+ LL_DEBUGS() << "LLUICtrl::handleMouseDown calling LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << LL_ENDL;
+
+ bool handled = LLView::handleMouseDown(x,y,mask);
+
+ if (mMouseDownSignal)
+ {
+ (*mMouseDownSignal)(this,x,y,mask);
+ }
+ LL_DEBUGS() << "LLUICtrl::handleMousedown - handled is returning as: " << handled << " " << LL_ENDL;
+
+ if (handled) {
+ LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-56,-56,getPathname());
+ }
+ return handled;
+}
+
+//virtual
+bool LLUICtrl::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+
+ LL_DEBUGS() << "LLUICtrl::handleMouseUp calling LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << LL_ENDL;
+
+ bool handled = LLView::handleMouseUp(x,y,mask);
+ if (handled) {
+ LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-56,-56,getPathname());
+ }
+ if (mMouseUpSignal)
+ {
+ (*mMouseUpSignal)(this,x,y,mask);
+ }
+
+ LL_DEBUGS() << "LLUICtrl::handleMouseUp - handled for xui " << getPathname() << " - is returning as: " << handled << " " << LL_ENDL;
+
+ return handled;
+}
+
+//virtual
+bool LLUICtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ bool handled = LLView::handleRightMouseDown(x,y,mask);
+ if (mRightMouseDownSignal)
+ {
+ (*mRightMouseDownSignal)(this,x,y,mask);
+ }
+ return handled;
+}
+
+//virtual
+bool LLUICtrl::handleRightMouseUp(S32 x, S32 y, MASK mask)
+{
+ bool handled = LLView::handleRightMouseUp(x,y,mask);
+ if(mRightMouseUpSignal)
+ {
+ (*mRightMouseUpSignal)(this,x,y,mask);
+ }
+ return handled;
+}
+
+bool LLUICtrl::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+ bool handled = LLView::handleDoubleClick(x, y, mask);
+ if (mDoubleClickSignal)
+ {
+ (*mDoubleClickSignal)(this, x, y, mask);
+ }
+ return handled;
+}
+
+// can't tab to children of a non-tab-stop widget
+bool LLUICtrl::canFocusChildren() const
+{
+ return hasTabStop();
+}
+
+
+void LLUICtrl::onCommit()
+{
+ if (mCommitSignal)
+ {
+ if (!mFunctionName.empty())
+ {
+ LL_DEBUGS("UIUsage") << "calling commit function " << mFunctionName << LL_ENDL;
+ LLUIUsage::instance().logCommand(mFunctionName);
+ LLUIUsage::instance().logControl(getPathname());
+ }
+ else
+ {
+ //LL_DEBUGS("UIUsage") << "calling commit function " << "UNKNOWN" << LL_ENDL;
+ }
+ (*mCommitSignal)(this, getValue());
+ }
+}
+
+//virtual
+bool LLUICtrl::isCtrl() const
+{
+ return true;
+}
+
+//virtual
+void LLUICtrl::setValue(const LLSD& value)
+{
+ mViewModel->setValue(value);
+}
+
+//virtual
+LLSD LLUICtrl::getValue() const
+{
+ return mViewModel->getValue();
+}
+
+/// When two widgets are displaying the same data (e.g. during a skin
+/// change), share their ViewModel.
+void LLUICtrl::shareViewModelFrom(const LLUICtrl& other)
+{
+ // Because mViewModel is an LLViewModelPtr, this assignment will quietly
+ // dispose of the previous LLViewModel -- unless it's already shared by
+ // somebody else.
+ mViewModel = other.mViewModel;
+}
+
+//virtual
+LLViewModel* LLUICtrl::getViewModel() const
+{
+ return mViewModel;
+}
+
+//virtual
+bool LLUICtrl::postBuild()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
+ //
+ // Find all of the children that want to be in front and move them to the front
+ //
+
+ if (getChildCount() > 0)
+ {
+ std::vector<LLUICtrl*> childrenToMoveToFront;
+
+ for (LLView::child_list_const_iter_t child_it = beginChild(); child_it != endChild(); ++child_it)
+ {
+ LLUICtrl* uictrl = dynamic_cast<LLUICtrl*>(*child_it);
+
+ if (uictrl && uictrl->mRequestsFront)
+ {
+ childrenToMoveToFront.push_back(uictrl);
+ }
+ }
+
+ for (std::vector<LLUICtrl*>::iterator it = childrenToMoveToFront.begin(); it != childrenToMoveToFront.end(); ++it)
+ {
+ sendChildToFront(*it);
+ }
+ }
+
+ return LLView::postBuild();
+}
+
+bool LLUICtrl::setControlValue(const LLSD& value)
+{
+ if (mControlVariable)
+ {
+ mControlVariable->set(value);
+ return true;
+ }
+ return false;
+}
+
+void LLUICtrl::setControlVariable(LLControlVariable* control)
+{
+ if (mControlVariable)
+ {
+ //RN: this will happen in practice, should we try to avoid it?
+ //LL_WARNS() << "setControlName called twice on same control!" << LL_ENDL;
+ mControlConnection.disconnect(); // disconnect current signal
+ mControlVariable = NULL;
+ }
+
+ if (control)
+ {
+ mControlVariable = control;
+ mControlConnection = mControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("value")));
+ setValue(mControlVariable->getValue());
+ }
+}
+
+void LLUICtrl::removeControlVariable()
+{
+ if (mControlVariable)
+ {
+ mControlConnection.disconnect();
+ mControlVariable = NULL;
+ }
+}
+
+//virtual
+void LLUICtrl::setControlName(const std::string& control_name, LLView *context)
+{
+ if (context == NULL)
+ {
+ context = this;
+ }
+
+ // Register new listener
+ if (!control_name.empty())
+ {
+ LLControlVariable* control = context->findControl(control_name);
+ if (!control)
+ {
+ LL_WARNS() << "Failed to assign control variable to " << getName()
+ << ": control "<< control_name << " does not exist." << LL_ENDL;
+ }
+ setControlVariable(control);
+ }
+}
+
+void LLUICtrl::setEnabledControlVariable(LLControlVariable* control)
+{
+ if (mEnabledControlVariable)
+ {
+ mEnabledControlConnection.disconnect(); // disconnect current signal
+ mEnabledControlVariable = NULL;
+ }
+ if (control)
+ {
+ mEnabledControlVariable = control;
+ mEnabledControlConnection = mEnabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("enabled")));
+ setEnabled(mEnabledControlVariable->getValue().asBoolean());
+ }
+}
+
+void LLUICtrl::setDisabledControlVariable(LLControlVariable* control)
+{
+ if (mDisabledControlVariable)
+ {
+ mDisabledControlConnection.disconnect(); // disconnect current signal
+ mDisabledControlVariable = NULL;
+ }
+ if (control)
+ {
+ mDisabledControlVariable = control;
+ mDisabledControlConnection = mDisabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("disabled")));
+ setEnabled(!(mDisabledControlVariable->getValue().asBoolean()));
+ }
+}
+
+void LLUICtrl::setMakeVisibleControlVariable(LLControlVariable* control)
+{
+ if (mMakeVisibleControlVariable)
+ {
+ mMakeVisibleControlConnection.disconnect(); // disconnect current signal
+ mMakeVisibleControlVariable = NULL;
+ }
+ if (control)
+ {
+ mMakeVisibleControlVariable = control;
+ mMakeVisibleControlConnection = mMakeVisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("visible")));
+ setVisible(mMakeVisibleControlVariable->getValue().asBoolean());
+ }
+}
+
+void LLUICtrl::setMakeInvisibleControlVariable(LLControlVariable* control)
+{
+ if (mMakeInvisibleControlVariable)
+ {
+ mMakeInvisibleControlConnection.disconnect(); // disconnect current signal
+ mMakeInvisibleControlVariable = NULL;
+ }
+ if (control)
+ {
+ mMakeInvisibleControlVariable = control;
+ mMakeInvisibleControlConnection = mMakeInvisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("invisible")));
+ setVisible(!(mMakeInvisibleControlVariable->getValue().asBoolean()));
+ }
+}
+
+void LLUICtrl::setFunctionName(const std::string& function_name)
+{
+ mFunctionName = function_name;
+}
+
+// static
+bool LLUICtrl::controlListener(const LLSD& newvalue, LLHandle<LLUICtrl> handle, std::string type)
+{
+ LLUICtrl* ctrl = handle.get();
+ if (ctrl)
+ {
+ if (type == "value")
+ {
+ ctrl->setValue(newvalue);
+ return true;
+ }
+ else if (type == "enabled")
+ {
+ ctrl->setEnabled(newvalue.asBoolean());
+ return true;
+ }
+ else if(type =="disabled")
+ {
+ ctrl->setEnabled(!newvalue.asBoolean());
+ return true;
+ }
+ else if (type == "visible")
+ {
+ ctrl->setVisible(newvalue.asBoolean());
+ return true;
+ }
+ else if (type == "invisible")
+ {
+ ctrl->setVisible(!newvalue.asBoolean());
+ return true;
+ }
+ }
+ return false;
+}
+
+// virtual
+bool LLUICtrl::setTextArg( const std::string& key, const LLStringExplicit& text )
+{
+ return false;
+}
+
+// virtual
+bool LLUICtrl::setLabelArg( const std::string& key, const LLStringExplicit& text )
+{
+ return false;
+}
+
+// virtual
+LLCtrlSelectionInterface* LLUICtrl::getSelectionInterface()
+{
+ return NULL;
+}
+
+// virtual
+LLCtrlListInterface* LLUICtrl::getListInterface()
+{
+ return NULL;
+}
+
+// virtual
+LLCtrlScrollInterface* LLUICtrl::getScrollInterface()
+{
+ return NULL;
+}
+
+bool LLUICtrl::hasFocus() const
+{
+ return (gFocusMgr.childHasKeyboardFocus(this));
+}
+
+void LLUICtrl::setFocus(bool b)
+{
+ // focus NEVER goes to ui ctrls that are disabled!
+ if (!getEnabled())
+ {
+ return;
+ }
+ if( b )
+ {
+ if (!hasFocus())
+ {
+ gFocusMgr.setKeyboardFocus( this );
+ }
+ }
+ else
+ {
+ if( gFocusMgr.childHasKeyboardFocus(this))
+ {
+ gFocusMgr.setKeyboardFocus( NULL );
+ }
+ }
+}
+
+// virtual
+void LLUICtrl::setTabStop( bool b )
+{
+ mTabStop = b;
+}
+
+// virtual
+bool LLUICtrl::hasTabStop() const
+{
+ return mTabStop;
+}
+
+// virtual
+bool LLUICtrl::acceptsTextInput() const
+{
+ return false;
+}
+
+//virtual
+bool LLUICtrl::isDirty() const
+{
+ return mViewModel->isDirty();
+};
+
+//virtual
+void LLUICtrl::resetDirty()
+{
+ mViewModel->resetDirty();
+}
+
+// virtual
+void LLUICtrl::onTabInto()
+{
+ onUpdateScrollToChild(this);
+}
+
+// virtual
+void LLUICtrl::clear()
+{
+}
+
+// virtual
+void LLUICtrl::setIsChrome(bool is_chrome)
+{
+ mIsChrome = is_chrome;
+}
+
+// virtual
+bool LLUICtrl::getIsChrome() const
+{
+ if (mIsChrome)
+ return true;
+
+ LLView* parent_ctrl = getParent();
+ while (parent_ctrl)
+ {
+ if (parent_ctrl->isCtrl())
+ return ((LLUICtrl*)parent_ctrl)->getIsChrome();
+
+ parent_ctrl = parent_ctrl->getParent();
+ }
+
+ return false;
+}
+
+
+bool LLUICtrl::focusFirstItem(bool prefer_text_fields, bool focus_flash)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
+ // try to select default tab group child
+ LLViewQuery query = getTabOrderQuery();
+ child_list_t result = query(this);
+ if(result.size() > 0)
+ {
+ LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back());
+ if(!ctrl->hasFocus())
+ {
+ ctrl->setFocus(true);
+ ctrl->onTabInto();
+ if(focus_flash)
+ {
+ gFocusMgr.triggerFocusFlash();
+ }
+ }
+ return true;
+ }
+ // search for text field first
+ if(prefer_text_fields)
+ {
+ LLViewQuery query = getTabOrderQuery();
+ query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
+ child_list_t result = query(this);
+ if(result.size() > 0)
+ {
+ LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back());
+ if(!ctrl->hasFocus())
+ {
+ ctrl->setFocus(true);
+ ctrl->onTabInto();
+ if(focus_flash)
+ {
+ gFocusMgr.triggerFocusFlash();
+ }
+ }
+ return true;
+ }
+ }
+ // no text field found, or we don't care about text fields
+ result = getTabOrderQuery().run(this);
+ if(result.size() > 0)
+ {
+ LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back());
+ if(!ctrl->hasFocus())
+ {
+ ctrl->setFocus(true);
+ ctrl->onTabInto();
+ if(focus_flash)
+ {
+ gFocusMgr.triggerFocusFlash();
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool LLUICtrl::focusNextItem(bool text_fields_only)
+{
+ // this assumes that this method is called on the focus root.
+ LLViewQuery query = getTabOrderQuery();
+ static LLUICachedControl<bool> tab_to_text_fields_only ("TabToTextFieldsOnly", false);
+ if(text_fields_only || tab_to_text_fields_only)
+ {
+ query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
+ }
+ child_list_t result = query(this);
+ return focusNext(result);
+}
+
+bool LLUICtrl::focusPrevItem(bool text_fields_only)
+{
+ // this assumes that this method is called on the focus root.
+ LLViewQuery query = getTabOrderQuery();
+ static LLUICachedControl<bool> tab_to_text_fields_only ("TabToTextFieldsOnly", false);
+ if(text_fields_only || tab_to_text_fields_only)
+ {
+ query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
+ }
+ child_list_t result = query(this);
+ return focusPrev(result);
+}
+
+LLUICtrl* LLUICtrl::findRootMostFocusRoot()
+{
+ LLUICtrl* focus_root = NULL;
+ LLUICtrl* next_view = this;
+ while(next_view && next_view->hasTabStop())
+ {
+ if (next_view->isFocusRoot())
+ {
+ focus_root = next_view;
+ }
+ next_view = next_view->getParentUICtrl();
+ }
+
+ return focus_root;
+}
+
+// Skip over any parents that are not LLUICtrl's
+// Used in focus logic since only LLUICtrl elements can have focus
+LLUICtrl* LLUICtrl::getParentUICtrl() const
+{
+ LLView* parent = getParent();
+ while (parent)
+ {
+ if (parent->isCtrl())
+ {
+ return (LLUICtrl*)(parent);
+ }
+ else
+ {
+ parent = parent->getParent();
+ }
+ }
+ return NULL;
+}
+
+bool LLUICtrl::findHelpTopic(std::string& help_topic_out)
+{
+ LLUICtrl* ctrl = this;
+
+ // search back through the control's parents for a panel
+ // or tab with a help_topic string defined
+ while (ctrl)
+ {
+ LLPanel *panel = dynamic_cast<LLPanel *>(ctrl);
+
+ if (panel)
+ {
+
+ LLView *child;
+ LLPanel *subpanel = NULL;
+
+ // does the panel have a sub-panel with a help topic?
+ bfs_tree_iterator_t it = beginTreeBFS();
+ // skip ourselves
+ ++it;
+ for (; it != endTreeBFS(); ++it)
+ {
+ child = *it;
+ // do we have a panel with a help topic?
+ LLPanel *panel = dynamic_cast<LLPanel *>(child);
+ if (panel && panel->isInVisibleChain() && !panel->getHelpTopic().empty())
+ {
+ subpanel = panel;
+ break;
+ }
+ }
+
+ if (subpanel)
+ {
+ help_topic_out = subpanel->getHelpTopic();
+ return true; // success (subpanel)
+ }
+
+ // does the panel have an active tab with a help topic?
+ LLPanel *tab_panel = NULL;
+
+ it = beginTreeBFS();
+ // skip ourselves
+ ++it;
+ for (; it != endTreeBFS(); ++it)
+ {
+ child = *it;
+ LLPanel *curTabPanel = NULL;
+
+ // do we have a tab container?
+ LLTabContainer *tab = dynamic_cast<LLTabContainer *>(child);
+ if (tab && tab->getVisible())
+ {
+ curTabPanel = tab->getCurrentPanel();
+ }
+
+ // do we have an accordion tab?
+ LLAccordionCtrlTab* accordion = dynamic_cast<LLAccordionCtrlTab *>(child);
+ if (accordion && accordion->getDisplayChildren())
+ {
+ curTabPanel = dynamic_cast<LLPanel *>(accordion->getAccordionView());
+ }
+
+ // if we found a valid tab, does it have a help topic?
+ if (curTabPanel && !curTabPanel->getHelpTopic().empty())
+ {
+ tab_panel = curTabPanel;
+ break;
+ }
+ }
+
+ if (tab_panel)
+ {
+ help_topic_out = tab_panel->getHelpTopic();
+ return true; // success (tab)
+ }
+
+ // otherwise, does the panel have a help topic itself?
+ if (!panel->getHelpTopic().empty())
+ {
+ help_topic_out = panel->getHelpTopic();
+ return true; // success (panel)
+ }
+ }
+
+ ctrl = ctrl->getParentUICtrl();
+ }
+
+ return false; // no help topic found
+}
+
+// *TODO: Deprecate; for backwards compatability only:
+boost::signals2::connection LLUICtrl::setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data)
+{
+ return setCommitCallback( boost::bind(cb, _1, data));
+}
+boost::signals2::connection LLUICtrl::setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb )
+{
+ if (!mValidateSignal) mValidateSignal = new enable_signal_t();
+
+ return mValidateSignal->connect(boost::bind(cb, _2));
+}
+
+// virtual
+void LLUICtrl::setTentative(bool b)
+{
+ mTentative = b;
+}
+
+// virtual
+bool LLUICtrl::getTentative() const
+{
+ return mTentative;
+}
+
+// virtual
+void LLUICtrl::setColor(const LLColor4& color)
+{ }
+
+F32 LLUICtrl::getCurrentTransparency()
+{
+ F32 alpha = 0;
+
+ switch(mTransparencyType)
+ {
+ case TT_DEFAULT:
+ alpha = getDrawContext().mAlpha;
+ break;
+
+ case TT_ACTIVE:
+ alpha = sActiveControlTransparency;
+ break;
+
+ case TT_INACTIVE:
+ alpha = sInactiveControlTransparency;
+ break;
+
+ case TT_FADING:
+ alpha = sInactiveControlTransparency / 2;
+ break;
+ }
+
+ return alpha;
+}
+
+void LLUICtrl::setTransparencyType(ETypeTransparency type)
+{
+ mTransparencyType = type;
+}
+
+boost::signals2::connection LLUICtrl::setCommitCallback(const CommitCallbackParam& cb)
+{
+ return setCommitCallback(initCommitCallback(cb));
+}
+
+boost::signals2::connection LLUICtrl::setValidateCallback(const EnableCallbackParam& cb)
+{
+ return setValidateCallback(initEnableCallback(cb));
+}
+
+boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::slot_type& cb )
+{
+ if (!mCommitSignal) mCommitSignal = new commit_signal_t();
+
+ return mCommitSignal->connect(cb);
+}
+
+boost::signals2::connection LLUICtrl::setValidateCallback( const enable_signal_t::slot_type& cb )
+{
+ if (!mValidateSignal) mValidateSignal = new enable_signal_t();
+
+ return mValidateSignal->connect(cb);
+}
+
+boost::signals2::connection LLUICtrl::setMouseEnterCallback( const commit_signal_t::slot_type& cb )
+{
+ if (!mMouseEnterSignal) mMouseEnterSignal = new commit_signal_t();
+
+ return mMouseEnterSignal->connect(cb);
+}
+
+boost::signals2::connection LLUICtrl::setMouseLeaveCallback( const commit_signal_t::slot_type& cb )
+{
+ if (!mMouseLeaveSignal) mMouseLeaveSignal = new commit_signal_t();
+
+ return mMouseLeaveSignal->connect(cb);
+}
+
+boost::signals2::connection LLUICtrl::setMouseDownCallback( const mouse_signal_t::slot_type& cb )
+{
+ if (!mMouseDownSignal) mMouseDownSignal = new mouse_signal_t();
+
+ return mMouseDownSignal->connect(cb);
+}
+
+boost::signals2::connection LLUICtrl::setMouseUpCallback( const mouse_signal_t::slot_type& cb )
+{
+ if (!mMouseUpSignal) mMouseUpSignal = new mouse_signal_t();
+
+ return mMouseUpSignal->connect(cb);
+}
+
+boost::signals2::connection LLUICtrl::setRightMouseDownCallback( const mouse_signal_t::slot_type& cb )
+{
+ if (!mRightMouseDownSignal) mRightMouseDownSignal = new mouse_signal_t();
+
+ return mRightMouseDownSignal->connect(cb);
+}
+
+boost::signals2::connection LLUICtrl::setRightMouseUpCallback( const mouse_signal_t::slot_type& cb )
+{
+ if (!mRightMouseUpSignal) mRightMouseUpSignal = new mouse_signal_t();
+
+ return mRightMouseUpSignal->connect(cb);
+}
+
+boost::signals2::connection LLUICtrl::setDoubleClickCallback( const mouse_signal_t::slot_type& cb )
+{
+ if (!mDoubleClickSignal) mDoubleClickSignal = new mouse_signal_t();
+
+ return mDoubleClickSignal->connect(cb);
+}
+
+void LLUICtrl::addInfo(LLSD & info)
+{
+ LLView::addInfo(info);
+ info["value"] = getValue();
+}