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.cpp529
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;
+ }
+}