diff options
Diffstat (limited to 'indra/llui/lluictrl.cpp')
-rw-r--r-- | indra/llui/lluictrl.cpp | 529 |
1 files changed, 397 insertions, 132 deletions
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 9d97312ab0..7ff942268d 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -36,103 +36,237 @@ #include "lluictrl.h" #include "llfocusmgr.h" #include "llpanel.h" +#include "lluictrlfactory.h" -static LLRegisterWidget<LLUICtrl> r("ui_ctrl"); +static LLDefaultChildRegistry::Register<LLUICtrl> r("ui_ctrl"); -LLFocusableElement::LLFocusableElement() -: mFocusLostCallback(NULL), - mFocusReceivedCallback(NULL), - mFocusChangedCallback(NULL), - mFocusCallbackUserData(NULL) +LLUICtrl::Params::Params() +: tab_stop("tab_stop", true), + 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") { + addSynonym(initial_value, "initial_value"); } -//virtual -LLFocusableElement::~LLFocusableElement() +// NOTE: the LLFocusableElement implementation has been moved from here to llfocusmgr.cpp. + +//static +const LLUICtrl::Params& LLUICtrl::getDefaultParams() { + return LLUICtrlFactory::getDefaultParams<LLUICtrl>(); } -void LLFocusableElement::onFocusReceived() + +LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel) +: LLView(p), + mTentative(FALSE), + mIsChrome(FALSE), + mViewModel(viewmodel), + mControlVariable(NULL), + mEnabledControlVariable(NULL), + mDisabledControlVariable(NULL), + mMakeVisibleControlVariable(NULL), + mMakeInvisibleControlVariable(NULL) { - if( mFocusReceivedCallback ) + mUICtrlHandle.bind(this); +} + +void LLUICtrl::initFromParams(const Params& p) +{ + LLView::initFromParams(p); + + 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 if(p.enabled_controls.disabled.isChosen()) + { + LLControlVariable* control = findControl(p.enabled_controls.disabled); + if (control) + setDisabledControlVariable(control); + } + } + if(p.controls_visibility.isProvided()) { - mFocusReceivedCallback( this, mFocusCallbackUserData ); + if (p.controls_visibility.visible.isChosen()) + { + LLControlVariable* control = findControl(p.controls_visibility.visible); + if (control) + setMakeVisibleControlVariable(control); + } + else if (p.controls_visibility.invisible.isChosen()) + { + LLControlVariable* control = findControl(p.controls_visibility.invisible); + if (control) + setMakeInvisibleControlVariable(control); + } } - if( mFocusChangedCallback ) + + setTabStop(p.tab_stop); + setFocusLostCallback(p.focus_lost_callback()); + + if (p.initial_value.isProvided() + && !p.control_name.isProvided()) + { + setValue(p.initial_value); + } + + if (p.commit_callback.isProvided()) + initCommitCallback(p.commit_callback, mCommitSignal); + + if (p.validate_callback.isProvided()) + initEnableCallback(p.validate_callback, mValidateSignal); + + if (p.init_callback.isProvided()) { - mFocusChangedCallback( this, mFocusCallbackUserData ); + 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()) + initCommitCallback(p.mouseenter_callback, mMouseEnterSignal); + + if(p.mouseleave_callback.isProvided()) + initCommitCallback(p.mouseleave_callback, mMouseLeaveSignal); } -void LLFocusableElement::onFocusLost() + +LLUICtrl::~LLUICtrl() { - if( mFocusLostCallback ) + gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() + + if( gFocusMgr.getTopCtrl() == this ) { - mFocusLostCallback( this, mFocusCallbackUserData ); + llwarns << "UI Control holding top ctrl deleted: " << getName() << ". Top view removed." << llendl; + gFocusMgr.removeTopCtrlWithoutCallback( this ); } +} - if( mFocusChangedCallback ) +void LLUICtrl::initCommitCallback(const CommitCallbackParam& cb, commit_signal_t& sig) +{ + if (cb.function.isProvided()) { - mFocusChangedCallback( this, mFocusCallbackUserData ); + if (cb.parameter.isProvided()) + sig.connect(boost::bind(cb.function(), _1, cb.parameter)); + else + sig.connect(cb.function()); + } + else + { + std::string function_name = cb.function_name; + commit_callback_t* func = (CommitCallbackRegistry::getValue(function_name)); + if (func) + { + if (cb.parameter.isProvided()) + sig.connect(boost::bind((*func), _1, cb.parameter)); + else + sig.connect(*func); + } + else if (!function_name.empty()) + { + llwarns << "No callback found for: '" << function_name << "' in control: " << getName() << llendl; + } } } -BOOL LLFocusableElement::hasFocus() const +void LLUICtrl::initEnableCallback(const EnableCallbackParam& cb, enable_signal_t& sig) { - return FALSE; + // Set the callback function + if (cb.function.isProvided()) + { + if (cb.parameter.isProvided()) + sig.connect(boost::bind(cb.function(), this, cb.parameter)); + else + sig.connect(cb.function()); + } + else + { + enable_callback_t* func = (EnableCallbackRegistry::getValue(cb.function_name)); + if (func) + { + if (cb.parameter.isProvided()) + sig.connect(boost::bind((*func), this, cb.parameter)); + else + sig.connect(*func); + } + } } -void LLFocusableElement::setFocus(BOOL b) +// virtual +void LLUICtrl::onMouseEnter(S32 x, S32 y, MASK mask) { + mMouseEnterSignal(this, getValue()); } +// virtual +void LLUICtrl::onMouseLeave(S32 x, S32 y, MASK mask) +{ + mMouseLeaveSignal(this, getValue()); +} +//virtual +BOOL LLUICtrl::handleMouseDown(S32 x, S32 y, MASK mask) +{ + BOOL handled = LLView::handleMouseDown(x,y,mask); + mMouseDownSignal(this,x,y,mask); + return handled; +} -LLUICtrl::LLUICtrl() : - mCommitCallback(NULL), - mLostTopCallback(NULL), - mValidateCallback(NULL), - mCallbackUserData(NULL), - mTentative(FALSE), - mTabStop(TRUE), - mIsChrome(FALSE) +//virtual +BOOL LLUICtrl::handleMouseUp(S32 x, S32 y, MASK mask) { + BOOL handled = LLView::handleMouseUp(x,y,mask); + mMouseUpSignal(this,x,y,mask); + return handled; } -LLUICtrl::LLUICtrl(const std::string& name, const LLRect& rect, BOOL mouse_opaque, - void (*on_commit_callback)(LLUICtrl*, void*), - void* callback_userdata, - U32 reshape) -: // can't make this automatically follow top and left, breaks lots - // of buttons in the UI. JC 7/20/2002 - LLView( name, rect, mouse_opaque, reshape ), - mCommitCallback( on_commit_callback) , - mLostTopCallback( NULL ), - mValidateCallback( NULL ), - mCallbackUserData( callback_userdata ), - mTentative( FALSE ), - mTabStop( TRUE ), - mIsChrome(FALSE) +//virtual +BOOL LLUICtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) { + BOOL handled = LLView::handleRightMouseDown(x,y,mask); + mRightMouseDownSignal(this,x,y,mask); + return handled; } -LLUICtrl::~LLUICtrl() +//virtual +BOOL LLUICtrl::handleRightMouseUp(S32 x, S32 y, MASK mask) { - gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() + BOOL handled = LLView::handleRightMouseUp(x,y,mask); + mRightMouseUpSignal(this,x,y,mask); + return handled; +} - if( gFocusMgr.getTopCtrl() == this ) - { - llwarns << "UI Control holding top ctrl deleted: " << getName() << ". Top view removed." << llendl; - gFocusMgr.removeTopCtrlWithoutCallback( this ); - } +// can't tab to children of a non-tab-stop widget +BOOL LLUICtrl::canFocusChildren() const +{ + return hasTabStop(); } + void LLUICtrl::onCommit() { - if( mCommitCallback ) - { - mCommitCallback( this, mCallbackUserData ); - } + mCommitSignal(this, getValue()); } //virtual @@ -141,10 +275,170 @@ BOOL LLUICtrl::isCtrl() const return TRUE; } +//virtual +void LLUICtrl::setValue(const LLSD& value) +{ + mViewModel->setValue(value); +} + //virtual LLSD LLUICtrl::getValue() const { - return LLSD(); + 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; +} + +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? + //llwarns << "setControlName called twice on same control!" << llendl; + mControlConnection.disconnect(); // disconnect current signal + mControlVariable = NULL; + } + + if (control) + { + mControlVariable = control; + mControlConnection = mControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getUICtrlHandle(), std::string("value"))); + setValue(mControlVariable->getValue()); + } +} + +//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); + 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, getUICtrlHandle(), 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, getUICtrlHandle(), 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, getUICtrlHandle(), 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, getUICtrlHandle(), std::string("invisible"))); + setVisible(!(mMakeInvisibleControlVariable->getValue().asBoolean())); + } +} +// 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 @@ -212,7 +506,7 @@ void LLUICtrl::onFocusReceived() // find first view in hierarchy above new focus that is a LLUICtrl LLView* viewp = getParent(); - LLUICtrl* last_focus = gFocusMgr.getLastKeyboardFocus(); + LLUICtrl* last_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getLastKeyboardFocus()); while (viewp && !viewp->isCtrl()) { @@ -248,12 +542,10 @@ void LLUICtrl::onFocusLost() } } -void LLUICtrl::onLostTop() +void LLUICtrl::onTopLost() { - if (mLostTopCallback) - { - mLostTopCallback(this, mCallbackUserData); - } + // trigger callbacks + LLFocusableElement::onTopLost(); } @@ -278,12 +570,13 @@ BOOL LLUICtrl::acceptsTextInput() const //virtual BOOL LLUICtrl::isDirty() const { - return FALSE; + return mViewModel->isDirty(); }; //virtual void LLUICtrl::resetDirty() { + mViewModel->resetDirty(); } // virtual @@ -456,7 +749,8 @@ BOOL LLUICtrl::focusNextItem(BOOL text_fields_only) { // this assumes that this method is called on the focus root. LLCtrlQuery query = getTabOrderQuery(); - if(text_fields_only || LLUI::sConfigGroup->getBOOL("TabToTextFieldsOnly")) + static LLUICachedControl<bool> tab_to_text_fields_only ("TabToTextFieldsOnly", false); + if(text_fields_only || tab_to_text_fields_only) { query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance()); } @@ -468,7 +762,8 @@ BOOL LLUICtrl::focusPrevItem(BOOL text_fields_only) { // this assumes that this method is called on the focus root. LLCtrlQuery query = getTabOrderQuery(); - if(text_fields_only || LLUI::sConfigGroup->getBOOL("TabToTextFieldsOnly")) + static LLUICachedControl<bool> tab_to_text_fields_only ("TabToTextFieldsOnly", false); + if(text_fields_only || tab_to_text_fields_only) { query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance()); } @@ -492,65 +787,6 @@ LLUICtrl* LLUICtrl::findRootMostFocusRoot() return focus_root; } - -/* -// Don't let the children handle the tool tip. Handle it here instead. -BOOL LLUICtrl::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) -{ - BOOL handled = FALSE; - if (getVisible() && pointInView( x, y ) ) - { - if( !mToolTipMsg.empty() ) - { - msg = mToolTipMsg; - - // Convert rect local to screen coordinates - localPointToScreen( - 0, 0, - &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) ); - localPointToScreen( - getRect().getWidth(), getRect().getHeight(), - &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) ); - - handled = TRUE; - } - } - - if (!handled) - { - return LLView::handleToolTip(x, y, msg, sticky_rect_screen); - } - - return handled; -}*/ - -void LLUICtrl::initFromXML(LLXMLNodePtr node, LLView* parent) -{ - BOOL has_tab_stop = hasTabStop(); - node->getAttributeBOOL("tab_stop", has_tab_stop); - - setTabStop(has_tab_stop); - - LLView::initFromXML(node, parent); -} - -LLXMLNodePtr LLUICtrl::getXML(bool save_children) const -{ - LLXMLNodePtr node = LLView::getXML(save_children); - node->createChild("tab_stop", TRUE)->setBoolValue(hasTabStop()); - - return node; -} - -//static -LLView* LLUICtrl::fromXML(LLXMLNodePtr node, LLView* parent, class LLUICtrlFactory* factory) -{ - LLUICtrl* ctrl = new LLUICtrl(); - ctrl->initFromXML(node, parent); - return ctrl; -} - - // Skip over any parents that are not LLUICtrl's // Used in focus logic since only LLUICtrl elements can have focus LLUICtrl* LLUICtrl::getParentUICtrl() const @@ -570,6 +806,16 @@ LLUICtrl* LLUICtrl::getParentUICtrl() const return NULL; } +// *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 ) +{ + return mValidateSignal.connect(boost::bind(cb, _2)); +} + // virtual void LLUICtrl::setTentative(BOOL b) { @@ -583,18 +829,37 @@ BOOL LLUICtrl::getTentative() const } // virtual -void LLUICtrl::setDoubleClickCallback( void (*cb)(void*) ) -{ -} - -// virtual void LLUICtrl::setColor(const LLColor4& color) { } // virtual -void LLUICtrl::setMinValue(LLSD min_value) +void LLUICtrl::setAlpha(F32 alpha) { } -// virtual -void LLUICtrl::setMaxValue(LLSD max_value) -{ } + +namespace LLInitParam +{ + template<> + bool ParamCompare<LLUICtrl::commit_callback_t>::equals( + const LLUICtrl::commit_callback_t &a, + const LLUICtrl::commit_callback_t &b) + { + return false; + } + + template<> + bool ParamCompare<LLUICtrl::focus_callback_t>::equals( + const LLUICtrl::focus_callback_t &a, + const LLUICtrl::focus_callback_t &b) + { + return false; + } + + template<> + bool ParamCompare<LLUICtrl::enable_callback_t>::equals( + const LLUICtrl::enable_callback_t &a, + const LLUICtrl::enable_callback_t &b) + { + return false; + } +} |