From b3d97b086090a12373547567354193d8778e4367 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 3 Jul 2013 17:12:12 -0500 Subject: [PATCH 1/8] Avoid running the motionblur shader if there hasn't been camera movement. Also clamp per-frame fragment velocity to reduce visual artifacts. --- indra/llrender/llpostprocess.cpp | 3 ++- .../app_settings/shaders/class1/effects/MotionBlurF.glsl | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp index 0ab80bf68..1ea12e351 100644 --- a/indra/llrender/llpostprocess.cpp +++ b/indra/llrender/llpostprocess.cpp @@ -282,6 +282,7 @@ public: { addSetting(mStrength); } + /*virtual*/ bool isEnabled() const { return LLPostProcessShader::isEnabled() && llabs(gGLModelView[0] - gGLPreviousModelView[0]) > .0000001; } /*virtual*/ S32 getColorChannel() const { return 0; } /*virtual*/ S32 getDepthChannel() const { return 1; } /*virtual*/ QuadType preDraw() @@ -298,7 +299,7 @@ public: getShader().uniformMatrix4fv("inv_proj", 1, GL_FALSE, inv_proj.m); getShader().uniform2fv("screen_res", 1, screen_rect.mV); getShader().uniform1i("blur_strength", mStrength); - + return QUAD_NORMAL; } /*virtual*/ bool draw(U32 pass) diff --git a/indra/newview/app_settings/shaders/class1/effects/MotionBlurF.glsl b/indra/newview/app_settings/shaders/class1/effects/MotionBlurF.glsl index 89aaa8f10..efa1265a1 100644 --- a/indra/newview/app_settings/shaders/class1/effects/MotionBlurF.glsl +++ b/indra/newview/app_settings/shaders/class1/effects/MotionBlurF.glsl @@ -44,7 +44,9 @@ void main(void) vec4 prev_pos = prev_proj * pos; prev_pos/=prev_pos.w; prev_pos.w = 1.0; - vec2 vel = ((ndc.xy-prev_pos.xy) * .5) * screen_res * .001 * blur_strength; + vec2 vel = ((ndc.xy-prev_pos.xy) * .5) * screen_res * .01 * blur_strength * 1.0/SAMPLE_COUNT; + float len = length(vel); + vel = normalize(vel) * min(len, 50); vec3 color = texture2DRect(tex0, vary_texcoord0.st).rgb; vec2 texcoord = vary_texcoord0 + vel; for(int i = 1; i < SAMPLE_COUNT; ++i, texcoord += vel) From 4455dd7eff28f288a3563ea26d8790bf9cca7f1e Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 3 Jul 2013 17:13:11 -0500 Subject: [PATCH 2/8] When requesting an avatar reload, also reload all attachments (prior to this it was not possible to actually reload attachments on non-agent avatars) --- indra/newview/llviewermenu.cpp | 63 ++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 8df0599dd..64b4a0f35 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -2186,6 +2186,38 @@ public: private: std::set< LLViewerFetchedTexture*> mTextures; }; + +void reload_objects(LLTextureReloader& texture_list, LLViewerObject::const_child_list_t& object_list, bool recurse) +{ + for(LLViewerObject::const_child_list_t::const_iterator it = object_list.begin(); it!=object_list.end(); ++it) + { + if(it->isNull()) + continue; + + LLViewerObject* object = it->get(); + object->markForUpdate(TRUE); + + if(object->isSculpted() && !object->isMesh()) + { + LLSculptParams *sculpt_params = (LLSculptParams *)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + if(sculpt_params) + { + texture_list.addTexture(LLViewerTextureManager::getFetchedTexture(sculpt_params->getSculptTexture())); + } + } + + for (U8 i = 0; i < object->getNumTEs(); i++) + { + texture_list.addTexture(object->getTEImage(i)); + } + + if(recurse) + { + reload_objects(texture_list,object->getChildren(), true); + } + } +} + class LLAvatarReloadTextures : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) @@ -2214,6 +2246,7 @@ class LLAvatarReloadTextures : public view_listener_t texture_list.addTexture(avatar->getTEImage((ETextureIndex)i)); } } + reload_objects(texture_list,avatar->getChildren(),true); } return true; } @@ -2222,30 +2255,16 @@ class LLObjectReloadTextures : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { - LLTextureReloader texture_list; - for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++) - { - LLViewerObject* object = (*iter)->getObject(); - object->markForUpdate(TRUE); + LLViewerObject::vobj_list_t object_list; - if(object->isSculpted() && !object->isMesh()) - { - LLSculptParams *sculpt_params = (LLSculptParams *)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT); - if(sculpt_params) - { - texture_list.addTexture(LLViewerTextureManager::getFetchedTexture(sculpt_params->getSculptTexture())); - } - } - - for (U8 i = 0; i < object->getNumTEs(); i++) - { - if((*iter)->isTESelected(i)) - { - texture_list.addTexture(object->getTEImage(i)); - } - } + for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin(); + iter != LLSelectMgr::getInstance()->getSelection()->end(); iter++) + { + object_list.push_back((*iter)->getObject()); } + + reload_objects(LLTextureReloader(),object_list,false); + return true; } }; From 8310575fc3851f8d91a68e0ec238dd37e4177fed Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 3 Jul 2013 17:15:30 -0500 Subject: [PATCH 3/8] added LLProgressView::abortShowProgress. Issue upon failed login to terminate pending loginpanel destruction which was killing the actual 'new' replacement loginpanel instead of the old to-be-deleted version. --- indra/newview/llpanellogin.cpp | 11 ++--------- indra/newview/llprogressview.cpp | 8 ++++++++ indra/newview/llprogressview.h | 1 + indra/newview/llviewerwindow.cpp | 8 ++++++++ indra/newview/llviewerwindow.h | 1 + 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 0986ac024..440b83b0d 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -216,15 +216,8 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, setBackgroundVisible(FALSE); setBackgroundOpaque(TRUE); - // instance management - if (LLPanelLogin::sInstance) - { - LL_WARNS("AppInit") << "Duplicate instance of login view deleted" << LL_ENDL; - // Don't leave bad pointer in gFocusMgr - gFocusMgr.setDefaultKeyboardFocus(NULL); - - delete LLPanelLogin::sInstance; - } + gViewerWindow->abortShowProgress(); //Kill previous instance. It might still be alive, and if so, its probably pending + //deletion via the progressviews idle callback. Kill it now and unregister said idle callback. LLPanelLogin::sInstance = this; diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index 394dfce31..cbaa5d47e 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -134,6 +134,14 @@ void LLProgressView::revealIntroPanel() mFadeFromLoginTimer.start(); gIdleCallbacks.addFunction(onIdle, this); } + +void LLProgressView::abortShowProgress() +{ + mFadeFromLoginTimer.stop(); + LLPanelLogin::close(); + gIdleCallbacks.deleteFunction(onIdle, this); +} + void LLProgressView::setStartupComplete() { mStartupComplete = true; diff --git a/indra/newview/llprogressview.h b/indra/newview/llprogressview.h index bff970e29..816305efd 100644 --- a/indra/newview/llprogressview.h +++ b/indra/newview/llprogressview.h @@ -62,6 +62,7 @@ public: void setMessage(const std::string& msg); void revealIntroPanel(); + void abortShowProgress(); void setStartupComplete(); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 6a1cf636a..ca054bae3 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -5154,6 +5154,14 @@ void LLViewerWindow::revealIntroPanel() } } +void LLViewerWindow::abortShowProgress() +{ + if (mProgressView) + { + mProgressView->abortShowProgress(); + } +} + void LLViewerWindow::setShowProgress(const BOOL show) { if (mProgressView) diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 9d47812d9..3b38f450d 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -280,6 +280,7 @@ public: void setProgressCancelButtonVisible( BOOL b, const std::string& label = LLStringUtil::null ); LLProgressView *getProgressView() const; void revealIntroPanel(); + void abortShowProgress(); void setStartupComplete(); void updateObjectUnderCursor(); From 0219186106fd3a70b5ce993ce3012503c1e01590 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 3 Jul 2013 17:16:37 -0500 Subject: [PATCH 4/8] Use SHGetKnownFolderPath on vista/win7/win8, instead of deprecated SHGetSpecialFolderPath. --- indra/llvfs/lldir_win32.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp index 194fe617a..271afa5e9 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -63,7 +63,25 @@ LLDir_Win32::LLDir_Win32() // // We used to store the cache in AppData\Roaming, and the installer // cleans up that version on upgrade. JC - SHGetSpecialFolderPath(NULL, w_str, CSIDL_LOCAL_APPDATA, TRUE); + + if(HMODULE shell = LoadLibrary(L"shell32")) //SHGetSpecialFolderPath is deprecated from Vista an onwards. Try to use SHGetSpecialFolderPath if it's available + { + HRESULT (WINAPI* pSHGetKnownFolderPath)(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath); + pSHGetKnownFolderPath = (HRESULT (WINAPI *)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *))GetProcAddress(shell, "SHGetKnownFolderPath"); + WCHAR* pPath = NULL; + if(pSHGetKnownFolderPath && (*pSHGetKnownFolderPath)(FOLDERID_LocalAppData, 0, NULL, &pPath) == S_OK) + wcscpy_s(w_str,pPath); + else + SHGetSpecialFolderPath(NULL, w_str, CSIDL_LOCAL_APPDATA, TRUE); + + FreeLibrary(shell); + if(pPath) + CoTaskMemFree(pPath); + } + else //XP doesn't support SHGetKnownFolderPath + { + SHGetSpecialFolderPath(NULL, w_str, CSIDL_LOCAL_APPDATA, TRUE); + } mOSCacheDir = utf16str_to_utf8str(llutf16string(w_str)); if (GetTempPath(MAX_PATH, w_str)) From c82ac0b0af6d96f5660e2bfd1ef4a69ac9ab404f Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 3 Jul 2013 17:18:26 -0500 Subject: [PATCH 5/8] Added several missing mouse-event callback signals to LLUICtrl --- indra/llui/lluictrl.cpp | 101 ++++++++++++++++++++++++++++++++++++++++ indra/llui/lluictrl.h | 21 +++++++++ 2 files changed, 122 insertions(+) diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index ee9e74ae4..b70737c27 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -49,6 +49,11 @@ LLUICtrl::LLUICtrl() : mValidateSignal(NULL), mMouseEnterSignal(NULL), mMouseLeaveSignal(NULL), + mMouseDownSignal(NULL), + mMouseUpSignal(NULL), + mRightMouseDownSignal(NULL), + mRightMouseUpSignal(NULL), + mDoubleClickSignal(NULL), mTentative(FALSE), mTabStop(TRUE), mIsChrome(FALSE) @@ -66,6 +71,11 @@ LLUICtrl::LLUICtrl(const std::string& name, const LLRect rect, BOOL mouse_opaque mViewModel(LLViewModelPtr(new LLViewModel)), mMouseEnterSignal(NULL), mMouseLeaveSignal(NULL), + mMouseDownSignal(NULL), + mMouseUpSignal(NULL), + mRightMouseDownSignal(NULL), + mRightMouseUpSignal(NULL), + mDoubleClickSignal(NULL), mTentative( FALSE ), mTabStop( TRUE ), mIsChrome(FALSE) @@ -86,6 +96,13 @@ LLUICtrl::~LLUICtrl() delete mCommitSignal; delete mValidateSignal; + delete mMouseEnterSignal; + delete mMouseLeaveSignal; + delete mMouseDownSignal; + delete mMouseUpSignal; + delete mRightMouseDownSignal; + delete mRightMouseUpSignal; + delete mDoubleClickSignal; } @@ -107,6 +124,60 @@ void LLUICtrl::onMouseLeave(S32 x, S32 y, MASK mask) } } +//virtual +BOOL LLUICtrl::handleMouseDown(S32 x, S32 y, MASK mask) +{ + BOOL handled = LLView::handleMouseDown(x,y,mask); + if (mMouseDownSignal) + { + (*mMouseDownSignal)(this,x,y,mask); + } + return handled; +} + +//virtual +BOOL LLUICtrl::handleMouseUp(S32 x, S32 y, MASK mask) +{ + BOOL handled = LLView::handleMouseUp(x,y,mask); + if (mMouseUpSignal) + { + (*mMouseUpSignal)(this,x,y,mask); + } + 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; +} + void LLUICtrl::onCommit() { if (mCommitSignal) @@ -697,3 +768,33 @@ boost::signals2::connection LLUICtrl::setMouseLeaveCallback( const commit_signal 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); +} diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index c1de060cb..b7ebc5bcc 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -49,6 +49,7 @@ class LLUICtrl public: typedef boost::function commit_callback_t; typedef boost::signals2::signal commit_signal_t; + typedef boost::signals2::signal mouse_signal_t; typedef boost::function enable_callback_t; typedef boost::signals2::signal enable_signal_t; @@ -69,6 +70,11 @@ public: /*virtual*/ BOOL isCtrl() const; /*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask); /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); // From LLFocusableElement /*virtual*/ void setFocus( BOOL b ); @@ -132,6 +138,14 @@ public: boost::signals2::connection setMouseEnterCallback( const commit_signal_t::slot_type& cb ); boost::signals2::connection setMouseLeaveCallback( const commit_signal_t::slot_type& cb ); + + boost::signals2::connection setMouseDownCallback( const mouse_signal_t::slot_type& cb ); + boost::signals2::connection setMouseUpCallback( const mouse_signal_t::slot_type& cb ); + boost::signals2::connection setRightMouseDownCallback( const mouse_signal_t::slot_type& cb ); + boost::signals2::connection setRightMouseUpCallback( const mouse_signal_t::slot_type& cb ); + + boost::signals2::connection setDoubleClickCallback( const mouse_signal_t::slot_type& cb ); + // *TODO: Deprecate; for backwards compatability only: boost::signals2::connection setCommitCallback( boost::function cb, void* data); boost::signals2::connection setValidateBeforeCommit( boost::function cb ); @@ -165,6 +179,13 @@ protected: commit_signal_t* mMouseEnterSignal; commit_signal_t* mMouseLeaveSignal; + mouse_signal_t* mMouseDownSignal; + mouse_signal_t* mMouseUpSignal; + mouse_signal_t* mRightMouseDownSignal; + mouse_signal_t* mRightMouseUpSignal; + + mouse_signal_t* mDoubleClickSignal; + LLViewModelPtr mViewModel; LLControlVariable* mMakeVisibleControlVariable; From 7f981e6f1731defb7b6ad09e09c8c7400ecc8d32 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 3 Jul 2013 17:19:39 -0500 Subject: [PATCH 6/8] 'Typeregionname' combobox should have an empty value. Was hosing up logic in LPanelLogin::onUpdateStartSLURL. --- indra/newview/skins/default/xui/en-us/panel_login.xml | 2 +- indra/newview/skins/default/xui/es/panel_login.xml | 2 +- indra/newview/skins/default/xui/fr/panel_login.xml | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/indra/newview/skins/default/xui/en-us/panel_login.xml b/indra/newview/skins/default/xui/en-us/panel_login.xml index aebdcc41a..917653980 100644 --- a/indra/newview/skins/default/xui/en-us/panel_login.xml +++ b/indra/newview/skins/default/xui/en-us/panel_login.xml @@ -70,7 +70,7 @@ My Last Location - + <Type region name> diff --git a/indra/newview/skins/default/xui/es/panel_login.xml b/indra/newview/skins/default/xui/es/panel_login.xml index e33c0e8a2..8bafe6eaa 100644 --- a/indra/newview/skins/default/xui/es/panel_login.xml +++ b/indra/newview/skins/default/xui/es/panel_login.xml @@ -29,7 +29,7 @@ Mi Última Ubicación - + <Escribe el Nombre de la Región> diff --git a/indra/newview/skins/default/xui/fr/panel_login.xml b/indra/newview/skins/default/xui/fr/panel_login.xml index 7307b7249..aa3ba89bc 100644 --- a/indra/newview/skins/default/xui/fr/panel_login.xml +++ b/indra/newview/skins/default/xui/fr/panel_login.xml @@ -23,9 +23,6 @@ Dernier emplacement - - <Choisir région> - <Nom de la région> From 624141a31a4d92c1c4ab0883ba0b25a35afe9e3c Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 3 Jul 2013 17:21:45 -0500 Subject: [PATCH 7/8] A break was missing from case logic in LLPanelLogin::onUpdateStartSLURL --- indra/newview/llpanellogin.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 440b83b0d..79d4c56d3 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -738,6 +738,7 @@ void LLPanelLogin::onUpdateStartSLURL(const LLSLURL& new_start_slurl) location_combo->setCurrentByIndex( 2 ); location_combo->setTextEntry(new_start_slurl.getLocationString()); } + break; case LLSLURL::HOME_LOCATION: location_combo->setCurrentByIndex( 0 ); // home location break; From bbb0bd54bfc85cb261af9ff7d8b6282c8234687f Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 5 Jul 2013 02:28:36 -0500 Subject: [PATCH 8/8] Fixed location combobox not updating properly when a slurl link is clicked. Reset the location combobox when a different grid is selected (added setCurrentGridChangeCallback to hippogridmanager). Moved login panel elements into a layout_stack so hiding the grid or location columns no longer leaves big empty gaps. --- indra/llui/llcombobox.cpp | 172 +++++++++++++----- indra/llui/llcombobox.h | 12 +- indra/newview/hippogridmanager.cpp | 5 + indra/newview/hippogridmanager.h | 13 ++ indra/newview/hippopanelgrids.cpp | 1 - indra/newview/llappviewer.cpp | 1 - indra/newview/llpanellogin.cpp | 29 +-- indra/newview/llpanellogin.h | 2 + .../skins/default/xui/en-us/panel_login.xml | 129 +++++++------ .../skins/default/xui/es/panel_login.xml | 80 ++++---- .../skins/default/xui/fr/panel_login.xml | 80 ++++---- .../skins/default/xui/pt/panel_login.xml | 64 ++++--- 12 files changed, 357 insertions(+), 231 deletions(-) diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index 30a10c39a..6fd7084df 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -64,17 +64,20 @@ LLComboBox::LLComboBox( const std::string& name, const LLRect &rect, const std:: commit_callback_t commit_callback) : LLUICtrl(name, rect, TRUE, commit_callback, FOLLOWS_LEFT | FOLLOWS_TOP), mTextEntry(NULL), - mArrowImage(NULL), - mAllowTextEntry(FALSE), - mMaxChars(20), mTextEntryTentative(TRUE), - mListPosition(BELOW), + mArrowImage(NULL), + mHasAutocompletedText(false), + mAllowTextEntry(false), + mAllowNewValues(false), + mMaxChars(20), mPrearrangeCallback( NULL ), mTextEntryCallback( NULL ), + mListPosition(BELOW), mSuppressTentative( false ), mSuppressAutoComplete( false ), - mLabel(label), - mListColor(LLUI::sColorsGroup->getColor("ComboBoxBg")) + mListColor(LLUI::sColorsGroup->getColor("ComboBoxBg")), + mLastSelectedIndex(-1), + mLabel(label) { // Always use text box // Text label button @@ -91,17 +94,25 @@ LLComboBox::LLComboBox( const std::string& name, const LLRect &rect, const std:: mButton->setFont(LLFontGL::getFontSansSerifSmall()); mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT); mButton->setHAlign( LLFontGL::LEFT ); - mButton->setRightHPad(2); + if(mAllowTextEntry) + { + mButton->setRightHPad(2); + } + addChild(mButton); // disallow multiple selection mList = new LLScrollListCtrl(std::string("ComboBox"), LLRect(), - boost::bind(&LLComboBox::onItemSelected, this), FALSE); + boost::bind(&LLComboBox::onItemSelected, this, _2), FALSE); mList->setVisible(FALSE); mList->setBgWriteableColor(mListColor); mList->setCommitOnKeyboardMovement(FALSE); addChild(mList); + // Mouse-down on button will transfer mouse focus to the list + // Grab the mouse-up event and make sure the button state is correct + mList->setMouseUpCallback(boost::bind(&LLComboBox::onListMouseUp, this)); + mArrowImage = LLUI::getUIImage("combobox_arrow.tga"); mButton->setImageOverlay("combobox_arrow.tga", LLFontGL::RIGHT); @@ -234,6 +245,7 @@ void LLComboBox::clear() mButton->setLabelSelected(LLStringUtil::null); mButton->setLabelUnselected(LLStringUtil::null); mList->deselectAllItems(); + mLastSelectedIndex = -1; } void LLComboBox::onCommit() @@ -280,6 +292,11 @@ void LLComboBox::resetDirty() } } +bool LLComboBox::itemExists(const std::string& name) +{ + return mList->getItemByLabel(name); +} + void LLComboBox::resetTextDirty() { if ( mTextEntry ) @@ -358,6 +375,7 @@ BOOL LLComboBox::setSimple(const LLStringExplicit& name) if (found) { setLabel(name); + mLastSelectedIndex = mList->getFirstSelectedIndex(); } return found; @@ -372,14 +390,19 @@ void LLComboBox::setValue(const LLSD& value) LLScrollListItem* item = mList->getFirstSelected(); if (item) { - setLabel( mList->getSelectedItemLabel() ); + updateLabel(); } + mLastSelectedIndex = mList->getFirstSelectedIndex(); + } + else + { + mLastSelectedIndex = -1; } } const std::string LLComboBox::getSimple() const { - const std::string res = mList->getSelectedItemLabel(); + const std::string res = getSelectedItemLabel(); if (res.empty() && mAllowTextEntry) { return mTextEntry->getText(); @@ -421,6 +444,7 @@ void LLComboBox::setLabel(const LLStringExplicit& name) if (mList->selectItemByLabel(name, FALSE)) { mTextEntry->setTentative(FALSE); + mLastSelectedIndex = mList->getFirstSelectedIndex(); } else { @@ -435,6 +459,25 @@ void LLComboBox::setLabel(const LLStringExplicit& name) } } +void LLComboBox::updateLabel() +{ + // Update the combo editor with the selected + // item label. + if (mTextEntry) + { + mTextEntry->setText(getSelectedItemLabel()); + mTextEntry->setTentative(FALSE); + } + + // If combo box doesn't allow text entry update + // the combo button label. + if (!mAllowTextEntry) + { + std::string label = getSelectedItemLabel(); + mButton->setLabelUnselected(label); + mButton->setLabelSelected(label); + } +} BOOL LLComboBox::remove(const std::string& name) { @@ -447,6 +490,7 @@ BOOL LLComboBox::remove(const std::string& name) { mList->deleteSingleItem(mList->getItemIndex(item)); } + mLastSelectedIndex = mList->getFirstSelectedIndex(); } return found; @@ -457,6 +501,7 @@ BOOL LLComboBox::remove(S32 index) if (index < mList->getItemCount()) { mList->deleteSingleItem(index); + setLabel(getSelectedItemLabel()); return TRUE; } return FALSE; @@ -502,7 +547,8 @@ BOOL LLComboBox::setCurrentByIndex( S32 index ) BOOL found = mList->selectNthItem( index ); if (found) { - setLabel(mList->getSelectedItemLabel()); + setLabel(getSelectedItemLabel()); + mLastSelectedIndex = index; } return found; } @@ -560,10 +606,12 @@ void LLComboBox::updateLayout() mButton->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP | FOLLOWS_RIGHT); } - else if (!mAllowTextEntry) + else { mButton->setRect(rect); mButton->setTabStop(TRUE); + mButton->setLabelUnselected(mLabel); + mButton->setLabelSelected(mLabel); if (mTextEntry) { @@ -682,24 +730,28 @@ void LLComboBox::showList() void LLComboBox::hideList() { -#if 0 // Don't do this! mTextEntry->getText() can be truncated, in which case selectItemByLabel - // fails and this only resets the selection :/ - - // *HACK: store the original value explicitly somewhere, not just in label - std::string orig_selection = mAllowTextEntry ? mTextEntry->getText() : mButton->getLabelSelected(); - - // assert selection in list - mList->selectItemByLabel(orig_selection, FALSE); -#endif - - mButton->setToggleState(FALSE); - mList->setVisible(FALSE); - mList->mouseOverHighlightNthItem(-1); - - setUseBoundingRect(FALSE); - if( gFocusMgr.getTopCtrl() == this ) + if (mList->getVisible()) { - gFocusMgr.setTopCtrl(NULL); + // assert selection in list + if(mAllowNewValues) + { + // mLastSelectedIndex = -1 means that we entered a new value, don't select + // any of existing items in this case. + if(mLastSelectedIndex >= 0) + mList->selectNthItem(mLastSelectedIndex); + } + else if(mLastSelectedIndex >= 0) + mList->selectNthItem(mLastSelectedIndex); + + mButton->setToggleState(FALSE); + mList->setVisible(FALSE); + mList->mouseOverHighlightNthItem(-1); + + setUseBoundingRect(FALSE); + if( gFocusMgr.getTopCtrl() == this ) + { + gFocusMgr.setTopCtrl(NULL); + } } } @@ -730,10 +782,14 @@ void LLComboBox::onButtonMouseDown() setFocus( TRUE ); // pass mouse capture on to list if button is depressed - /*if (self->mButton->hasMouseCapture()) + if (mButton->hasMouseCapture()) { - gFocusMgr.setMouseCapture(self->mList); - }*/ + gFocusMgr.setMouseCapture(mList); + + // But keep the "pressed" look, which buttons normally lose when they + // lose focus + mButton->setForcePressedState(true); + } } else { @@ -742,15 +798,23 @@ void LLComboBox::onButtonMouseDown() } -void LLComboBox::onItemSelected() +void LLComboBox::onListMouseUp() { - // Note: item is the LLScrollListCtrl - const std::string name = mList->getSelectedItemLabel(); + // In some cases this is the termination of a mouse click that started on + // the button, so clear its pressed state + mButton->setForcePressedState(false); +} - S32 cur_id = getCurrentIndex(); - if (cur_id != -1) +//------------------------------------------------------------------ +// static functions +//------------------------------------------------------------------ + +void LLComboBox::onItemSelected(const LLSD& data) +{ + mLastSelectedIndex = getCurrentIndex(); + if (mLastSelectedIndex != -1) { - setLabel(name); + updateLabel(); if (mAllowTextEntry) { @@ -758,7 +822,6 @@ void LLComboBox::onItemSelected() mTextEntry->selectAll(); } } - // hiding the list reasserts the old value stored in the text editor/dropdown button hideList(); @@ -879,6 +942,7 @@ void LLComboBox::setTextEntry(const LLStringExplicit& text) if (mTextEntry) { mTextEntry->setText(text); + mHasAutocompletedText = FALSE; updateSelection(); } } @@ -902,12 +966,14 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor) if (mList->selectItemByLabel(line_editor->getText(), FALSE)) { line_editor->setTentative(FALSE); + mLastSelectedIndex = mList->getFirstSelectedIndex(); } else { if (!mSuppressTentative) line_editor->setTentative(mTextEntryTentative); mList->deselectAllItems(); + mLastSelectedIndex = -1; } return; } @@ -964,7 +1030,7 @@ void LLComboBox::updateSelection() LLWString left_wstring = mTextEntry->getWText().substr(0, mTextEntry->getCursor()); // user-entered portion of string, based on assumption that any selected // text was a result of auto-completion - LLWString user_wstring = mTextEntry->hasSelection() ? left_wstring : mTextEntry->getWText(); + LLWString user_wstring = mHasAutocompletedText ? left_wstring : mTextEntry->getWText(); std::string full_string = mTextEntry->getText(); // go ahead and arrange drop down list on first typed character, even @@ -978,21 +1044,26 @@ void LLComboBox::updateSelection() if (mList->selectItemByLabel(full_string, FALSE)) { mTextEntry->setTentative(FALSE); + mLastSelectedIndex = mList->getFirstSelectedIndex(); } - else if (!mList->selectItemByPrefix(left_wstring, FALSE)) + else if (mList->selectItemByPrefix(left_wstring, FALSE)) { - mList->deselectAllItems(); - mTextEntry->setText(wstring_to_utf8str(user_wstring)); - if (!mSuppressTentative) mTextEntry->setTentative(mTextEntryTentative); - } - else - { - LLWString selected_item = utf8str_to_wstring(mList->getSelectedItemLabel()); + LLWString selected_item = utf8str_to_wstring(getSelectedItemLabel()); LLWString wtext = left_wstring + selected_item.substr(left_wstring.size(), selected_item.size()); mTextEntry->setText(wstring_to_utf8str(wtext)); mTextEntry->setSelection(left_wstring.size(), mTextEntry->getWText().size()); mTextEntry->endSelection(); mTextEntry->setTentative(FALSE); + mHasAutocompletedText = TRUE; + mLastSelectedIndex = mList->getFirstSelectedIndex(); + } + else // no matching items found + { + mList->deselectAllItems(); + mTextEntry->setText(wstring_to_utf8str(user_wstring)); // removes text added by autocompletion + mTextEntry->setTentative(mTextEntryTentative); + mHasAutocompletedText = FALSE; + mLastSelectedIndex = -1; } } @@ -1109,7 +1180,8 @@ BOOL LLComboBox::setCurrentByID(const LLUUID& id) if (found) { - setLabel(mList->getSelectedItemLabel()); + setLabel(getSelectedItemLabel()); + mLastSelectedIndex = mList->getFirstSelectedIndex(); } return found; @@ -1124,7 +1196,7 @@ BOOL LLComboBox::setSelectedByValue(const LLSD& value, BOOL selected) BOOL found = mList->setSelectedByValue(value, selected); if (found) { - setLabel(mList->getSelectedItemLabel()); + setLabel(getSelectedItemLabel()); } return found; } diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index f061865b8..b6165ae0f 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -123,6 +123,7 @@ public: LLScrollListItem* addSeparator(EAddPosition pos = ADD_BOTTOM); BOOL remove( S32 index ); // remove item by index, return TRUE if found and removed void removeall() { clearRows(); } + bool itemExists(const std::string& name); void sortByName(BOOL ascending = TRUE); // Sort the entries in the combobox by name @@ -131,12 +132,15 @@ public: // Get name of current item. Returns an empty string if not found. const std::string getSimple() const; // Get contents of column x of selected row - const std::string getSelectedItemLabel(S32 column = 0) const; + virtual const std::string getSelectedItemLabel(S32 column = 0) const; // Sets the label, which doesn't have to exist in the label. // This is probably a UI abuse. void setLabel(const LLStringExplicit& name); + // Updates the combobox label to match the selected list item. + void updateLabel(); + BOOL remove(const std::string& name); // remove item "name", return TRUE if found and removed BOOL setCurrentByIndex( S32 index ); @@ -185,7 +189,8 @@ public: void setButtonVisible(BOOL visible); void onButtonMouseDown(); - void onItemSelected(); + void onListMouseUp(); + void onItemSelected(const LLSD& data); void onTextCommit(const LLSD& data); @@ -205,10 +210,12 @@ protected: EPreferredPosition mListPosition; LLPointer mArrowImage; std::string mLabel; + BOOL mHasAutocompletedText; LLColor4 mListColor; private: BOOL mAllowTextEntry; + BOOL mAllowNewValues; S32 mMaxChars; BOOL mTextEntryTentative; bool mSuppressAutoComplete; @@ -216,6 +223,7 @@ private: commit_callback_t mPrearrangeCallback; commit_callback_t mTextEntryCallback; boost::signals2::connection mTopLostSignalConnection; + S32 mLastSelectedIndex; }; class LLFlyoutButton : public LLComboBox diff --git a/indra/newview/hippogridmanager.cpp b/indra/newview/hippogridmanager.cpp index d7c02be7f..5fb8195f7 100644 --- a/indra/newview/hippogridmanager.cpp +++ b/indra/newview/hippogridmanager.cpp @@ -646,6 +646,8 @@ HippoGridManager::HippoGridManager() : HippoGridManager::~HippoGridManager() { cleanup(); + if(mCurrentGridChangeSignal) + delete mCurrentGridChangeSignal; } @@ -805,6 +807,7 @@ void HippoGridManager::setDefaultGrid(const std::string& grid) void HippoGridManager::setCurrentGrid(const std::string& grid) { + HippoGridInfo* prevGrid = getGrid(mCurrentGrid); GridIterator it = mGridInfo.find(grid); if (it != mGridInfo.end()) { @@ -815,6 +818,8 @@ void HippoGridManager::setCurrentGrid(const std::string& grid) llwarns << "Unknown grid '" << grid << "'. Setting to default grid." << llendl; mCurrentGrid = mDefaultGrid; } + if(mCurrentGridChangeSignal) + (*mCurrentGridChangeSignal)(getGrid(mCurrentGrid),prevGrid); } diff --git a/indra/newview/hippogridmanager.h b/indra/newview/hippogridmanager.h index e5600dfa9..605a02e0d 100644 --- a/indra/newview/hippogridmanager.h +++ b/indra/newview/hippogridmanager.h @@ -15,6 +15,8 @@ #include "expat/expat.h" #endif +#include + class LLSD; @@ -152,6 +154,8 @@ private: class HippoGridManager { public: + typedef boost::signals2::signal current_grid_change_signal_t; + HippoGridManager(); ~HippoGridManager(); @@ -179,6 +183,13 @@ public: GridIterator beginGrid() { return mGridInfo.begin(); } GridIterator endGrid() { return mGridInfo.end(); } + boost::signals2::connection setCurrentGridChangeCallback( const current_grid_change_signal_t::slot_type& cb ) + { + if(!mCurrentGridChangeSignal) + mCurrentGridChangeSignal = new current_grid_change_signal_t; + return mCurrentGridChangeSignal->connect(cb); + } + private: friend class HippoGridInfo; std::map mGridInfo; @@ -187,6 +198,8 @@ private: HippoGridInfo* mConnectedGrid; int mDefaultGridsVersion; + current_grid_change_signal_t* mCurrentGridChangeSignal; + void cleanup(); void loadFromFile(); void parseFile(const std::string& fileName, bool mergeIfNewer); diff --git a/indra/newview/hippopanelgrids.cpp b/indra/newview/hippopanelgrids.cpp index c5fe98de2..b0239fead 100644 --- a/indra/newview/hippopanelgrids.cpp +++ b/indra/newview/hippopanelgrids.cpp @@ -227,7 +227,6 @@ void HippoPanelGridsImpl::apply() // adding new grid did not fail gHippoGridManager->setCurrentGrid(mCurGrid); } - LLPanelLogin::refreshLoginPage(); gHippoGridManager->saveFile(); refresh(); // update render compatibility diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 29a339eca..efbd2b5fe 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2332,7 +2332,6 @@ bool LLAppViewer::initConfiguration() if(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION) { gHippoGridManager->setCurrentGrid(LLStartUp::getStartSLURL().getGrid()); - } } else if(clp.hasOption("slurl")) diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 79d4c56d3..5e818d880 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -278,9 +278,8 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, { LL_INFOS("AppInit")<<"no valid LoginLocation, using home"<setCurrentGridChangeCallback(boost::bind(&LLPanelLogin::onCurGridChange,this,_1,_2)); } void LLPanelLogin::setSiteIsAlive( bool alive ) @@ -631,7 +630,6 @@ void LLPanelLogin::setFields(const LLSavedLoginEntry& entry, bool takeFocus) if(!grid.empty() && gHippoGridManager->getGrid(grid) && grid != gHippoGridManager->getCurrentGridName()) { gHippoGridManager->setCurrentGrid(grid); - LLPanelLogin::refreshLoginPage(); } if (entry.getPassword().empty()) @@ -702,13 +700,10 @@ void LLPanelLogin::updateLocationSelectorsVisibility() #endif // RLV_EXTENSION_STARTLOCATION // [/RLVa:KB] - sInstance->getChild("start_location_combo")->setVisible(show_start); // maintain ShowStartLocation if legacy - sInstance->getChild("start_location_text")->setVisible(show_start); + sInstance->getChildView("location_panel")->setVisible(show_start); - bool show_server = true; - sInstance->getChild("grids_combo")->setVisible(show_server); - sInstance->getChild("grids_text")->setVisible(show_server); - sInstance->getChild("grids_btn")->setVisible(show_server); + bool show_server = true; + sInstance->getChildView("grids_panel")->setVisible(show_server); } } @@ -1030,6 +1025,17 @@ void LLPanelLogin::onPassKey(LLLineEditor* caller) } } +void LLPanelLogin::onCurGridChange(HippoGridInfo* new_grid, HippoGridInfo* old_grid) +{ + refreshLoginPage(); + if(old_grid != new_grid) //Changed grid? Reset the location combobox + { + std::string defaultStartLocation = gSavedSettings.getString("LoginLocation"); + LLSLURL defaultStart(defaultStartLocation); + LLStartUp::setStartSLURL(defaultStart.isSpatial() ? defaultStart : LLSLURL(LLSLURL::SIM_LOCATION_HOME)); // calls onUpdateStartSLURL + } +} + // static //void LLPanelLogin::updateServer() void LLPanelLogin::refreshLoginPage() @@ -1074,7 +1080,6 @@ void LLPanelLogin::refreshLoginPage() void LLPanelLogin::onSelectGrid(LLUICtrl *ctrl) { gHippoGridManager->setCurrentGrid(ctrl->getValue()); - LLPanelLogin::refreshLoginPage(); } void LLPanelLogin::onLocationSLURL() diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index 5041871ed..2158105e0 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -41,6 +41,7 @@ class LLUIImage; class LLComboBox; +class HippoGridInfo; class LLPanelLogin: public LLPanel, @@ -92,6 +93,7 @@ public: void updateGridCombo(); + void onCurGridChange(HippoGridInfo* new_grid, HippoGridInfo* old_grid); static void loadLoginPage(); static void refreshLoginPage(); static void giveFocus(); diff --git a/indra/newview/skins/default/xui/en-us/panel_login.xml b/indra/newview/skins/default/xui/en-us/panel_login.xml index 917653980..d8879f6d2 100644 --- a/indra/newview/skins/default/xui/en-us/panel_login.xml +++ b/indra/newview/skins/default/xui/en-us/panel_login.xml @@ -13,72 +13,81 @@ http://secondlife.com/account/request.php - + + - Name or Username: - - - - Password: - - - + Name or Username: + + + - - - + + + - Grid: - - - -