From c0ed4b6ff5301a7c90b32e3f552f84b84ee80465 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Thu, 31 Oct 2019 20:22:27 +0200 Subject: SL-11913 Favorites not resetting properly --- indra/newview/llpanellogin.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index d7c189271e..fd76a36044 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -41,7 +41,6 @@ #include "llcommandhandler.h" // for secondlife:///app/login/ #include "llcombobox.h" #include "llviewercontrol.h" -#include "llfloaterpreference.h" #include "llfocusmgr.h" #include "lllineeditor.h" #include "llnotificationsutil.h" @@ -456,6 +455,10 @@ void LLPanelLogin::addFavoritesToStartLocation() } break; } + if (combo->getValue().asString().empty()) + { + combo->selectFirstItem(); + } } LLPanelLogin::~LLPanelLogin() @@ -1275,13 +1278,13 @@ void LLPanelLogin::onSelectServer() { std::string location = location_combo->getValue().asString(); LLSLURL slurl(location); // generata a slurl from the location combo contents - if ( slurl.getType() == LLSLURL::LOCATION - && slurl.getGrid() != LLGridManager::getInstance()->getGrid() - ) + if (location.empty() + || (slurl.getType() == LLSLURL::LOCATION + && slurl.getGrid() != LLGridManager::getInstance()->getGrid()) + ) { // the grid specified by the location is not this one, so clear the combo location_combo->setCurrentByIndex(0); // last location on the new grid - location_combo->setTextEntry(LLStringUtil::null); } } break; -- cgit v1.2.3 From aadbb3d912af1184fd9c5210e5066d9d92e0dacd Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Thu, 31 Oct 2019 23:17:10 +0200 Subject: SL-11732 Validation for stored favorites --- indra/newview/llfavoritesbar.cpp | 29 +++++++++++++++++++++++------ indra/newview/llfavoritesbar.h | 5 ++++- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 17952349dc..347997a69a 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1590,14 +1590,29 @@ void LLFavoritesOrderStorage::load() << (fav_llsd.isMap() ? "" : "un") << "successfully" << LL_ENDL; in_file.close(); - user_llsd = fav_llsd[gAgentUsername]; + if (fav_llsd.isMap() && fav_llsd.has(gAgentUsername)) + { + user_llsd = fav_llsd[gAgentUsername]; - S32 index = 0; - for (LLSD::array_iterator iter = user_llsd.beginArray(); + S32 index = 0; + bool needs_validation = gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"); + for (LLSD::array_iterator iter = user_llsd.beginArray(); iter != user_llsd.endArray(); ++iter) - { - mSortIndexes.insert(std::make_pair(iter->get("id").asUUID(), index)); - index++; + { + // Validation + LLUUID fv_id = iter->get("id").asUUID(); + if (needs_validation + && (fv_id.isNull() + || iter->get("asset_id").asUUID().isNull() + || iter->get("name").asString().empty() + || iter->get("slurl").asString().empty())) + { + mRecreateFavoriteStorage = true; + } + + mSortIndexes.insert(std::make_pair(fv_id, index)); + index++; + } } } else @@ -1841,6 +1856,8 @@ void LLFavoritesOrderStorage::rearrangeFavoriteLandmarks(const LLUUID& source_it BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed) { + pref_changed |= mRecreateFavoriteStorage; + mRecreateFavoriteStorage = false; LLUUID favorite_folder= gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); if (favorite_folder.isNull()) diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index d93161fd7a..571208aa31 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -248,6 +248,7 @@ private: slurls_map_t mSLURLs; std::set mMissingSLURLs; bool mIsDirty; + bool mRecreateFavoriteStorage; struct IsNotInFavorites { @@ -278,7 +279,9 @@ private: inline LLFavoritesOrderStorage::LLFavoritesOrderStorage() : - mIsDirty(false), mUpdateRequired(false) + mIsDirty(false), + mUpdateRequired(false), + mRecreateFavoriteStorage(false) { load(); } #endif // LL_LLFAVORITESBARCTRL_H -- cgit v1.2.3 From 4d7c106a6108ff88b5b5211addc5e8b7506fb1b1 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Thu, 19 Sep 2019 16:57:22 +0300 Subject: SL-6109 New cell type with icon and text (and 1 pixel offset for all text cells) --- indra/llui/llscrolllistcell.cpp | 146 +++++++++++++++++++++++++++++++++++++++- indra/llui/llscrolllistcell.h | 29 +++++++- 2 files changed, 169 insertions(+), 6 deletions(-) diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp index 8000efad0e..63762ab8b8 100644 --- a/indra/llui/llscrolllistcell.cpp +++ b/indra/llui/llscrolllistcell.cpp @@ -50,6 +50,10 @@ LLScrollListCell* LLScrollListCell::create(const LLScrollListCell::Params& cell_ { cell = new LLScrollListDate(cell_p); } + else if (cell_p.type() == "icontext") + { + cell = new LLScrollListIconText(cell_p); + } else // default is "text" { cell = new LLScrollListText(cell_p); @@ -168,7 +172,7 @@ U32 LLScrollListText::sCount = 0; LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p) : LLScrollListCell(p), - mText(p.value().asString()), + mText(p.text.isProvided() ? p.text() : p.value().asString()), mFont(p.font), mColor(p.color), mUseColor(p.color.isProvided()), @@ -296,7 +300,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col switch(mFontAlignment) { case LLFontGL::LEFT: - left = mFont->getWidth(mText.getString(), 0, mHighlightOffset); + left = mFont->getWidth(mText.getString(), 1, mHighlightOffset); break; case LLFontGL::RIGHT: left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX); @@ -319,7 +323,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col switch(mFontAlignment) { case LLFontGL::LEFT: - start_x = 0.f; + start_x = 1.f; break; case LLFontGL::RIGHT: start_x = (F32)getWidth(); @@ -435,3 +439,139 @@ const LLSD LLScrollListDate::getValue() const { return mDate; } + +// +// LLScrollListIconText +// +LLScrollListIconText::LLScrollListIconText(const LLScrollListCell::Params& p) + : LLScrollListText(p), + mIcon(p.value().isUUID() ? LLUI::getUIImageByID(p.value().asUUID()) : LLUI::getUIImage(p.value().asString())), + mPad(4) +{ + mTextWidth = getWidth() - mPad /*padding*/ - mFont->getLineHeight(); +} + +LLScrollListIconText::~LLScrollListIconText() +{ +} + +const LLSD LLScrollListIconText::getValue() const +{ + if (mIcon.isNull()) + { + return LLStringUtil::null; + } + return mIcon->getName(); +} + +void LLScrollListIconText::setValue(const LLSD& value) +{ + if (value.isUUID()) + { + // don't use default image specified by LLUUID::null, use no image in that case + LLUUID image_id = value.asUUID(); + mIcon = image_id.notNull() ? LLUI::getUIImageByID(image_id) : LLUIImagePtr(NULL); + } + else + { + std::string value_string = value.asString(); + if (LLUUID::validate(value_string)) + { + setValue(LLUUID(value_string)); + } + else if (!value_string.empty()) + { + mIcon = LLUI::getUIImage(value.asString()); + } + else + { + mIcon = NULL; + } + } +} + +void LLScrollListIconText::setWidth(S32 width) +{ + LLScrollListCell::setWidth(width); + // Assume that iamge height and width is identical to font height and width + mTextWidth = width - mPad /*padding*/ - mFont->getLineHeight(); +} + + +void LLScrollListIconText::draw(const LLColor4& color, const LLColor4& highlight_color) const +{ + LLColor4 display_color; + if (mUseColor) + { + display_color = mColor; + } + else + { + display_color = color; + } + + S32 icon_height = mFont->getLineHeight(); + S32 icon_space = mIcon ? (icon_height + mPad) : 0; + + if (mHighlightCount > 0) + { + S32 left = 0; + switch (mFontAlignment) + { + case LLFontGL::LEFT: + left = mFont->getWidth(mText.getString(), icon_space + 1, mHighlightOffset); + break; + case LLFontGL::RIGHT: + left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX) - icon_space; + break; + case LLFontGL::HCENTER: + left = (getWidth() - mFont->getWidth(mText.getString()) - icon_space) / 2; + break; + } + LLRect highlight_rect(left - 2, + mFont->getLineHeight() + 1, + left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1, + 1); + mRoundedRectImage->draw(highlight_rect, highlight_color); + } + + // Try to draw the entire string + F32 right_x; + U32 string_chars = mText.length(); + F32 start_text_x = 0.f; + S32 start_icon_x = 0; + switch (mFontAlignment) + { + case LLFontGL::LEFT: + start_text_x = icon_space + 1; + start_icon_x = 1; + break; + case LLFontGL::RIGHT: + start_text_x = (F32)getWidth(); + start_icon_x = getWidth() - mFont->getWidth(mText.getString()) - icon_space; + break; + case LLFontGL::HCENTER: + F32 center = (F32)getWidth()* 0.5f; + start_text_x = center + ((F32)icon_space * 0.5f); + start_icon_x = center - (((F32)icon_space + mFont->getWidth(mText.getString())) * 0.5f); + break; + } + mFont->render(mText.getWString(), 0, + start_text_x, 0.f, + display_color, + mFontAlignment, + LLFontGL::BOTTOM, + 0, + LLFontGL::NO_SHADOW, + string_chars, + getTextWidth(), + &right_x, + TRUE); + + if (mIcon) + { + mIcon->draw(start_icon_x, 0, icon_height, icon_height, mColor); + } +} + + diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h index d625ebddcc..1604a9b1dc 100644 --- a/indra/llui/llscrolllistcell.h +++ b/indra/llui/llscrolllistcell.h @@ -59,7 +59,8 @@ public: visible; Optional userdata; - Optional value; + Optional value; // state of checkbox, icon id/name, date + Optional text; // description or text Optional tool_tip; Optional font; @@ -152,7 +153,7 @@ public: void setText(const LLStringExplicit& text); void setFontStyle(const U8 font_style); -private: +protected: LLUIString mText; S32 mTextWidth; const LLFontGL* mFont; @@ -169,7 +170,7 @@ private: }; /* - * Cell displaying an image. + * Cell displaying an image. AT the moment, this is specifically UI image */ class LLScrollListIcon : public LLScrollListCell { @@ -223,4 +224,26 @@ private: LLDate mDate; }; +/* +* Cell displaying icon and text. +*/ + +class LLScrollListIconText : public LLScrollListText +{ +public: + LLScrollListIconText(const LLScrollListCell::Params& p); + /*virtual*/ ~LLScrollListIconText(); + /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; + /*virtual*/ const LLSD getValue() const; + /*virtual*/ void setValue(const LLSD& value); + + + S32 getIconWidth() const; + /*virtual*/ void setWidth(S32 width);/* { LLScrollListCell::setWidth(width); mTextWidth = width - ; }*/ + +private: + LLPointer mIcon; + S32 mPad; +}; + #endif -- cgit v1.2.3 From fc238f6ca06b6fc71ed3bb7c3968f48406bb2c09 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Thu, 19 Sep 2019 16:59:23 +0300 Subject: SL-6109 Extended Key-to-string functionality --- indra/llui/llmenugl.cpp | 10 +++--- indra/llui/llmenugl.h | 13 ++++++-- indra/llwindow/llkeyboard.cpp | 77 +++++++++++++++++++++++-------------------- indra/llwindow/llkeyboard.h | 14 ++------ 4 files changed, 60 insertions(+), 54 deletions(-) diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 676c94468f..e6a3de281e 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -263,13 +263,13 @@ BOOL LLMenuItemGL::handleRightMouseUp(S32 x, S32 y, MASK mask) // This function checks to see if the accelerator key is already in use; // if not, it will be added to the list -BOOL LLMenuItemGL::addToAcceleratorList(std::list *listp) +BOOL LLMenuItemGL::addToAcceleratorList(std::list *listp) { - LLKeyBinding *accelerator = NULL; + LLMenuKeyboardBinding *accelerator = NULL; if (mAcceleratorKey != KEY_NONE) { - std::list::iterator list_it; + std::list::iterator list_it; for (list_it = listp->begin(); list_it != listp->end(); ++list_it) { accelerator = *list_it; @@ -293,7 +293,7 @@ BOOL LLMenuItemGL::addToAcceleratorList(std::list *listp) } if (!accelerator) { - accelerator = new LLKeyBinding; + accelerator = new LLMenuKeyboardBinding; if (accelerator) { accelerator->mKey = mAcceleratorKey; @@ -1024,7 +1024,7 @@ BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask) // This function checks to see if the accelerator key is already in use; // if not, it will be added to the list -BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list *listp) +BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list *listp) { LLMenuGL* branch = getBranch(); if (!branch) diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 78f688642e..3a6b849e73 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -42,6 +42,13 @@ extern S32 MENU_BAR_HEIGHT; extern S32 MENU_BAR_WIDTH; +class LLMenuKeyboardBinding +{ +public: + KEY mKey; + MASK mMask; +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLMenuItemGL // @@ -109,7 +116,7 @@ public: virtual void setBriefItem(BOOL brief); virtual BOOL isBriefItem() const; - virtual BOOL addToAcceleratorList(std::list *listp); + virtual BOOL addToAcceleratorList(std::list *listp); void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; } BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; } @@ -628,7 +635,7 @@ public: virtual BOOL handleAcceleratorKey(KEY key, MASK mask); // check if we've used these accelerators already - virtual BOOL addToAcceleratorList(std::list *listp); + virtual BOOL addToAcceleratorList(std::list *listp); // called to rebuild the draw label virtual void buildDrawLabel( void ); @@ -794,7 +801,7 @@ private: void checkMenuTrigger(); - std::list mAccelerators; + std::list mAccelerators; BOOL mAltKeyTrigger; }; diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp index f6f6c3931c..8e75325859 100644 --- a/indra/llwindow/llkeyboard.cpp +++ b/indra/llwindow/llkeyboard.cpp @@ -347,7 +347,48 @@ std::string LLKeyboard::stringFromKey(KEY key) return res; } +//static +std::string LLKeyboard::stringFromAccelerator(MASK accel_mask) +{ + std::string res; + + LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator; + if (trans == NULL) + { + LL_ERRS() << "No mKeyStringTranslator" << LL_ENDL; + return res; + } + + // Append any masks +#ifdef LL_DARWIN + // Standard Mac names for modifier keys in menu equivalents + // We could use the symbol characters, but they only exist in certain fonts. + if (accel_mask & MASK_CONTROL) + { + if (accel_mask & MASK_MAC_CONTROL) + { + res.append(trans("accel-mac-control")); + } + else + { + res.append(trans("accel-mac-command")); // Symbol would be "\xE2\x8C\x98" + } + } + if (accel_mask & MASK_ALT) + res.append(trans("accel-mac-option")); // Symbol would be "\xE2\x8C\xA5" + if (accel_mask & MASK_SHIFT) + res.append(trans("accel-mac-shift")); // Symbol would be "\xE2\x8C\xA7" +#else + if (accel_mask & MASK_CONTROL) + res.append(trans("accel-win-control")); + if (accel_mask & MASK_ALT) + res.append(trans("accel-win-alt")); + if (accel_mask & MASK_SHIFT) + res.append(trans("accel-win-shift")); +#endif + return res; +} //static std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key ) { @@ -359,41 +400,7 @@ std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key ) return res; } - LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator; - - if( trans == NULL ) - { - LL_ERRS() << "No mKeyStringTranslator" << LL_ENDL; - return res; - } - - // Append any masks -#ifdef LL_DARWIN - // Standard Mac names for modifier keys in menu equivalents - // We could use the symbol characters, but they only exist in certain fonts. - if( accel_mask & MASK_CONTROL ) - { - if ( accel_mask & MASK_MAC_CONTROL ) - { - res.append( trans("accel-mac-control") ); - } - else - { - res.append( trans("accel-mac-command") ); // Symbol would be "\xE2\x8C\x98" - } - } - if( accel_mask & MASK_ALT ) - res.append( trans("accel-mac-option") ); // Symbol would be "\xE2\x8C\xA5" - if( accel_mask & MASK_SHIFT ) - res.append( trans("accel-mac-shift") ); // Symbol would be "\xE2\x8C\xA7" -#else - if( accel_mask & MASK_CONTROL ) - res.append( trans("accel-win-control") ); - if( accel_mask & MASK_ALT ) - res.append( trans("accel-win-alt") ); - if( accel_mask & MASK_SHIFT ) - res.append( trans("accel-win-shift") ); -#endif + res.append(stringFromAccelerator(accel_mask)); std::string key_string = LLKeyboard::stringFromKey(key); if ((accel_mask & MASK_NORMALKEYS) && (key_string[0] == '-' || key_string[0] == '=' || key_string[0] == '+')) diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index 6f2dc87317..f6404164e7 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -38,10 +38,10 @@ enum EKeystate { KEYSTATE_DOWN, KEYSTATE_LEVEL, - KEYSTATE_UP + KEYSTATE_UP }; -typedef boost::function LLKeyFunc; +typedef boost::function LLKeyFunc; typedef std::string (LLKeyStringTranslatorFunc)(const char *label); enum EKeyboardInsertMode @@ -50,15 +50,6 @@ enum EKeyboardInsertMode LL_KIM_OVERWRITE }; -class LLKeyBinding -{ -public: - KEY mKey; - MASK mMask; -// const char *mName; // unused - LLKeyFunc mFunction; -}; - class LLWindowCallbacks; class LLKeyboard @@ -104,6 +95,7 @@ public: static BOOL maskFromString(const std::string& str, MASK *mask); // False on failure static BOOL keyFromString(const std::string& str, KEY *key); // False on failure static std::string stringFromKey(KEY key); + static std::string stringFromAccelerator( MASK accel_mask ); // separated for convinience, returns with "+": "Shift+" or "Shift+Alt+"... static std::string stringFromAccelerator( MASK accel_mask, KEY key ); void setCallbacks(LLWindowCallbacks *cbs) { mCallbacks = cbs; } -- cgit v1.2.3 From dcb1bea0f6086d963fba8b374d0294223bf66a11 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Thu, 19 Sep 2019 16:55:28 +0300 Subject: SL-6109 Implement keybindings --- indra/llcommon/CMakeLists.txt | 2 + indra/llcommon/indra_constants.h | 10 +++ indra/llcommon/llkeybind.cpp | 147 ++++++++++++++++++++++++++++++++++ indra/llcommon/llkeybind.h | 70 ++++++++++++++++ indra/llwindow/llmousehandler.cpp | 2 +- indra/llwindow/llmousehandler.h | 12 +-- indra/llxml/CMakeLists.txt | 1 - indra/llxml/llcontrol.h | 2 - indra/llxml/llcontrolgroupreader.h | 80 ------------------ indra/newview/llfloaterpreference.cpp | 14 ++-- indra/newview/llfloaterpreference.h | 2 +- indra/newview/lltool.cpp | 2 +- indra/newview/lltool.h | 2 +- indra/newview/lltoolpie.cpp | 2 +- indra/newview/lltoolpie.h | 2 +- indra/newview/llviewerwindow.cpp | 39 +++++---- indra/newview/llviewerwindow.h | 2 +- indra/newview/llvoiceclient.cpp | 8 +- indra/newview/llvoiceclient.h | 2 +- 19 files changed, 268 insertions(+), 133 deletions(-) create mode 100644 indra/llcommon/llkeybind.cpp create mode 100644 indra/llcommon/llkeybind.h delete mode 100644 indra/llxml/llcontrolgroupreader.h diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index af41b9e460..7e52a620db 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -73,6 +73,7 @@ set(llcommon_SOURCE_FILES llinitparam.cpp llinitdestroyclass.cpp llinstancetracker.cpp + llkeybind.cpp llleap.cpp llleaplistener.cpp llliveappconfig.cpp @@ -183,6 +184,7 @@ set(llcommon_HEADER_FILES llinitdestroyclass.h llinitparam.h llinstancetracker.h + llkeybind.h llkeythrottle.h llleap.h llleaplistener.h diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 0fbf4b966b..e763d413e5 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -54,6 +54,16 @@ enum ETerrainBrushType E_LANDBRUSH_INVALID = 6 }; +enum EMouseClickType{ + CLICK_NONE = -1, + CLICK_LEFT = 0, + CLICK_MIDDLE, + CLICK_RIGHT, + CLICK_BUTTON4, + CLICK_BUTTON5, + CLICK_DOUBLELEFT +}; + // keys // Bit masks for various keyboard modifier keys. const MASK MASK_NONE = 0x0000; diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp new file mode 100644 index 0000000000..f227c0a1a5 --- /dev/null +++ b/indra/llcommon/llkeybind.cpp @@ -0,0 +1,147 @@ +/** + * @file llkeybind.cpp + * @brief Information about key combinations. + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2019, 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" + +#include "llkeybind.h" + +#include "llsd.h" +#include "llsdutil.h" + +LLKeyData::LLKeyData() + : mMouse(CLICK_NONE), mKey(KEY_NONE), mMask(MASK_NONE) +{ +} + +LLKeyData::LLKeyData(const LLSD &key_data) +{ + mMouse = (EMouseClickType)key_data["mouse"].asInteger(); + mKey = key_data["key"].asInteger(); + mMask = key_data["mask"].asInteger(); +} + +LLSD LLKeyData::asLLSD() const +{ + LLSD data; + data["mouse"] = (LLSD::Integer)mMouse; + data["key"] = (LLSD::Integer)mKey; + data["mask"] = (LLSD::Integer)mMask; + return data; +} + +bool LLKeyData::isEmpty() const +{ + return mMouse == CLICK_NONE && mKey == KEY_NONE && mMask == MASK_NONE; +} + +void LLKeyData::reset() +{ + mMouse = CLICK_NONE; + mKey = KEY_NONE; + mMask = MASK_NONE; +} + +LLKeyData& LLKeyData::operator=(const LLKeyData& rhs) +{ + mMouse = rhs.mMouse; + mKey = rhs.mKey; + mMask = rhs.mMask; + return *this; +} + +// LLKeyBind + +LLKeyBind::LLKeyBind(const LLSD &key_bind) +{ + if (key_bind.has("DataPrimary")) + { + mDataPrimary = LLKeyData(key_bind["DataPrimary"]); + } + if (key_bind.has("DataSecondary")) + { + mDataSecondary = LLKeyData(key_bind["DataSecondary"]); + } +} + +bool LLKeyBind::operator==(const LLKeyBind& rhs) +{ + if (mDataPrimary.mMouse != rhs.mDataPrimary.mMouse) return false; + if (mDataPrimary.mKey != rhs.mDataPrimary.mKey) return false; + if (mDataPrimary.mMask != rhs.mDataPrimary.mMask) return false; + if (mDataSecondary.mMouse != rhs.mDataSecondary.mMouse) return false; + if (mDataSecondary.mKey != rhs.mDataSecondary.mKey) return false; + if (mDataSecondary.mMask != rhs.mDataSecondary.mMask) return false; + return true; +} + +bool LLKeyBind::empty() +{ + if (mDataPrimary.mMouse != CLICK_NONE) return false; + if (mDataPrimary.mKey != KEY_NONE) return false; + if (mDataPrimary.mMask != MASK_NONE) return false; + if (mDataSecondary.mMouse != CLICK_NONE) return false; + if (mDataSecondary.mKey != KEY_NONE) return false; + if (mDataSecondary.mMask != MASK_NONE) return false; + return false; +} + +LLSD LLKeyBind::asLLSD() const +{ + LLSD data; + if (!mDataPrimary.isEmpty()) + { + data["DataPrimary"] = mDataPrimary.asLLSD(); + } + if (!mDataSecondary.isEmpty()) + { + data["DataSecondary"] = mDataSecondary.asLLSD(); + } + return data; +} + +bool LLKeyBind::canHandle(EMouseClickType mouse, KEY key, MASK mask) const +{ + if (mDataPrimary.mKey == key && mDataPrimary.mMask == mask && mDataPrimary.mMouse == mouse) + { + return true; + } + if (mDataSecondary.mKey == key && mDataSecondary.mMask == mask && mDataSecondary.mMouse == mouse) + { + return true; + } + return false; +} + +bool LLKeyBind::canHandleKey(KEY key, MASK mask) const +{ + return canHandle(CLICK_NONE, key, mask); +} + +bool LLKeyBind::canHandleMouse(EMouseClickType mouse, MASK mask) const +{ + return canHandle(mouse, KEY_NONE, mask); +} + diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h new file mode 100644 index 0000000000..4fe622fb79 --- /dev/null +++ b/indra/llcommon/llkeybind.h @@ -0,0 +1,70 @@ +/** + * @file llkeybind.h + * @brief Information about key combinations. + * + * $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$ + */ + +#ifndef LL_KEYBIND_H +#define LL_KEYBIND_H + +#include "indra_constants.h" + +// KeyData - single key combination (mouse/mask/keyboard) +class LL_COMMON_API LLKeyData +{ +public: + LLKeyData(); + LLKeyData(const LLSD &key_data); + + LLSD asLLSD() const; + bool isEmpty() const; + void reset(); + LLKeyData& operator=(const LLKeyData& rhs); + + EMouseClickType mMouse; + KEY mKey; + MASK mMask; +}; + +// One function can bind to multiple Key options +class LLKeyBind +{ +public: + LLKeyBind() {} + LLKeyBind(const LLSD &key_bind); + + bool operator==(const LLKeyBind& rhs); + bool empty(); + + LLSD asLLSD() const; + + bool canHandle(EMouseClickType mouse, KEY key, MASK mask) const; + bool canHandleKey(KEY key, MASK mask) const; + bool canHandleMouse(EMouseClickType mouse, MASK mask) const; + + LLKeyData mDataPrimary; + LLKeyData mDataSecondary; +}; + + +#endif // LL_KEYBIND_H diff --git a/indra/llwindow/llmousehandler.cpp b/indra/llwindow/llmousehandler.cpp index d5fa65fe4b..e41ebd42f3 100644 --- a/indra/llwindow/llmousehandler.cpp +++ b/indra/llwindow/llmousehandler.cpp @@ -27,7 +27,7 @@ #include "llmousehandler.h" //virtual -BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down) +BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL handled = FALSE; if (down) diff --git a/indra/llwindow/llmousehandler.h b/indra/llwindow/llmousehandler.h index 1dcd0348d8..d221dd117c 100644 --- a/indra/llwindow/llmousehandler.h +++ b/indra/llwindow/llmousehandler.h @@ -29,6 +29,7 @@ #include "linden_common.h" #include "llrect.h" +#include "indra_constants.h" // Mostly-abstract interface. // Intended for use via multiple inheritance. @@ -46,16 +47,7 @@ public: SHOW_ALWAYS, } EShowToolTip; - typedef enum { - CLICK_LEFT, - CLICK_MIDDLE, - CLICK_RIGHT, - CLICK_BUTTON4, - CLICK_BUTTON5, - CLICK_DOUBLELEFT - } EClickType; - - virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down); + virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) = 0; virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) = 0; virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask) = 0; diff --git a/indra/llxml/CMakeLists.txt b/indra/llxml/CMakeLists.txt index 17400a203e..013a422d35 100644 --- a/indra/llxml/CMakeLists.txt +++ b/indra/llxml/CMakeLists.txt @@ -28,7 +28,6 @@ set(llxml_HEADER_FILES CMakeLists.txt llcontrol.h - llcontrolgroupreader.h llxmlnode.h llxmlparser.h llxmltree.h diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index de0d366492..9312bbc91a 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -34,8 +34,6 @@ #include "llrefcount.h" #include "llinstancetracker.h" -#include "llcontrolgroupreader.h" - #include // *NOTE: boost::visit_each<> generates warning 4675 on .net 2003 diff --git a/indra/llxml/llcontrolgroupreader.h b/indra/llxml/llcontrolgroupreader.h deleted file mode 100644 index 6a27a65499..0000000000 --- a/indra/llxml/llcontrolgroupreader.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @file llcontrolgroupreader.h - * @brief Interface providing readonly access to LLControlGroup (intended for unit testing) - * - * $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$ - */ - -#ifndef LL_LLCONTROLGROUPREADER_H -#define LL_LLCONTROLGROUPREADER_H - -#include "stdtypes.h" -#include - -#include "v3math.h" -#include "v3dmath.h" -#include "v3color.h" -#include "v4color.h" -#include "llrect.h" - -class LLControlGroupReader -{ -public: - LLControlGroupReader() {} - virtual ~LLControlGroupReader() {} - - virtual std::string getString(const std::string& name) { return ""; } - virtual LLWString getWString(const std::string& name) { return LLWString(); } - virtual std::string getText(const std::string& name) { return ""; } - virtual LLVector3 getVector3(const std::string& name) { return LLVector3(); } - virtual LLVector3d getVector3d(const std::string& name) { return LLVector3d(); } - virtual LLRect getRect(const std::string& name) { return LLRect(); } - virtual BOOL getBOOL(const std::string& name) { return FALSE; } - virtual S32 getS32(const std::string& name) { return 0; } - virtual F32 getF32(const std::string& name) {return 0.0f; } - virtual U32 getU32(const std::string& name) {return 0; } - virtual LLSD getLLSD(const std::string& name) { return LLSD(); } - - virtual LLColor4 getColor(const std::string& name) { return LLColor4(); } - virtual LLColor4 getColor4(const std::string& name) { return LLColor4(); } - virtual LLColor3 getColor3(const std::string& name) { return LLColor3(); } - - virtual void setBOOL(const std::string& name, BOOL val) {} - virtual void setS32(const std::string& name, S32 val) {} - virtual void setF32(const std::string& name, F32 val) {} - virtual void setU32(const std::string& name, U32 val) {} - virtual void setString(const std::string& name, const std::string& val) {} - virtual void setVector3(const std::string& name, const LLVector3 &val) {} - virtual void setVector3d(const std::string& name, const LLVector3d &val) {} - virtual void setRect(const std::string& name, const LLRect &val) {} - virtual void setColor4(const std::string& name, const LLColor4 &val) {} - virtual void setLLSD(const std::string& name, const LLSD& val) {} -}; - -#endif /* LL_LLCONTROLGROUPREADER_H */ - - - - - - - diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index b48495b5b2..9282196b86 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -170,7 +170,7 @@ public: void setParent(LLFloaterPreference* parent) { mParent = parent; } BOOL handleKeyHere(KEY key, MASK mask); - BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down); + BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); static void onCancel(void* user_data); private: @@ -214,11 +214,11 @@ BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask) return result; } -BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down) +BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL result = FALSE; if (down - && (clicktype == LLMouseHandler::CLICK_MIDDLE || clicktype == LLMouseHandler::CLICK_BUTTON4 || clicktype == LLMouseHandler::CLICK_BUTTON5) + && (clicktype == CLICK_MIDDLE || clicktype == CLICK_BUTTON4 || clicktype == CLICK_BUTTON5) && mask == 0) { mParent->setMouse(clicktype); @@ -1717,21 +1717,21 @@ void LLFloaterPreference::setKey(KEY key) getChild("modifier_combo")->onCommit(); } -void LLFloaterPreference::setMouse(LLMouseHandler::EClickType click) +void LLFloaterPreference::setMouse(EMouseClickType click) { std::string bt_name; std::string ctrl_value; switch (click) { - case LLMouseHandler::CLICK_MIDDLE: + case CLICK_MIDDLE: bt_name = "middle_mouse"; ctrl_value = MIDDLE_MOUSE_CV; break; - case LLMouseHandler::CLICK_BUTTON4: + case CLICK_BUTTON4: bt_name = "button4_mouse"; ctrl_value = MOUSE_BUTTON_4_CV; break; - case LLMouseHandler::CLICK_BUTTON5: + case CLICK_BUTTON5: bt_name = "button5_mouse"; ctrl_value = MOUSE_BUTTON_5_CV; break; diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 4412c95473..9190ef8ebd 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -148,7 +148,7 @@ public: void onSelectSkin(); void onClickSetKey(); void setKey(KEY key); - void setMouse(LLMouseHandler::EClickType click); + void setMouse(EMouseClickType click); void onClickSetMiddleMouse(); void onClickSetSounds(); void onClickEnablePopup(); diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp index c5e31ff8e6..0038138078 100644 --- a/indra/newview/lltool.cpp +++ b/indra/newview/lltool.cpp @@ -60,7 +60,7 @@ LLTool::~LLTool() } } -BOOL LLTool::handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down) +BOOL LLTool::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); diff --git a/indra/newview/lltool.h b/indra/newview/lltool.h index 308983afda..41a38804ce 100644 --- a/indra/newview/lltool.h +++ b/indra/newview/lltool.h @@ -49,7 +49,7 @@ public: virtual BOOL isView() const { return FALSE; } // Virtual functions inherited from LLMouseHandler - virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down); + virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 6c1ae7159b..0b569b4fe8 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -91,7 +91,7 @@ LLToolPie::LLToolPie() { } -BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down) +BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index fe0acfe473..6d0e25eaeb 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -42,7 +42,7 @@ class LLToolPie : public LLTool, public LLSingleton public: // Virtual functions inherited from LLMouseHandler - virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down); + virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 1e2b2c37d0..2c58295814 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -898,7 +898,7 @@ LLViewerWindow::Params::Params() {} -BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down) +BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down) { const char* buttonname = ""; const char* buttonstatestr = ""; @@ -907,6 +907,8 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK x = ll_round((F32)x / mDisplayScale.mV[VX]); y = ll_round((F32)y / mDisplayScale.mV[VY]); + LLVoiceClient::getInstance()->updateMouseState(clicktype, mask, down); + // only send mouse clicks to UI if UI is visible if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) { @@ -922,26 +924,26 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK switch (clicktype) { - case LLMouseHandler::CLICK_LEFT: + case CLICK_LEFT: mLeftMouseDown = down; buttonname = "Left"; break; - case LLMouseHandler::CLICK_RIGHT: + case CLICK_RIGHT: mRightMouseDown = down; buttonname = "Right"; break; - case LLMouseHandler::CLICK_MIDDLE: + case CLICK_MIDDLE: mMiddleMouseDown = down; buttonname = "Middle"; break; - case LLMouseHandler::CLICK_DOUBLELEFT: + case CLICK_DOUBLELEFT: mLeftMouseDown = down; buttonname = "Left Double Click"; break; - case LLMouseHandler::CLICK_BUTTON4: + case CLICK_BUTTON4: buttonname = "Button 4"; break; - case LLMouseHandler::CLICK_BUTTON5: + case CLICK_BUTTON5: buttonname = "Button 5"; break; } @@ -1059,7 +1061,7 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask mMouseDownTimer.reset(); } BOOL down = TRUE; - return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); + return handleAnyMouseClick(window, pos, mask, CLICK_LEFT, down); } BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask) @@ -1067,8 +1069,7 @@ BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK ma // try handling as a double-click first, then a single-click if that // wasn't handled. BOOL down = TRUE; - if (handleAnyMouseClick(window, pos, mask, - LLMouseHandler::CLICK_DOUBLELEFT, down)) + if (handleAnyMouseClick(window, pos, mask, CLICK_DOUBLELEFT, down)) { return TRUE; } @@ -1082,7 +1083,7 @@ BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) mMouseDownTimer.stop(); } BOOL down = FALSE; - return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); + return handleAnyMouseClick(window, pos, mask, CLICK_LEFT, down); } @@ -1094,7 +1095,7 @@ BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK y = ll_round((F32)y / mDisplayScale.mV[VY]); BOOL down = TRUE; - BOOL handle = handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down); + BOOL handle = handleAnyMouseClick(window, pos, mask, CLICK_RIGHT, down); if (handle) return handle; @@ -1115,14 +1116,13 @@ BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { BOOL down = FALSE; - return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down); + return handleAnyMouseClick(window, pos, mask, CLICK_RIGHT, down); } BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) { BOOL down = TRUE; - LLVoiceClient::getInstance()->updateMouseState(LLMouseHandler::CLICK_MIDDLE, true); - handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down); + handleAnyMouseClick(window, pos, mask, CLICK_MIDDLE, down); // Always handled as far as the OS is concerned. return TRUE; @@ -1277,8 +1277,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { BOOL down = FALSE; - LLVoiceClient::getInstance()->updateMouseState(LLMouseHandler::CLICK_MIDDLE, false); - handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down); + handleAnyMouseClick(window, pos, mask, CLICK_MIDDLE, down); // Always handled as far as the OS is concerned. return TRUE; @@ -1289,12 +1288,10 @@ BOOL LLViewerWindow::handleOtherMouse(LLWindow *window, LLCoordGL pos, MASK mask switch (button) { case 4: - LLVoiceClient::getInstance()->updateMouseState(LLMouseHandler::CLICK_BUTTON4, down); - handleAnyMouseClick(window, pos, mask, LLMouseHandler::CLICK_BUTTON4, down); + handleAnyMouseClick(window, pos, mask, CLICK_BUTTON4, down); break; case 5: - LLVoiceClient::getInstance()->updateMouseState(LLMouseHandler::CLICK_BUTTON5, down); - handleAnyMouseClick(window, pos, mask, LLMouseHandler::CLICK_BUTTON5, down); + handleAnyMouseClick(window, pos, mask, CLICK_BUTTON5, down); break; default: break; diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 385bbd57e5..5f03685cee 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -176,7 +176,7 @@ public: void setUIVisibility(bool); bool getUIVisibility(); - BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down); + BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down); // // LLWindowCallback interface implementation diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index bce399a940..e7a8a78c14 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -641,15 +641,15 @@ void LLVoiceClient::setPTTKey(std::string &key) // Value is stored as text for readability if(key == "MiddleMouse") { - mPTTMouseButton = LLMouseHandler::CLICK_MIDDLE; + mPTTMouseButton = CLICK_MIDDLE; } else if(key == "MouseButton4") { - mPTTMouseButton = LLMouseHandler::CLICK_BUTTON4; + mPTTMouseButton = CLICK_BUTTON4; } else if (key == "MouseButton5") { - mPTTMouseButton = LLMouseHandler::CLICK_BUTTON5; + mPTTMouseButton = CLICK_BUTTON5; } else { @@ -711,7 +711,7 @@ void LLVoiceClient::keyUp(KEY key, MASK mask) } } } -void LLVoiceClient::updateMouseState(S32 click, bool down) +void LLVoiceClient::updateMouseState(S32 click, MASK mask, bool down) { if(mPTTMouseButton == click && LLAgent::isActionAllowed("speak")) { diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index fbc85fd977..e3285b0c9b 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -418,7 +418,7 @@ public: // PTT key triggering void keyDown(KEY key, MASK mask); void keyUp(KEY key, MASK mask); - void updateMouseState(S32 click, bool down); + void updateMouseState(S32 click, MASK mask, bool down); boost::signals2::connection MicroChangedCallback(const micro_changed_signal_t::slot_type& cb ) { return mMicroChangedSignal.connect(cb); } -- cgit v1.2.3 From 50719510630768d65c9f00043676f287c58ca110 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Mon, 19 Aug 2019 23:16:29 +0300 Subject: SL_6109 Rebinding --- indra/newview/llfloaterpreference.cpp | 330 ++++++++++++++++++++- indra/newview/llfloaterpreference.h | 21 ++ indra/newview/llspatialpartition.cpp | 2 +- indra/newview/llvoiceclient.cpp | 7 +- .../skins/default/xui/en/floater_preferences.xml | 7 + .../default/xui/en/panel_preferences_controls.xml | 196 ++++++++++++ 6 files changed, 553 insertions(+), 10 deletions(-) create mode 100644 indra/newview/skins/default/xui/en/panel_preferences_controls.xml diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 9282196b86..182341685b 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -52,6 +52,7 @@ #include "llfavoritesbar.h" #include "llfloatersidepanelcontainer.h" #include "llfloaterimsession.h" +#include "llkeybindings.h" #include "llkeyboard.h" #include "llmodaldialog.h" #include "llnavigationbar.h" @@ -168,6 +169,7 @@ public: /*virtual*/ BOOL postBuild(); void setParent(LLFloaterPreference* parent) { mParent = parent; } + void setTmpParent(LLPanelPreferenceControls* parent) { mTmpParent = parent; } // todo: voice key will be removed, class renamved, so it will have only one parent BOOL handleKeyHere(KEY key, MASK mask); BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); @@ -175,11 +177,13 @@ public: private: LLFloaterPreference* mParent; + LLPanelPreferenceControls* mTmpParent;// todo: voice key will be removed, class renamved, so it will have only one parent }; LLVoiceSetKeyDialog::LLVoiceSetKeyDialog(const LLSD& key) : LLModalDialog(key), - mParent(NULL) + mParent(NULL), + mTmpParent(NULL) { } @@ -201,15 +205,30 @@ LLVoiceSetKeyDialog::~LLVoiceSetKeyDialog() BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask) { BOOL result = TRUE; + + if (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT || key == KEY_NONE) + { + // temp + return false; + } + // todo, same for escape if (key == 'Q' && mask == MASK_CONTROL) { result = FALSE; - } + if (mTmpParent) + { + mTmpParent->onSetKey(KEY_NONE, MASK_NONE); + } + } else if (mParent) { mParent->setKey(key); } + else if (mTmpParent) + { + mTmpParent->onSetKey(key, mask); + } closeFloater(); return result; } @@ -217,11 +236,38 @@ BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask) BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL result = FALSE; - if (down - && (clicktype == CLICK_MIDDLE || clicktype == CLICK_BUTTON4 || clicktype == CLICK_BUTTON5) - && mask == 0) + + if (clicktype == CLICK_LEFT) + { + if (down) + { + result = LLView::handleMouseDown(x, y, mask); + } + else + { + result = LLView::handleMouseUp(x, y, mask); + } + } + if (clicktype == LLMouseHandler::CLICK_LEFT) + { + result = LLView::handleDoubleClick(x, y, mask); + } + if (result) + { + return TRUE; + } + if (down && clicktype != LLMouseHandler::CLICK_RIGHT) //tmp + //&& (clicktype == LLMouseHandler::CLICK_MIDDLE || clicktype == LLMouseHandler::CLICK_BUTTON4 || clicktype == LLMouseHandler::CLICK_BUTTON5) + //&& mask == 0) { - mParent->setMouse(clicktype); + if (mParent) + { + mParent->setMouse(clicktype); + } + else if (mTmpParent) + { + mTmpParent->onSetMouse(clicktype, mask); + } result = TRUE; closeFloater(); } @@ -237,6 +283,11 @@ BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseCli void LLVoiceSetKeyDialog::onCancel(void* user_data) { LLVoiceSetKeyDialog* self = (LLVoiceSetKeyDialog*)user_data; + // tmp needs 'no key' button + if (self->mTmpParent) + { + self->mTmpParent->onSetKey(KEY_NONE, MASK_NONE); + } self->closeFloater(); } @@ -2914,6 +2965,273 @@ void LLPanelPreferenceGraphics::setHardwareDefaults() resetDirtyChilds(); } + +//-------------------For LLPanelPreferenceControls' list--------------------------- +class LLGroupControlsListItem : public LLScrollListItem, public LLHandleProvider +{ +public: + LLGroupControlsListItem(const LLScrollListItem::Params& p) + : LLScrollListItem(p) + { + } + + LLGroupControlsListItem(const LLScrollListItem::Params& p, const LLUUID& icon_id) + : LLScrollListItem(p), mIconId(icon_id) + { + } + + void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding) + { + // todo: insert image and adjust rect + LLScrollListItem::draw(rect, fg_color, bg_color, highlight_color, column_padding); + } +private: + LLUUID mIconId; +}; + +static const std::string tmp_typetostring[LLControlBindings::CONTROL_NUM_INDICES] = { + "control_view_actions", + "control_about", + "control_orbit", + "control_pan", + "control_world_map", + "control_zoom", + "control_interactions", + "control_build", + "control_drag", + "control_edit", + "control_menu", + "control_open", + "control_touch", + "control_wear", + "control_movements", + "control_moveto", + "control_sit", + "control_teleportto", + "control_forward", + "control_backward", + "control_left", + "control_right", + "control_lstrafe", + "control_rstrafe", + "control_jump", + "control_down", + "control_run", + "control_toggle_run", + "control_fly", + "control_mediacontent", + "control_parcel", + "control_media", + "control_voice", + "control_toggle_voice", + "control_reserved", + "control_menu", + "control_reserved_select", + "control_shift_select", + "control_cntrl_select" +}; + +//------------------------LLPanelPreferenceControls-------------------------------- +static LLPanelInjector t_pref_contrls("panel_preference_controls"); + +BOOL LLPanelPreferenceControls::postBuild() +{ + //todo: on open instead of on the go + //todo: add pitch/yaw? + //todo: Scroll? + //todo: should be auto-expandable with menu items and should pull names from menu when possible + + + // populate list of controls + pControlsTable = getChild("controls_list"); + populateControlTable(); + + pControlsTable->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onListCommit, this)); + + return TRUE; +} + +void LLPanelPreferenceControls::populateControlTable() +{ + pControlsTable->clearRows(); + + // todo: subsections need sorting? + std::string label; + LLScrollListCell::Params cell_params; + // init basic cell params + cell_params.font = LLFontGL::getFontSansSerif(); + cell_params.font_halign = LLFontGL::LEFT; + cell_params.column = ""; + cell_params.value = label; + + LLScrollListItem::Params item_params_blank; + cell_params.enabled = false; + item_params_blank.value = LLSD::Integer(-1); + item_params_blank.columns.add(cell_params); + cell_params.enabled = true; + + for (U32 i = LLControlBindings::CONTROL_VIEW_ACTIONS; i < LLControlBindings::CONTROL_NUM_INDICES; i++) + { + switch (i) + { + case LLControlBindings::CONTROL_VIEW_ACTIONS: + { + // same as below, but without separator + LLScrollListItem::Params item_params; + item_params.value = LLSD::Integer(i); + + label = getString(tmp_typetostring[i]); + cell_params.column = "lst_action"; + cell_params.value = label; + //dummy cells + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl1"; + cell_params.value = ""; + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl2"; + cell_params.value = ""; + item_params.columns.add(cell_params); + LLUUID id; + LLGroupControlsListItem* item = new LLGroupControlsListItem(item_params, id); + pControlsTable->addRow(item, item_params, EAddPosition::ADD_BOTTOM); + break; + } + case LLControlBindings::CONTROL_INTERACTIONS: + case LLControlBindings::CONTROL_MOVEMENTS: + case LLControlBindings::CONTROL_MEDIACONTENT: + case LLControlBindings::CONTROL_RESERVED: + { + // insert blank + pControlsTable->addRow(item_params_blank, EAddPosition::ADD_BOTTOM); + // inster with icon + LLScrollListItem::Params item_params; + item_params.value = LLSD::Integer(i); + + label = getString(tmp_typetostring[i]); + cell_params.column = "lst_action"; + cell_params.value = label; + //dummy cells + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl1"; + cell_params.value = ""; + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl2"; + cell_params.value = ""; + item_params.columns.add(cell_params); + LLUUID id; + LLGroupControlsListItem* item = new LLGroupControlsListItem(item_params, id); + pControlsTable->addRow(item, item_params, EAddPosition::ADD_BOTTOM); + break; + } + default: + { + //default insert + LLScrollListItem::Params item_params; + item_params.value = LLSD::Integer(i); + + // todo oddset + cell_params.column = "lst_action"; + label = getString(tmp_typetostring[i]); + cell_params.value = label; + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl1"; + cell_params.value = gControlBindings.getPrimaryControl((LLControlBindings::EControlTypes)i).asString(); + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl2"; + cell_params.value = gControlBindings.getSecondaryControl((LLControlBindings::EControlTypes)i).asString(); + item_params.columns.add(cell_params); + + pControlsTable->addRow(item_params, EAddPosition::ADD_BOTTOM); + break; + } + } + } +} + +void LLPanelPreferenceControls::cancel() +{ +} + +void LLPanelPreferenceControls::saveSettings() +{ +} + +void LLPanelPreferenceControls::resetDirtyChilds() +{ +} + +bool LLPanelPreferenceControls::hasDirtyChilds() +{ + return false; +} + +void LLPanelPreferenceControls::onListCommit() +{ + LLScrollListItem* item = pControlsTable->getFirstSelected(); + if (item == NULL) + { + return; + } + + S32 control = item->getValue().asInteger(); + + if (!gControlBindings.canAssignControl((LLControlBindings::EControlTypes)control)) + { + return; + } + + // todo: add code to determine what cell was clicked, probably cells themself should be clickable + + LLVoiceSetKeyDialog* dialog = LLFloaterReg::showTypedInstance("voice_set_key", LLSD(), TRUE); + if (dialog) + { + dialog->setTmpParent(this); // will be remade from being voice later + } +} + +void LLPanelPreferenceControls::onSetKey(KEY key, MASK mask) +{ + LLScrollListItem* item = pControlsTable->getFirstSelected(); + if (item == NULL) + { + return; + } + + LLControlBindings::EControlTypes control = (LLControlBindings::EControlTypes)item->getValue().asInteger(); + + if (!gControlBindings.canAssignControl(control)) + { + return; + } + + gControlBindings.registerPrimaryControl(control, LLMouseHandler::CLICK_NONE, key, mask); + + // instead of populating, update single element + populateControlTable(); +} + +void LLPanelPreferenceControls::onSetMouse(LLMouseHandler::EClickType click, MASK mask) +{ + + LLScrollListItem* item = pControlsTable->getFirstSelected(); + if (item == NULL) + { + return; + } + + LLControlBindings::EControlTypes control = (LLControlBindings::EControlTypes)item->getValue().asInteger(); + + if (!gControlBindings.canAssignControl(control)) + { + return; + } + + gControlBindings.registerPrimaryControl(control, click, KEY_NONE, mask); + + // instead of populating, update single element + populateControlTable(); +} + LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key) : LLFloater(key) { diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 9190ef8ebd..74f55a7f91 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -293,6 +293,27 @@ private: LOG_CLASS(LLPanelPreferenceGraphics); }; +class LLPanelPreferenceControls : public LLPanelPreference +{ + LOG_CLASS(LLPanelPreferenceControls); +public: + BOOL postBuild(); + void populateControlTable(); + void cancel(); + void saveSettings(); + void resetDirtyChilds(); + + void onListCommit(); + void onSetKey(KEY key, MASK mask); + void onSetMouse(LLMouseHandler::EClickType click, MASK mask); + +protected: + bool hasDirtyChilds(); + +private: + LLScrollListCtrl* pControlsTable; +}; + class LLFloaterPreferenceGraphicsAdvanced : public LLFloater { public: diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 1dc1e65fe5..7e6f3ef7bc 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -996,7 +996,7 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible) } LLSpatialGroup* group = drawablep->getSpatialGroup(); - llassert(group != NULL); + //llassert(group != NULL); if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING)) { diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index e7a8a78c14..676f06bcb9 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -35,6 +35,7 @@ #include "llnotificationsutil.h" #include "llsdserialize.h" #include "llui.h" +#include "llkeybindings.h" #include "llkeyboard.h" #include "llagent.h" @@ -690,7 +691,7 @@ void LLVoiceClient::keyDown(KEY key, MASK mask) return; } - if (mPTTMouseButton == 0 && LLAgent::isActionAllowed("speak") && (key == mPTTKey)) + if (LLAgent::isActionAllowed("speak") && gControlBindings.canHandleKey(LLControlBindings::CONTROL_VOICE, key, mask)) { bool down = gKeyboard->getKeyDown(mPTTKey); if (down) @@ -702,7 +703,7 @@ void LLVoiceClient::keyDown(KEY key, MASK mask) } void LLVoiceClient::keyUp(KEY key, MASK mask) { - if (mPTTMouseButton == 0 && (key == mPTTKey)) + if (gControlBindings.canHandleKey(LLControlBindings::CONTROL_VOICE, key, mask)) { bool down = gKeyboard->getKeyDown(mPTTKey); if (!down) @@ -713,7 +714,7 @@ void LLVoiceClient::keyUp(KEY key, MASK mask) } void LLVoiceClient::updateMouseState(S32 click, MASK mask, bool down) { - if(mPTTMouseButton == click && LLAgent::isActionAllowed("speak")) + if(LLAgent::isActionAllowed("speak") && gControlBindings.canHandleMouse(LLControlBindings::CONTROL_VOICE, click, mask)) { inputUserControlState(down); } diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml index 0e62d50072..ee730dcb01 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences.xml @@ -169,6 +169,13 @@ https://accounts.secondlife.com/change_email/ layout="topleft" help_topic="preferences_uploads_tab" name="uploads" /> + diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml new file mode 100644 index 0000000000..a1a2fd0598 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml @@ -0,0 +1,196 @@ + + + + View Actions + + + About/Profile + + + Orbit + + + Pan + + + World Map + + + Zoom + + + Interactions + + + Build + + + Drag + + + Edit + + + Menu + + + Open + + + Touch + + + Wear + + + Move Actions + + + Move To + + + Sit/Stand + + + Teleport To + + + Move Forward + + + Move Backward + + + Left + + + Right + + + + Strafe left + + + Strafe right + + + Strafe right + + + Strafe right + + + Run + + + Toggle Run + + + Fly/Stop flying + + + Sound and Media + + + Play/Pause Parcel Media + + + Play/Stop All Media + + + Voice + + + Toggle Voice + + + Reserved Controls + + + + Select + + + Multi-Select + + + Add to Selection + + + + + + + + + + -- cgit v1.2.3 From c21812bf095de2defa4e61978b2659764c838abf Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Tue, 17 Sep 2019 21:36:59 +0300 Subject: SL-6109 Keyaboard support ready --- indra/llcommon/llkeybind.cpp | 180 ++++- indra/llcommon/llkeybind.h | 23 +- indra/llui/llscrolllistctrl.cpp | 4 + indra/llui/llscrolllistctrl.h | 4 +- indra/newview/CMakeLists.txt | 2 + indra/newview/llfloaterpreference.cpp | 680 ++++++++++-------- indra/newview/llfloaterpreference.h | 31 +- indra/newview/llkeyconflict.cpp | 789 +++++++++++++++++++++ indra/newview/llkeyconflict.h | 214 ++++++ indra/newview/llviewerkeyboard.cpp | 56 +- indra/newview/llviewerkeyboard.h | 6 +- indra/newview/llvoiceclient.cpp | 18 +- .../skins/default/xui/en/floater_select_key.xml | 40 +- .../default/xui/en/panel_preferences_controls.xml | 161 ++++- 14 files changed, 1798 insertions(+), 410 deletions(-) create mode 100644 indra/newview/llkeyconflict.cpp create mode 100644 indra/newview/llkeyconflict.h diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp index f227c0a1a5..765084bbf6 100644 --- a/indra/llcommon/llkeybind.cpp +++ b/indra/llcommon/llkeybind.cpp @@ -36,6 +36,11 @@ LLKeyData::LLKeyData() { } +LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, MASK mask) +: mMouse(mouse), mKey(key), mMask(mask) +{ +} + LLKeyData::LLKeyData(const LLSD &key_data) { mMouse = (EMouseClickType)key_data["mouse"].asInteger(); @@ -72,65 +77,100 @@ LLKeyData& LLKeyData::operator=(const LLKeyData& rhs) return *this; } +bool LLKeyData::operator==(const LLKeyData& rhs) +{ + if (mMouse != rhs.mMouse) return false; + if (mKey != rhs.mKey) return false; + if (mMask != rhs.mMask) return false; + return true; +} + +bool LLKeyData::operator!=(const LLKeyData& rhs) +{ + if (mMouse != rhs.mMouse) return true; + if (mKey != rhs.mKey) return true; + if (mMask != rhs.mMask) return true; + return false; +} + // LLKeyBind LLKeyBind::LLKeyBind(const LLSD &key_bind) { - if (key_bind.has("DataPrimary")) - { - mDataPrimary = LLKeyData(key_bind["DataPrimary"]); - } - if (key_bind.has("DataSecondary")) + if (key_bind.isArray()) { - mDataSecondary = LLKeyData(key_bind["DataSecondary"]); + for (LLSD::array_const_iterator data = key_bind.beginArray(), endLists = key_bind.endArray(); + data != endLists; + data++ + ) + { + mData.push_back(LLKeyData(*data)); + } } } bool LLKeyBind::operator==(const LLKeyBind& rhs) { - if (mDataPrimary.mMouse != rhs.mDataPrimary.mMouse) return false; - if (mDataPrimary.mKey != rhs.mDataPrimary.mKey) return false; - if (mDataPrimary.mMask != rhs.mDataPrimary.mMask) return false; - if (mDataSecondary.mMouse != rhs.mDataSecondary.mMouse) return false; - if (mDataSecondary.mKey != rhs.mDataSecondary.mKey) return false; - if (mDataSecondary.mMask != rhs.mDataSecondary.mMask) return false; + U32 size = mData.size(); + if (size != rhs.mData.size()) return false; + + for (U32 i = 0; i < size; i++) + { + if (mData[i] != rhs.mData[i]) return false; + } + return true; } -bool LLKeyBind::empty() +bool LLKeyBind::operator!=(const LLKeyBind& rhs) { - if (mDataPrimary.mMouse != CLICK_NONE) return false; - if (mDataPrimary.mKey != KEY_NONE) return false; - if (mDataPrimary.mMask != MASK_NONE) return false; - if (mDataSecondary.mMouse != CLICK_NONE) return false; - if (mDataSecondary.mKey != KEY_NONE) return false; - if (mDataSecondary.mMask != MASK_NONE) return false; + U32 size = mData.size(); + if (size != rhs.mData.size()) return true; + + for (U32 i = 0; i < size; i++) + { + if (mData[i] != rhs.mData[i]) return true; + } + return false; } -LLSD LLKeyBind::asLLSD() const +bool LLKeyBind::isEmpty() const { - LLSD data; - if (!mDataPrimary.isEmpty()) + for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++) { - data["DataPrimary"] = mDataPrimary.asLLSD(); + if (!iter->isEmpty()) return false; } - if (!mDataSecondary.isEmpty()) + return true; +} + +LLSD LLKeyBind::asLLSD() const +{ + LLSD data; + for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++) { - data["DataSecondary"] = mDataSecondary.asLLSD(); + if (!iter->isEmpty()) + { + data.append(iter->asLLSD()); + } } return data; } bool LLKeyBind::canHandle(EMouseClickType mouse, KEY key, MASK mask) const { - if (mDataPrimary.mKey == key && mDataPrimary.mMask == mask && mDataPrimary.mMouse == mouse) + if (mouse == CLICK_NONE && key == KEY_NONE) { - return true; + // assume placeholder + return false; } - if (mDataSecondary.mKey == key && mDataSecondary.mMask == mask && mDataSecondary.mMouse == mouse) + + for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++) { - return true; + if (iter->mKey == key && iter->mMask == mask && iter->mMouse == mouse) + { + return true; + } } return false; } @@ -145,3 +185,85 @@ bool LLKeyBind::canHandleMouse(EMouseClickType mouse, MASK mask) const return canHandle(mouse, KEY_NONE, mask); } +bool LLKeyBind::addKeyData(EMouseClickType mouse, KEY key, MASK mask) +{ + if (!canHandle(mouse, key, mask)) + { + mData.push_back(LLKeyData(mouse, key, mask)); + return true; + } + return false; +} + +bool LLKeyBind::addKeyData(const LLKeyData& data) +{ + if (!canHandle(data.mMouse, data.mKey, data.mMask)) + { + mData.push_back(data); + return true; + } + return false; +} + +void LLKeyBind::replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, U32 index) +{ + if (mouse != CLICK_NONE && key != KEY_NONE && mask != MASK_NONE) + { + for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++) + { + if (iter->mKey == key && iter->mMask == mask && iter->mMouse == mouse) + { + mData.erase(iter); + break; + } + } + } + if (mData.size() > index) + { + mData[index] = LLKeyData(mouse, key, mask); + } + else + { + mData.push_back(LLKeyData(mouse, key, mask)); + } +} + +void LLKeyBind::replaceKeyData(const LLKeyData& data, U32 index) +{ + for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++) + { + if (iter->mKey == data.mKey && iter->mMask == data.mMask && iter->mMouse == data.mMouse) + { + mData.erase(iter); + break; + } + } + if (mData.size() > index) + { + mData[index] = data; + } + else + { + mData.push_back(data); + } +} + +bool LLKeyBind::hasKeyData(U32 index) const +{ + return mData.size() > index; +} + +LLKeyData LLKeyBind::getKeyData(U32 index) const +{ + if (mData.size() > index) + { + return mData[index]; + } + return LLKeyData(); +} + +U32 LLKeyBind::getDataCount() +{ + return mData.size(); +} + diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h index 4fe622fb79..481949f275 100644 --- a/indra/llcommon/llkeybind.h +++ b/indra/llcommon/llkeybind.h @@ -34,12 +34,16 @@ class LL_COMMON_API LLKeyData { public: LLKeyData(); + LLKeyData(EMouseClickType mouse, KEY key, MASK mask); LLKeyData(const LLSD &key_data); LLSD asLLSD() const; bool isEmpty() const; + bool empty() const { return isEmpty(); }; void reset(); LLKeyData& operator=(const LLKeyData& rhs); + bool operator==(const LLKeyData& rhs); + bool operator!=(const LLKeyData& rhs); EMouseClickType mMouse; KEY mKey; @@ -54,7 +58,9 @@ public: LLKeyBind(const LLSD &key_bind); bool operator==(const LLKeyBind& rhs); - bool empty(); + bool operator!=(const LLKeyBind& rhs); + bool isEmpty() const; + bool empty() const { return isEmpty(); }; LLSD asLLSD() const; @@ -62,8 +68,19 @@ public: bool canHandleKey(KEY key, MASK mask) const; bool canHandleMouse(EMouseClickType mouse, MASK mask) const; - LLKeyData mDataPrimary; - LLKeyData mDataSecondary; + // these methods enshure there will be no repeats + bool addKeyData(EMouseClickType mouse, KEY key, MASK mask); + bool addKeyData(const LLKeyData& data); + void replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, U32 index); + void replaceKeyData(const LLKeyData& data, U32 index); + bool hasKeyData(U32 index) const; + void clear() { mData.clear(); }; + LLKeyData getKeyData(U32 index) const; + U32 getDataCount(); + +private: + typedef std::vector data_vector_t; + data_vector_t mData; }; diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 6c8fde580f..7e17dd7c8d 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -130,6 +130,7 @@ LLScrollListCtrl::Params::Params() search_column("search_column", 0), sort_column("sort_column", -1), sort_ascending("sort_ascending", true), + can_sort("can_sort", true), mouse_wheel_opaque("mouse_wheel_opaque", false), commit_on_keyboard_movement("commit_on_keyboard_movement", true), heading_height("heading_height"), @@ -165,6 +166,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) mSelectionChanged(false), mNeedsScroll(false), mCanSelect(true), + mCanSort(p.can_sort), mColumnsDirty(false), mMaxItemCount(INT_MAX), mBorderThickness( 2 ), @@ -2801,6 +2803,8 @@ void LLScrollListCtrl::onClickColumn(void *userdata) LLScrollListCtrl *parent = info->mParentCtrl; if (!parent) return; + if (!parent->mCanSort) return; + S32 column_index = info->mIndex; LLScrollListColumn* column = parent->mColumnsIndexed[info->mIndex]; diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index d7572d9fcf..249d9a6f15 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -114,7 +114,8 @@ public: // sort and search behavior Optional search_column, sort_column; - Optional sort_ascending; + Optional sort_ascending, + can_sort; // whether user is allowed to sort // colors Optional fg_unselected_color, @@ -457,6 +458,7 @@ private: bool mNeedsScroll; bool mMouseWheelOpaque; bool mCanSelect; + bool mCanSort; // Whether user is allowed to sort bool mDisplayColumnHeaders; bool mColumnsDirty; bool mColumnWidthsDirty; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 6089162190..bfbe1a0cfd 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -376,6 +376,7 @@ set(viewer_SOURCE_FILES llinventoryobserver.cpp llinventorypanel.cpp lljoystickbutton.cpp + llkeyconflict.cpp lllandmarkactions.cpp lllandmarklist.cpp lllistbrowser.cpp @@ -1004,6 +1005,7 @@ set(viewer_HEADER_FILES llinventoryobserver.h llinventorypanel.h lljoystickbutton.h + llkeyconflict.h lllandmarkactions.h lllandmarklist.h lllightconstants.h diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 182341685b..4a4f66db14 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -52,7 +52,6 @@ #include "llfavoritesbar.h" #include "llfloatersidepanelcontainer.h" #include "llfloaterimsession.h" -#include "llkeybindings.h" #include "llkeyboard.h" #include "llmodaldialog.h" #include "llnavigationbar.h" @@ -72,8 +71,9 @@ #include "lltrans.h" #include "llviewercontrol.h" #include "llviewercamera.h" -#include "llviewerwindow.h" +#include "llviewereventrecorder.h" #include "llviewermessage.h" +#include "llviewerwindow.h" #include "llviewershadermgr.h" #include "llviewerthrottle.h" #include "llvoavatarself.h" @@ -160,36 +160,49 @@ struct LabelTable : public LLInitParam::Block {} }; -class LLVoiceSetKeyDialog : public LLModalDialog +// Filters for LLSetKeyBindDialog +static const U32 ALLOW_MOUSE = 1; +static const U32 ALLOW_MASK_MOUSE = 2; +static const U32 ALLOW_KEYS = 4; //keyboard +static const U32 ALLOW_MASK_KEYS = 8; +static const U32 ALLOW_MASKS = 16; +static const U32 IGNORE_MASKS = 32; // For example W (aka Forward) should work regardless of SHIFT being pressed +static const U32 DEFAULT_KEY_FILTER = ALLOW_MOUSE | ALLOW_MASK_MOUSE | ALLOW_KEYS | ALLOW_MASK_KEYS; + +class LLSetKeyBindDialog : public LLModalDialog { public: - LLVoiceSetKeyDialog(const LLSD& key); - ~LLVoiceSetKeyDialog(); - + LLSetKeyBindDialog(const LLSD& key); + ~LLSetKeyBindDialog(); + /*virtual*/ BOOL postBuild(); - - void setParent(LLFloaterPreference* parent) { mParent = parent; } - void setTmpParent(LLPanelPreferenceControls* parent) { mTmpParent = parent; } // todo: voice key will be removed, class renamved, so it will have only one parent - + + void setParent(LLPanelPreferenceControls* parent, U32 key_mask = DEFAULT_KEY_FILTER); + BOOL handleKeyHere(KEY key, MASK mask); BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); static void onCancel(void* user_data); - + static void onBlank(void* user_data); + static void onDefault(void* user_data); + private: - LLFloaterPreference* mParent; - LLPanelPreferenceControls* mTmpParent;// todo: voice key will be removed, class renamved, so it will have only one parent + LLPanelPreferenceControls* mParent; + + U32 mKeyMask; }; -LLVoiceSetKeyDialog::LLVoiceSetKeyDialog(const LLSD& key) +LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key) : LLModalDialog(key), mParent(NULL), - mTmpParent(NULL) + mKeyMask(DEFAULT_KEY_FILTER) { } //virtual -BOOL LLVoiceSetKeyDialog::postBuild() +BOOL LLSetKeyBindDialog::postBuild() { + childSetAction("SetEmpty", onBlank, this); + childSetAction("Default", onDefault, this); childSetAction("Cancel", onCancel, this); getChild("Cancel")->setFocus(TRUE); @@ -198,47 +211,85 @@ BOOL LLVoiceSetKeyDialog::postBuild() return TRUE; } -LLVoiceSetKeyDialog::~LLVoiceSetKeyDialog() +void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_mask) +{ + mParent = parent; + mKeyMask = key_mask; + + LLTextBase *text_ctrl = getChild("descritption"); + + std::string input; + if ((key_mask & ALLOW_MOUSE) != 0) + { + input = getString("mouse"); + } + if ((key_mask & ALLOW_KEYS) != 0) + { + if (!input.empty()) + { + input += ", "; + } + input += getString("keyboard"); + } + text_ctrl->setTextArg("[INPUT]", input); +} + +LLSetKeyBindDialog::~LLSetKeyBindDialog() { } -BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask) +BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask) { BOOL result = TRUE; - if (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT || key == KEY_NONE) + if ((key == 'Q' && mask == MASK_CONTROL) + || key == KEY_ESCAPE) + { + closeFloater(); + return true; + } + + // forbidden keys + if (key == KEY_NONE + || key == KEY_RETURN + || key == KEY_DELETE + || key == KEY_BACKSPACE) { - // temp return false; } - - // todo, same for escape - if (key == 'Q' && mask == MASK_CONTROL) - { - result = FALSE; - if (mTmpParent) - { - mTmpParent->onSetKey(KEY_NONE, MASK_NONE); - } + + if ((mKeyMask & ALLOW_MASKS) == 0 + && (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT)) + { + // mask by themself are not allowed + return false; + } + else if ((mKeyMask & ALLOW_KEYS) == 0) + { + // basic keys not allowed + return false; + } + else if ((mKeyMask & ALLOW_MASK_KEYS) == 0 && mask != 0) + { + // masked keys not allowed + return false; } + else if (mParent) { - mParent->setKey(key); - } - else if (mTmpParent) - { - mTmpParent->onSetKey(key, mask); + mParent->onSetKeyBind(CLICK_NONE, key, mask); } closeFloater(); return result; } -BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) +BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL result = FALSE; if (clicktype == CLICK_LEFT) { + // try handling buttons first if (down) { result = LLView::handleMouseDown(x, y, mask); @@ -248,30 +299,21 @@ BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseCli result = LLView::handleMouseUp(x, y, mask); } } - if (clicktype == LLMouseHandler::CLICK_LEFT) - { - result = LLView::handleDoubleClick(x, y, mask); - } - if (result) - { - return TRUE; - } - if (down && clicktype != LLMouseHandler::CLICK_RIGHT) //tmp - //&& (clicktype == LLMouseHandler::CLICK_MIDDLE || clicktype == LLMouseHandler::CLICK_BUTTON4 || clicktype == LLMouseHandler::CLICK_BUTTON5) - //&& mask == 0) + + if (!result + && ((mKeyMask & ALLOW_MOUSE) != 0) + && (clicktype != CLICK_RIGHT || mask != 0) // reassigning menu button is not supported + && ((mKeyMask & ALLOW_MASK_MOUSE) != 0 || mask == 0)) { if (mParent) { - mParent->setMouse(clicktype); - } - else if (mTmpParent) - { - mTmpParent->onSetMouse(clicktype, mask); + mParent->onSetKeyBind(clicktype, KEY_NONE, mask); } result = TRUE; closeFloater(); } - else + + if (!result) { result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); } @@ -280,17 +322,36 @@ BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseCli } //static -void LLVoiceSetKeyDialog::onCancel(void* user_data) +void LLSetKeyBindDialog::onCancel(void* user_data) { - LLVoiceSetKeyDialog* self = (LLVoiceSetKeyDialog*)user_data; - // tmp needs 'no key' button - if (self->mTmpParent) - { - self->mTmpParent->onSetKey(KEY_NONE, MASK_NONE); - } + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; self->closeFloater(); } +//static +void LLSetKeyBindDialog::onBlank(void* user_data) +{ + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; + // tmp needs 'no key' button + if (self->mParent) + { + self->mParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE); + } + self->closeFloater(); +} + +//static +void LLSetKeyBindDialog::onDefault(void* user_data) +{ + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; + // tmp needs 'no key' button + if (self->mParent) + { + self->mParent->onDefaultKeyBind(); + } + self->closeFloater(); +} + // global functions @@ -370,37 +431,6 @@ void handleAppearanceCameraMovementChanged(const LLSD& newvalue) } } -/*bool callback_skip_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option && floater ) - { - if ( floater ) - { - floater->setAllIgnored(); - // LLFirstUse::disableFirstUse(); - floater->buildPopupLists(); - } - } - return false; -} - -bool callback_reset_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if ( 0 == option && floater ) - { - if ( floater ) - { - floater->resetAllIgnored(); - //LLFirstUse::resetFirstUse(); - floater->buildPopupLists(); - } - } - return false; -} -*/ - void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator) { numerator = 0; @@ -435,7 +465,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) static bool registered_dialog = false; if (!registered_dialog) { - LLFloaterReg::add("voice_set_key", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("keybind_dialog", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); registered_dialog = true; } @@ -1754,53 +1784,6 @@ void LLFloaterPreference::onChangeQuality(const LLSD& data) void LLFloaterPreference::onClickSetKey() { - LLVoiceSetKeyDialog* dialog = LLFloaterReg::showTypedInstance("voice_set_key", LLSD(), TRUE); - if (dialog) - { - dialog->setParent(this); - } -} - -void LLFloaterPreference::setKey(KEY key) -{ - getChild("modifier_combo")->setValue(LLKeyboard::stringFromKey(key)); - // update the control right away since we no longer wait for apply - getChild("modifier_combo")->onCommit(); -} - -void LLFloaterPreference::setMouse(EMouseClickType click) -{ - std::string bt_name; - std::string ctrl_value; - switch (click) - { - case CLICK_MIDDLE: - bt_name = "middle_mouse"; - ctrl_value = MIDDLE_MOUSE_CV; - break; - case CLICK_BUTTON4: - bt_name = "button4_mouse"; - ctrl_value = MOUSE_BUTTON_4_CV; - break; - case CLICK_BUTTON5: - bt_name = "button5_mouse"; - ctrl_value = MOUSE_BUTTON_5_CV; - break; - default: - break; - } - - if (!ctrl_value.empty()) - { - LLUICtrl* p2t_line_editor = getChild("modifier_combo"); - // We are using text control names for readability and compatibility with voice - p2t_line_editor->setControlValue(ctrl_value); - LLPanel* advanced_preferences = dynamic_cast(p2t_line_editor->getParent()); - if (advanced_preferences) - { - p2t_line_editor->setValue(advanced_preferences->getString(bt_name)); - } - } } void LLFloaterPreference::onClickSetMiddleMouse() @@ -1825,18 +1808,6 @@ void LLFloaterPreference::onClickSetSounds() getChild("gesture_audio_play_btn")->setEnabled(!gSavedSettings.getBOOL("MuteSounds")); } -/* -void LLFloaterPreference::onClickSkipDialogs() -{ - LLNotificationsUtil::add("SkipShowNextTimeDialogs", LLSD(), LLSD(), boost::bind(&callback_skip_dialogs, _1, _2, this)); -} - -void LLFloaterPreference::onClickResetDialogs() -{ - LLNotificationsUtil::add("ResetShowNextTimeDialogs", LLSD(), LLSD(), boost::bind(&callback_reset_dialogs, _1, _2, this)); -} - */ - void LLFloaterPreference::onClickEnablePopup() { LLScrollListCtrl& disabled_popups = getChildRef("disabled_popups"); @@ -2845,7 +2816,7 @@ void LLPanelPreferenceGraphics::setPresetText() } } - if (hasDirtyChilds() && !preset_graphic_active.empty()) + if (hasDirtyChilds() && !preset_graphic_active.empty()) { gSavedSettings.setString("PresetGraphicActive", ""); preset_graphic_active.clear(); @@ -2965,98 +2936,124 @@ void LLPanelPreferenceGraphics::setHardwareDefaults() resetDirtyChilds(); } +//------------------------LLPanelPreferenceControls-------------------------------- +static LLPanelInjector t_pref_contrls("panel_preference_controls"); -//-------------------For LLPanelPreferenceControls' list--------------------------- -class LLGroupControlsListItem : public LLScrollListItem, public LLHandleProvider +LLPanelPreferenceControls::LLPanelPreferenceControls() + :LLPanelPreference(), + mEditingIndex(-1), + mEditingColumn(-1), + mEditingMode(0), + mShowKeyDialog(false) { -public: - LLGroupControlsListItem(const LLScrollListItem::Params& p) - : LLScrollListItem(p) - { - } - - LLGroupControlsListItem(const LLScrollListItem::Params& p, const LLUUID& icon_id) - : LLScrollListItem(p), mIconId(icon_id) - { - } - - void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding) - { - // todo: insert image and adjust rect - LLScrollListItem::draw(rect, fg_color, bg_color, highlight_color, column_padding); - } -private: - LLUUID mIconId; -}; - -static const std::string tmp_typetostring[LLControlBindings::CONTROL_NUM_INDICES] = { - "control_view_actions", - "control_about", - "control_orbit", - "control_pan", - "control_world_map", - "control_zoom", - "control_interactions", - "control_build", - "control_drag", - "control_edit", - "control_menu", - "control_open", - "control_touch", - "control_wear", - "control_movements", - "control_moveto", - "control_sit", - "control_teleportto", - "control_forward", - "control_backward", - "control_left", - "control_right", - "control_lstrafe", - "control_rstrafe", - "control_jump", - "control_down", - "control_run", - "control_toggle_run", - "control_fly", - "control_mediacontent", - "control_parcel", - "control_media", - "control_voice", - "control_toggle_voice", - "control_reserved", - "control_menu", - "control_reserved_select", - "control_shift_select", - "control_cntrl_select" -}; +} -//------------------------LLPanelPreferenceControls-------------------------------- -static LLPanelInjector t_pref_contrls("panel_preference_controls"); +LLPanelPreferenceControls::~LLPanelPreferenceControls() +{ +} BOOL LLPanelPreferenceControls::postBuild() { - //todo: on open instead of on the go //todo: add pitch/yaw? - //todo: Scroll? //todo: should be auto-expandable with menu items and should pull names from menu when possible // populate list of controls pControlsTable = getChild("controls_list"); - populateControlTable(); + pKeyModeBox = getChild("key_mode"); pControlsTable->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onListCommit, this)); + pKeyModeBox->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onModeCommit, this)); + getChild("restore_defaults")->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onRestoreDefaults, this)); return TRUE; } +// Something of a workaround: cells don't handle clicks, so we catch a click, then process it on hover. +BOOL LLPanelPreferenceControls::handleHover(S32 x, S32 y, MASK mask) +{ + if (mShowKeyDialog) + { + if (mEditingIndex > 0 && mConflictHandler[mEditingMode].canAssignControl((LLKeyConflictHandler::EControlTypes)mEditingIndex)) + { + mEditingColumn = pControlsTable->getColumnIndexFromOffset(x); + + if (mEditingColumn >0) + { + LLSetKeyBindDialog* dialog = LLFloaterReg::showTypedInstance("keybind_dialog", LLSD(), TRUE); + if (dialog) + { + if (mConflictHandler[mEditingMode].getLoadedMode() == LLKeyConflictHandler::MODE_GENERAL) + { + dialog->setParent(this, DEFAULT_KEY_FILTER); + } + else + { + dialog->setParent(this, ALLOW_KEYS | ALLOW_MASK_KEYS); + } + } + } + } + mShowKeyDialog = false; + } + return LLPanelPreference::handleHover(x, y, mask); +} + +void LLPanelPreferenceControls::addGroupRow(const std::string &icon, S32 index) +{ + LLScrollListItem::Params item_params; + item_params.value = LLSD::Integer(-1); + + LLScrollListCell::Params icon_cell_params; + icon_cell_params.font = LLFontGL::getFontSansSerif(); + icon_cell_params.font_halign = LLFontGL::LEFT; + icon_cell_params.type = "icontext"; + + LLScrollListCell::Params cell_params; + // init basic cell params + cell_params.font = LLFontGL::getFontSansSerif(); + cell_params.font_halign = LLFontGL::LEFT; + + std::string control_name = LLKeyConflictHandler::getControlName((LLKeyConflictHandler::EControlTypes)index); + std::string label; + if (hasString(control_name)) + { + label = getString(control_name); + } + else + { + label = control_name; + } + icon_cell_params.column = "lst_action"; + icon_cell_params.text = label; + icon_cell_params.value = icon; + item_params.columns.add(icon_cell_params); + //dummy cells + cell_params.column = "lst_ctrl1"; + cell_params.value = ""; + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl2"; + cell_params.value = ""; + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl3"; + cell_params.value = ""; + item_params.columns.add(cell_params); + pControlsTable->addRow(item_params, EAddPosition::ADD_BOTTOM); +} + +void LLPanelPreferenceControls::regenerateControls() +{ + mEditingMode = pKeyModeBox->getValue().asInteger(); + mConflictHandler[mEditingMode].loadFromSettings((LLKeyConflictHandler::EModes)mEditingMode); + populateControlTable(); +} + void LLPanelPreferenceControls::populateControlTable() { pControlsTable->clearRows(); // todo: subsections need sorting? - std::string label; + std::string label, control_name; LLScrollListCell::Params cell_params; // init basic cell params cell_params.font = LLFontGL::getFontSansSerif(); @@ -3064,81 +3061,71 @@ void LLPanelPreferenceControls::populateControlTable() cell_params.column = ""; cell_params.value = label; - LLScrollListItem::Params item_params_blank; - cell_params.enabled = false; - item_params_blank.value = LLSD::Integer(-1); - item_params_blank.columns.add(cell_params); - cell_params.enabled = true; - - for (U32 i = LLControlBindings::CONTROL_VIEW_ACTIONS; i < LLControlBindings::CONTROL_NUM_INDICES; i++) + S32 start = mEditingMode == LLKeyConflictHandler::MODE_GENERAL ? LLKeyConflictHandler::CONTROL_VIEW_ACTIONS : LLKeyConflictHandler::CONTROL_MOVEMENTS; + S32 end = mEditingMode == LLKeyConflictHandler::MODE_GENERAL ? LLKeyConflictHandler::CONTROL_NUM_INDICES : LLKeyConflictHandler::CONTROL_RESERVED; + for (S32 i = start; i < end; i++) { - switch (i) + LLKeyConflictHandler::EControlTypes type = (LLKeyConflictHandler::EControlTypes)i; + switch (type) { - case LLControlBindings::CONTROL_VIEW_ACTIONS: - { - // same as below, but without separator - LLScrollListItem::Params item_params; - item_params.value = LLSD::Integer(i); - - label = getString(tmp_typetostring[i]); - cell_params.column = "lst_action"; - cell_params.value = label; - //dummy cells - item_params.columns.add(cell_params); - cell_params.column = "lst_ctrl1"; - cell_params.value = ""; - item_params.columns.add(cell_params); - cell_params.column = "lst_ctrl2"; - cell_params.value = ""; - item_params.columns.add(cell_params); - LLUUID id; - LLGroupControlsListItem* item = new LLGroupControlsListItem(item_params, id); - pControlsTable->addRow(item, item_params, EAddPosition::ADD_BOTTOM); - break; - } - case LLControlBindings::CONTROL_INTERACTIONS: - case LLControlBindings::CONTROL_MOVEMENTS: - case LLControlBindings::CONTROL_MEDIACONTENT: - case LLControlBindings::CONTROL_RESERVED: - { - // insert blank - pControlsTable->addRow(item_params_blank, EAddPosition::ADD_BOTTOM); - // inster with icon - LLScrollListItem::Params item_params; - item_params.value = LLSD::Integer(i); - - label = getString(tmp_typetostring[i]); - cell_params.column = "lst_action"; - cell_params.value = label; - //dummy cells - item_params.columns.add(cell_params); - cell_params.column = "lst_ctrl1"; - cell_params.value = ""; - item_params.columns.add(cell_params); - cell_params.column = "lst_ctrl2"; - cell_params.value = ""; - item_params.columns.add(cell_params); - LLUUID id; - LLGroupControlsListItem* item = new LLGroupControlsListItem(item_params, id); - pControlsTable->addRow(item, item_params, EAddPosition::ADD_BOTTOM); - break; - } - default: + case LLKeyConflictHandler::CONTROL_VIEW_ACTIONS: + addSeparator(); + addGroupRow("Search_Icon", i); + break; + case LLKeyConflictHandler::CONTROL_INTERACTIONS: + addSeparator(); + addGroupRow("Command_Gestures_Icon", i); + break; + case LLKeyConflictHandler::CONTROL_MOVEMENTS: + addSeparator(); + addGroupRow("Move_Walk_Off", i); + break; + case LLKeyConflictHandler::CONTROL_MEDIACONTENT: + addSeparator(); + addGroupRow("Audio_Press", i); + break; + case LLKeyConflictHandler::CONTROL_CAMERA: + addSeparator(); + addGroupRow("Cam_FreeCam_Off", i); + break; + case LLKeyConflictHandler::CONTROL_EDIT_TITLE: + addSeparator(); + addGroupRow("Tool_Dozer", i); + break; + case LLKeyConflictHandler::CONTROL_RESERVED: + addSeparator(); + addGroupRow("Info_Small", i); + break; + default: { //default insert LLScrollListItem::Params item_params; item_params.value = LLSD::Integer(i); - // todo oddset cell_params.column = "lst_action"; - label = getString(tmp_typetostring[i]); + bool enabled = mConflictHandler[mEditingMode].canAssignControl(type); + control_name = LLKeyConflictHandler::getControlName(type); + if (hasString(control_name)) + { + label = getString(control_name); + } + else + { + label = control_name; + } cell_params.value = label; item_params.columns.add(cell_params); cell_params.column = "lst_ctrl1"; - cell_params.value = gControlBindings.getPrimaryControl((LLControlBindings::EControlTypes)i).asString(); + cell_params.value = mConflictHandler[mEditingMode].getControlString(type, 0); + cell_params.enabled = enabled; item_params.columns.add(cell_params); cell_params.column = "lst_ctrl2"; - cell_params.value = gControlBindings.getSecondaryControl((LLControlBindings::EControlTypes)i).asString(); + cell_params.value = mConflictHandler[mEditingMode].getControlString(type, 1); + cell_params.enabled = enabled; + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl3"; + cell_params.value = mConflictHandler[mEditingMode].getControlString(type, 2); + cell_params.enabled = enabled; item_params.columns.add(cell_params); pControlsTable->addRow(item_params, EAddPosition::ADD_BOTTOM); @@ -3146,23 +3133,64 @@ void LLPanelPreferenceControls::populateControlTable() } } } + + //temp + if (mEditingMode == LLKeyConflictHandler::MODE_GENERAL) + pControlsTable->setEnabled(false); } -void LLPanelPreferenceControls::cancel() +// Just a workaround to not care about first separator before headers (we can start from random header) +void LLPanelPreferenceControls::addSeparator() { + if (pControlsTable->getItemCount() > 0) + { + pControlsTable->addSeparator(EAddPosition::ADD_BOTTOM); + } } -void LLPanelPreferenceControls::saveSettings() +void LLPanelPreferenceControls::apply() { + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i) + { + if (mConflictHandler[i].hasUnsavedChanges()) + { + mConflictHandler[i].saveToSettings(); + } + } } -void LLPanelPreferenceControls::resetDirtyChilds() +void LLPanelPreferenceControls::cancel() { + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i) + { + if (mConflictHandler[i].hasUnsavedChanges()) + { + mConflictHandler[i].clear(); + } + } + pControlsTable->clear(); } -bool LLPanelPreferenceControls::hasDirtyChilds() +void LLPanelPreferenceControls::saveSettings() { - return false; + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i) + { + if (mConflictHandler[i].hasUnsavedChanges()) + { + mConflictHandler[i].saveToSettings(); + } + } + + S32 mode = pKeyModeBox->getValue().asInteger(); + if (mConflictHandler[mode].empty()) + { + regenerateControls(); + } +} + +void LLPanelPreferenceControls::resetDirtyChilds() +{ + regenerateControls(); } void LLPanelPreferenceControls::onListCommit() @@ -3175,61 +3203,85 @@ void LLPanelPreferenceControls::onListCommit() S32 control = item->getValue().asInteger(); - if (!gControlBindings.canAssignControl((LLControlBindings::EControlTypes)control)) + if (control <= 0) { return; } - - // todo: add code to determine what cell was clicked, probably cells themself should be clickable - LLVoiceSetKeyDialog* dialog = LLFloaterReg::showTypedInstance("voice_set_key", LLSD(), TRUE); - if (dialog) + if (!mConflictHandler[mEditingMode].canAssignControl((LLKeyConflictHandler::EControlTypes)control)) { - dialog->setTmpParent(this); // will be remade from being voice later + return; } + + // List does not tell us what cell was clicked, so we have to figure it out manually, but + // fresh mouse coordinates are not yet accessible during onCommit() and there are other issues, + // so we cheat: remember item user clicked at, trigger 'key dialog' on hover that comes next, + // use coordinates from hover to calculate cell + mEditingIndex = control; + mShowKeyDialog = true; } -void LLPanelPreferenceControls::onSetKey(KEY key, MASK mask) +void LLPanelPreferenceControls::onModeCommit() { - LLScrollListItem* item = pControlsTable->getFirstSelected(); - if (item == NULL) + regenerateControls(); +} + +void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask) +{ + LLKeyConflictHandler::EControlTypes control = (LLKeyConflictHandler::EControlTypes)mEditingIndex; + + if (!mConflictHandler[mEditingMode].canAssignControl(control)) { return; } - LLControlBindings::EControlTypes control = (LLControlBindings::EControlTypes)item->getValue().asInteger(); - - if (!gControlBindings.canAssignControl(control)) + pControlsTable->deselectAllItems(); + pControlsTable->selectByValue(mEditingIndex); + LLScrollListItem *item = pControlsTable->getFirstSelected(); + if (item && mEditingColumn > 0) { - return; + + mConflictHandler[mEditingMode].registerControl(control, mEditingColumn - 1, click, key, mask); + + LLScrollListCell *cell = item->getColumn(1); + cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 0)); + cell = item->getColumn(2); + cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 1)); + cell = item->getColumn(3); + cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 2)); } - gControlBindings.registerPrimaryControl(control, LLMouseHandler::CLICK_NONE, key, mask); + populateControlTable(); +} - // instead of populating, update single element +void LLPanelPreferenceControls::onRestoreDefaults() +{ + mConflictHandler[mEditingMode].resetToDefaults(); populateControlTable(); } -void LLPanelPreferenceControls::onSetMouse(LLMouseHandler::EClickType click, MASK mask) +void LLPanelPreferenceControls::onDefaultKeyBind() { + LLKeyConflictHandler::EControlTypes control = (LLKeyConflictHandler::EControlTypes)mEditingIndex; - LLScrollListItem* item = pControlsTable->getFirstSelected(); - if (item == NULL) + if (!mConflictHandler[mEditingMode].canAssignControl(control)) { return; } - LLControlBindings::EControlTypes control = (LLControlBindings::EControlTypes)item->getValue().asInteger(); - - if (!gControlBindings.canAssignControl(control)) + pControlsTable->deselectAllItems(); + pControlsTable->selectByValue(mEditingIndex); + LLScrollListItem *item = pControlsTable->getFirstSelected(); + if (item) { - return; - } + LLScrollListCell *cell = item->getColumn(mEditingColumn); - gControlBindings.registerPrimaryControl(control, click, KEY_NONE, mask); - - // instead of populating, update single element - populateControlTable(); + if (mEditingColumn > 0) + { + mConflictHandler[mEditingMode].resetToDefault(control, mEditingColumn - 1); + cell->setValue(mConflictHandler[mEditingMode].getControlString(control, mEditingColumn - 1)); + } + } } LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key) diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 74f55a7f91..bce84387ab 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -37,12 +37,14 @@ #include "llavatarpropertiesprocessor.h" #include "llconversationlog.h" #include "llsearcheditor.h" +#include "llkeyconflict.h" class LLConversationLogObserver; class LLPanelPreference; class LLPanelLCD; class LLPanelDebug; class LLMessageSystem; +class LLComboBox; class LLScrollListCtrl; class LLSliderCtrl; class LLSD; @@ -147,8 +149,6 @@ public: void onClickSkin(LLUICtrl* ctrl,const LLSD& userdata); void onSelectSkin(); void onClickSetKey(); - void setKey(KEY key); - void setMouse(EMouseClickType click); void onClickSetMiddleMouse(); void onClickSetSounds(); void onClickEnablePopup(); @@ -297,21 +297,36 @@ class LLPanelPreferenceControls : public LLPanelPreference { LOG_CLASS(LLPanelPreferenceControls); public: + LLPanelPreferenceControls(); + ~LLPanelPreferenceControls(); + BOOL postBuild(); - void populateControlTable(); + BOOL handleHover(S32 x, S32 y, MASK mask); + + void apply(); void cancel(); void saveSettings(); void resetDirtyChilds(); void onListCommit(); - void onSetKey(KEY key, MASK mask); - void onSetMouse(LLMouseHandler::EClickType click, MASK mask); - -protected: - bool hasDirtyChilds(); + void onModeCommit(); + void onSetKeyBind(EMouseClickType click, KEY key, MASK mask); + void onRestoreDefaults(); + void onDefaultKeyBind(); private: + void addGroupRow(const std::string &icon, S32 index); + void regenerateControls(); + void populateControlTable(); + void addSeparator(); + LLScrollListCtrl* pControlsTable; + LLComboBox *pKeyModeBox; + LLKeyConflictHandler mConflictHandler[LLKeyConflictHandler::MODE_COUNT]; + S32 mEditingIndex; + S32 mEditingColumn; + S32 mEditingMode; + bool mShowKeyDialog; }; class LLFloaterPreferenceGraphicsAdvanced : public LLFloater diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp new file mode 100644 index 0000000000..0f0129bf68 --- /dev/null +++ b/indra/newview/llkeyconflict.cpp @@ -0,0 +1,789 @@ +/** + * @file llkeyconflict.cpp + * @brief + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2019, 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$ + */ + +/* + * App-wide preferences. Note that these are not per-user, + * because we need to load many preferences before we have + * a login name. + */ + +#include "llviewerprecompiledheaders.h" + +#include "llkeyconflict.h" + +#include "llinitparam.h" +#include "llkeyboard.h" +#include "llviewercontrol.h" +#include "llviewerkeyboard.h" +#include "llxuiparser.h" +//#include "llstring.h" + +static const std::string typetostring[LLKeyConflictHandler::CONTROL_NUM_INDICES] = { + "control_view_actions", + "control_about", + "control_orbit", + "control_pan", + "control_world_map", + "control_zoom", + "control_interactions", + "control_build", + //"control_drag", + "control_edit", + //"control_menu", + "control_open", + "control_touch", + "control_wear", + "control_movements", + "control_moveto", + "control_sit", + "control_teleportto", + "push_forward", + "push_backward", + "turn_left", + "turn_right", + "slide_left", + "slide_right", + "jump", + "push_down", + //"control_run", + "control_toggle_run", + "toggle_fly", + "stop_moving", + "control_camera", + "look_up", + "look_down", + "move_forward", + "move_backward", + "move_forward_fast", + "move_backward_fast", + "move_forward_sitting", + "move_backward_sitting", + "spin_over", + "spin_under", + "spin_over_sitting", + "spin_under_sitting", + "pan_up", + "pan_down", + "pan_left", + "pan_right", + "pan_in", + "pan_out", + "spin_around_ccw", + "spin_around_cw", + "spin_around_ccw_sitting", + "spin_around_cw_sitting", + "control_edit_title", + "edit_avatar_spin_ccw", + "edit_avatar_spin_cw", + "edit_avatar_spin_over", + "edit_avatar_spin_under", + "edit_avatar_move_forward", + "edit_avatar_move_backward", + "control_mediacontent", + "control_parcel", + "control_media", + "control_voice", + "control_toggle_voice", + "start_chat", + "start_gesture", + "control_reserved", + "control_delete", + "control_menu", + "control_reserved_select", + "control_shift_select", + "control_cntrl_select" +}; + +// note, a solution is needed that will keep this up to date with llviewerkeyboard +typedef std::map control_enum_t; +static const control_enum_t command_to_key = +{ + { "jump", LLKeyConflictHandler::CONTROL_JUMP }, + { "push_down", LLKeyConflictHandler::CONTROL_DOWN }, + { "push_forward", LLKeyConflictHandler::CONTROL_FORWARD }, + { "push_backward", LLKeyConflictHandler::CONTROL_BACKWARD }, + { "look_up", LLKeyConflictHandler::CONTROL_LOOK_UP }, + { "look_down", LLKeyConflictHandler::CONTROL_LOOK_DOWN }, + { "toggle_fly", LLKeyConflictHandler::CONTROL_TOGGLE_FLY }, + { "turn_left", LLKeyConflictHandler::CONTROL_LEFT }, + { "turn_right", LLKeyConflictHandler::CONTROL_RIGHT }, + { "slide_left", LLKeyConflictHandler::CONTROL_LSTRAFE }, + { "slide_right", LLKeyConflictHandler::CONTROL_RSTRAFE }, + { "spin_around_ccw", LLKeyConflictHandler::CONTROL_CAMERA_SPIN_CCW }, // todo, no idea what these spins are + { "spin_around_cw", LLKeyConflictHandler::CONTROL_CAMERA_SPIN_CW }, + { "spin_around_ccw_sitting", LLKeyConflictHandler::CONTROL_CAMERA_SPIN_CCW_SITTING }, + { "spin_around_cw_sitting", LLKeyConflictHandler::CONTROL_CAMERA_SPIN_CCW_SITTING }, + { "spin_over", LLKeyConflictHandler::CONTROL_CAMERA_SOVER }, + { "spin_under", LLKeyConflictHandler::CONTROL_CAMERA_SUNDER }, + { "spin_over_sitting", LLKeyConflictHandler::CONTROL_CAMERA_SOVER_SITTING }, + { "spin_under_sitting", LLKeyConflictHandler::CONTROL_CAMERA_SUNDER_SITTING }, + { "move_forward", LLKeyConflictHandler::CONTROL_CAMERA_FORWARD }, + { "move_backward", LLKeyConflictHandler::CONTROL_CAMERA_BACKWARD }, + { "move_forward_sitting", LLKeyConflictHandler::CONTROL_CAMERA_FSITTING }, + { "move_backward_sitting", LLKeyConflictHandler::CONTROL_CAMERA_BSITTING }, + { "pan_up", LLKeyConflictHandler::CONTROL_CAMERA_PANUP }, + { "pan_down", LLKeyConflictHandler::CONTROL_CAMERA_PANDOWN }, + { "pan_left", LLKeyConflictHandler::CONTROL_CAMERA_PANLEFT }, + { "pan_right", LLKeyConflictHandler::CONTROL_CAMERA_PANRIGHT }, + { "pan_in", LLKeyConflictHandler::CONTROL_CAMERA_PANIN }, + { "pan_out", LLKeyConflictHandler::CONTROL_CAMERA_PANOUT }, + { "move_forward_fast", LLKeyConflictHandler::CONTROL_CAMERA_FFORWARD }, + { "move_backward_fast", LLKeyConflictHandler::CONTROL_CAMERA_FBACKWARD }, + { "edit_avatar_spin_ccw", LLKeyConflictHandler::CONTROL_EDIT_AV_SPIN_CCW }, + { "edit_avatar_spin_cw", LLKeyConflictHandler::CONTROL_EDIT_AV_SPIN_CW }, + { "edit_avatar_spin_over", LLKeyConflictHandler::CONTROL_EDIT_AV_SPIN_OVER }, + { "edit_avatar_spin_under", LLKeyConflictHandler::CONTROL_EDIT_AV_SPIN_UNDER }, + { "edit_avatar_move_forward", LLKeyConflictHandler::CONTROL_EDIT_AV_MV_FORWARD }, + { "edit_avatar_move_backward", LLKeyConflictHandler::CONTROL_EDIT_AV_MV_BACKWARD }, + { "stop_moving", LLKeyConflictHandler::CONTROL_STOP }, + { "start_chat", LLKeyConflictHandler::CONTROL_START_CHAT }, + { "start_gesture", LLKeyConflictHandler::CONTROL_START_GESTURE }, +}; + + +// LLKeyboard::stringFromMask is meant for UI and is OS dependent, +// so this class uses it's own version +std::string string_from_mask(MASK mask) +{ + std::string res; + if ((mask & MASK_CONTROL) != 0) + { + res = "CTL"; + } + if ((mask & MASK_ALT) != 0) + { + if (!res.empty()) res += "_"; + res += "ALT"; + } + if ((mask & MASK_SHIFT) != 0) + { + if (!res.empty()) res += "_"; + res += "SHIFT"; + } + + if (mask == MASK_NONE) + { + res = "NONE"; + } + return res; +} + +// LLKeyConflictHandler + +LLKeyConflictHandler::LLKeyConflictHandler() + : mHasUnsavedChanges(false) +{ + // todo: assign conflic priorities + // todo: load from keys.xml? + + // Thise controls are meant to cause conflicts when user tries to assign same control somewhere else + /*registerTemporaryControl(CONTROL_RESERVED_MENU, CLICK_RIGHT, KEY_NONE, MASK_NONE, 0); + registerTemporaryControl(CONTROL_SHIFT_SELECT, CLICK_LEFT, KEY_NONE, MASK_SHIFT, 0); + registerTemporaryControl(CONTROL_CNTRL_SELECT, CLICK_LEFT, KEY_NONE, MASK_CONTROL, 0); + registerTemporaryControl(CONTROL_DELETE, CLICK_NONE, KEY_DELETE, MASK_NONE, 0); + + loadFromSettings();*/ +} + +LLKeyConflictHandler::LLKeyConflictHandler(EModes mode) + : mHasUnsavedChanges(false), + mLoadedMode(mode) +{ + loadFromSettings(mode); +} + +bool LLKeyConflictHandler::canHandleControl(LLKeyConflictHandler::EControlTypes control_type, EMouseClickType mouse_ind, KEY key, MASK mask) +{ + return mControlsMap[control_type].canHandle(mouse_ind, key, mask); +} + +bool LLKeyConflictHandler::canHandleKey(EControlTypes control_type, KEY key, MASK mask) +{ + return canHandleControl(control_type, CLICK_NONE, key, mask); +} + +bool LLKeyConflictHandler::canHandleMouse(LLKeyConflictHandler::EControlTypes control_type, EMouseClickType mouse_ind, MASK mask) +{ + return canHandleControl(control_type, mouse_ind, KEY_NONE, mask); +} + +bool LLKeyConflictHandler::canHandleMouse(EControlTypes control_type, S32 mouse_ind, MASK mask) +{ + return canHandleControl(control_type, (EMouseClickType)mouse_ind, KEY_NONE, mask); +} + +bool LLKeyConflictHandler::canAssignControl(EControlTypes control_type) +{ + std::map::iterator iter = mControlsMap.find(control_type); + if (iter != mControlsMap.end()) + { + return iter->second.mAssignable; + } + return false; +} + +void LLKeyConflictHandler::registerControl(EControlTypes control_type, U32 index, EMouseClickType mouse, KEY key, MASK mask) +{ + LLKeyConflict &type_data = mControlsMap[control_type]; + if (!type_data.mAssignable) + { + LL_ERRS() << "Error in code, user or system should not be able to change certain controls" << LL_ENDL; + } + type_data.mKeyBind.replaceKeyData(mouse, key, mask, index); + + mHasUnsavedChanges = true; +} + +LLKeyData LLKeyConflictHandler::getControl(EControlTypes control_type, U32 index) +{ + return mControlsMap[control_type].getKeyData(index); +} + +// static +std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata) +{ + std::string result; + + if (keydata.mMask != MASK_NONE && keydata.mKey != KEY_NONE) + { + result = LLKeyboard::stringFromAccelerator(keydata.mMask, keydata.mKey); + } + else if (keydata.mKey != KEY_NONE) + { + result = LLKeyboard::stringFromKey(keydata.mKey); + } + else if (keydata.mMask != MASK_NONE) + { + LL_ERRS() << "Masks binding without keys is not supported yet" << LL_ENDL; + } + + #ifdef LL_DARWIN + // darwin uses special symbols and doesn't need '+' for masks + if (mMouse != CLICK_NONE && mKey != KEY_NONE) + { + result += " + "; + } + #else + if (keydata.mMouse != CLICK_NONE && !result.empty()) + { + result += " + "; + } + #endif + + switch (keydata.mMouse) + { + case CLICK_LEFT: + result += "LMB"; + break; + case CLICK_MIDDLE: + result += "MMB"; + break; + case CLICK_RIGHT: + result += "RMB"; + break; + case CLICK_BUTTON4: + result += "MB4"; + break; + case CLICK_BUTTON5: + result += "MB5"; + break; + case CLICK_DOUBLELEFT: + result += "Double LMB"; + break; + default: + break; + } + return result; +} + +// static +std::string LLKeyConflictHandler::getControlName(EControlTypes control_type) +{ + return typetostring[control_type]; +} + +std::string LLKeyConflictHandler::getControlString(EControlTypes control_type, U32 index) +{ + return getStringFromKeyData(mControlsMap[control_type].getKeyData(index)); +} + +void LLKeyConflictHandler::loadFromSettings(const LLViewerKeyboard::KeyMode& keymode, control_map_t *destination) +{ + for (LLInitParam::ParamIterator::const_iterator it = keymode.bindings.begin(), + end_it = keymode.bindings.end(); + it != end_it; + ++it) + { + KEY key; + MASK mask; + if (it->key.getValue().empty()) + { + key = KEY_NONE; + } + else + { + LLKeyboard::keyFromString(it->key, &key); + } + LLKeyboard::maskFromString(it->mask, &mask); + std::string command_name = it->command; + // it->command + // It might be better to have map, but at the moment enum is easier to iterate through. + // Besides keys.xml might not contain all commands + control_enum_t::const_iterator iter = command_to_key.find(command_name); + if (iter != command_to_key.end()) + { + LLKeyConflict &type_data = (*destination)[iter->second]; + type_data.mAssignable = true; + // Don't care about conflict level, all movement and view commands already account for it + type_data.mKeyBind.addKeyData(CLICK_NONE, key, mask); + } + } +} + +void LLKeyConflictHandler::loadFromSettings(const EModes &load_mode, const std::string &filename, control_map_t *destination) +{ + if (filename.empty()) + { + return; + } + + LLViewerKeyboard::Keys keys; + LLSimpleXUIParser parser; + + if (parser.readXUI(filename, keys) + && keys.validateBlock()) + { + switch (load_mode) + { + case MODE_FIRST_PERSON: + if (keys.first_person.isProvided()) + { + loadFromSettings(keys.first_person, destination); + } + break; + case MODE_THIRD_PERSON: + if (keys.third_person.isProvided()) + { + loadFromSettings(keys.third_person, destination); + } + break; + case MODE_EDIT: + if (keys.edit.isProvided()) + { + loadFromSettings(keys.edit, destination); + } + break; + case MODE_EDIT_AVATAR: + if (keys.edit_avatar.isProvided()) + { + loadFromSettings(keys.edit_avatar, destination); + } + break; + case MODE_SITTING: + if (keys.sitting.isProvided()) + { + loadFromSettings(keys.sitting, destination); + } + break; + default: + break; + } + } +} + +void LLKeyConflictHandler::loadFromSettings(EModes load_mode) +{ + mControlsMap.clear(); + mDefaultsMap.clear(); + if (load_mode == MODE_GENERAL) + { + for (U32 i = 0; i < CONTROL_NUM_INDICES; i++) + { + EControlTypes type = (EControlTypes)i; + switch (type) + { + case LLKeyConflictHandler::CONTROL_VIEW_ACTIONS: + case LLKeyConflictHandler::CONTROL_INTERACTIONS: + case LLKeyConflictHandler::CONTROL_MOVEMENTS: + case LLKeyConflictHandler::CONTROL_MEDIACONTENT: + case LLKeyConflictHandler::CONTROL_CAMERA: + case LLKeyConflictHandler::CONTROL_EDIT_TITLE: + case LLKeyConflictHandler::CONTROL_RESERVED: + // ignore 'headers', they are for representation and organization purposes + break; + default: + { + std::string name = getControlName(type); + LLControlVariablePtr var = gSavedSettings.getControl(name); + if (var) + { + LLKeyBind bind(var->getValue()); + LLKeyConflict key(bind, true, 0); + mControlsMap[type] = key; + } + break; + } + } + } + } + else + { + // load defaults + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "keys.xml"); + loadFromSettings(load_mode, filename, &mDefaultsMap); + + // load user's + filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml"); + if (gDirUtilp->fileExists(filename)) + { + loadFromSettings(load_mode, filename, &mControlsMap); + } + else + { + mControlsMap = mDefaultsMap; + } + } + mLoadedMode = load_mode; + + generatePlaceholders(); +} + +void LLKeyConflictHandler::saveToSettings() +{ + if (mControlsMap.empty()) + { + return; + } + + if (mLoadedMode == MODE_GENERAL) + { + for (U32 i = 0; i < CONTROL_NUM_INDICES; i++) + { + EControlTypes type = (EControlTypes)i; + switch (type) + { + case LLKeyConflictHandler::CONTROL_VIEW_ACTIONS: + case LLKeyConflictHandler::CONTROL_INTERACTIONS: + case LLKeyConflictHandler::CONTROL_MOVEMENTS: + case LLKeyConflictHandler::CONTROL_MEDIACONTENT: + case LLKeyConflictHandler::CONTROL_CAMERA: + case LLKeyConflictHandler::CONTROL_EDIT_TITLE: + case LLKeyConflictHandler::CONTROL_RESERVED: + // ignore 'headers', they are for representation and organization purposes + break; + default: + { + if (mControlsMap[type].mAssignable) + { + std::string name = getControlName(type); + if (gSavedSettings.controlExists(name)) + { + gSavedSettings.setLLSD(name, mControlsMap[type].mKeyBind.asLLSD()); + } + else if (!mControlsMap[type].mKeyBind.empty()) + { + // shouldn't happen user side since all settings are supposed to be declared already, but handy when creating new ones + // (just don't forget to change comment and to copy them from user's folder) + LL_INFOS() << "Creating new keybinding " << name << LL_ENDL; + gSavedSettings.declareLLSD(name, mControlsMap[type].mKeyBind.asLLSD(), "comment", LLControlVariable::PERSIST_ALWAYS); + } + } + break; + } + } + } + } + else + { + // loaded full copy of original file + std::string filename = gDirUtilp->findFile("keys.xml", + gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""), + gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + + LLViewerKeyboard::Keys keys; + LLSimpleXUIParser parser; + + if (parser.readXUI(filename, keys) + && keys.validateBlock()) + { + // replace category we edited + + // todo: fix this + // workaround to avoid doing own param container + LLViewerKeyboard::KeyMode mode; + LLViewerKeyboard::KeyBinding binding; + + control_map_t::iterator iter = mControlsMap.begin(); + control_map_t::iterator end = mControlsMap.end(); + for (; iter != end; ++iter) + { + U32 size = iter->second.mKeyBind.getDataCount(); + for (U32 i = 0; i < size; ++i) + { + // Still write empty keys to make sure we will maintain UI position + LLKeyData data = iter->second.mKeyBind.getKeyData(i); + if (data.mKey == KEY_NONE) + { + binding.key = ""; + } + else + { + // Note: this is UI string, we might want to hardcode our own for 'fixed' use in keys.xml + binding.key = LLKeyboard::stringFromKey(data.mKey); + } + binding.mask = string_from_mask(data.mMask); + binding.command = getControlName(iter->first); + mode.bindings.add(binding); + } + } + + switch (mLoadedMode) + { + case MODE_FIRST_PERSON: + if (keys.first_person.isProvided()) + { + keys.first_person.bindings.set(mode.bindings, true); + } + break; + case MODE_THIRD_PERSON: + if (keys.third_person.isProvided()) + { + keys.third_person.bindings.set(mode.bindings, true); + } + break; + case MODE_EDIT: + if (keys.edit.isProvided()) + { + keys.edit.bindings.set(mode.bindings, true); + } + break; + case MODE_EDIT_AVATAR: + if (keys.edit_avatar.isProvided()) + { + keys.edit_avatar.bindings.set(mode.bindings, true); + } + break; + case MODE_SITTING: + if (keys.sitting.isProvided()) + { + keys.sitting.bindings.set(mode.bindings, true); + } + break; + default: + break; + } + + // write back to user's xml; + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml"); + + LLXMLNodePtr output_node = new LLXMLNode("keys", false); + LLXUIParser parser; + parser.writeXUI(output_node, keys); + + // Write the resulting XML to file + if (!output_node->isNull()) + { + LLFILE *fp = LLFile::fopen(filename, "w"); + if (fp != NULL) + { + LLXMLNode::writeHeaderToFile(fp); + output_node->writeToFile(fp); + fclose(fp); + } + } + // Now force a rebind for keyboard + if (gDirUtilp->fileExists(filename)) + { + gViewerKeyboard.loadBindingsXML(filename); + } + } + } + mHasUnsavedChanges = false; +} + +LLKeyData LLKeyConflictHandler::getDefaultControl(EControlTypes control_type, U32 index) +{ + if (mLoadedMode == MODE_GENERAL) + { + std::string name = getControlName(control_type); + LLControlVariablePtr var = gSavedSettings.getControl(name); + if (var) + { + return LLKeyBind(var->getDefault()).getKeyData(index); + } + return LLKeyData(); + } + else + { + control_map_t::iterator iter = mDefaultsMap.find(control_type); + if (iter != mDefaultsMap.end()) + { + return iter->second.mKeyBind.getKeyData(index); + } + return LLKeyData(); + } +} + +void LLKeyConflictHandler::resetToDefault(EControlTypes control_type, U32 index) +{ + LLKeyData data = getDefaultControl(control_type, index); + mControlsMap[control_type].setKeyData(data, index); +} + +void LLKeyConflictHandler::resetToDefault(EControlTypes control_type) +{ + if (mLoadedMode == MODE_GENERAL) + { + std::string name = getControlName(control_type); + LLControlVariablePtr var = gSavedSettings.getControl(name); + if (var) + { + mControlsMap[control_type].mKeyBind = LLKeyBind(var->getDefault()); + } + else + { + mControlsMap[control_type].mKeyBind.clear(); + } + } + else + { + control_map_t::iterator iter = mDefaultsMap.find(control_type); + if (iter != mDefaultsMap.end()) + { + mControlsMap[control_type].mKeyBind = iter->second.mKeyBind; + } + else + { + mControlsMap[control_type].mKeyBind.clear(); + } + } +} + +void LLKeyConflictHandler::resetToDefaults(EModes mode) +{ + if (mode == MODE_GENERAL) + { + for (U32 i = 0; i < CONTROL_NUM_INDICES; i++) + { + EControlTypes type = (EControlTypes)i; + switch (type) + { + case LLKeyConflictHandler::CONTROL_VIEW_ACTIONS: + case LLKeyConflictHandler::CONTROL_INTERACTIONS: + case LLKeyConflictHandler::CONTROL_MOVEMENTS: + case LLKeyConflictHandler::CONTROL_MEDIACONTENT: + case LLKeyConflictHandler::CONTROL_CAMERA: + case LLKeyConflictHandler::CONTROL_EDIT_TITLE: + case LLKeyConflictHandler::CONTROL_RESERVED: + // ignore 'headers', they are for representation and organization purposes + break; + default: + { + resetToDefault(type); + break; + } + } + } + } + else + { + mControlsMap.clear(); + mControlsMap = mDefaultsMap; + generatePlaceholders(); + } + + mHasUnsavedChanges = true; +} + +void LLKeyConflictHandler::resetToDefaults() +{ + if (!empty()) + { + resetToDefaults(mLoadedMode); + } +} + +void LLKeyConflictHandler::resetAllToDefaults() +{ + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml"); + if (gDirUtilp->fileExists(filename)) + { + LLFile::remove(filename); + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "keys.xml"); + gViewerKeyboard.loadBindingsXML(filename); + } + + for (U32 i = 0; i < CONTROL_NUM_INDICES; i++) + { + EControlTypes type = (EControlTypes)i; + switch (type) + { + case LLKeyConflictHandler::CONTROL_VIEW_ACTIONS: + case LLKeyConflictHandler::CONTROL_INTERACTIONS: + case LLKeyConflictHandler::CONTROL_MOVEMENTS: + case LLKeyConflictHandler::CONTROL_MEDIACONTENT: + case LLKeyConflictHandler::CONTROL_RESERVED: + // ignore 'headers', they are for representation and organization purposes + break; + default: + { + resetToDefault(type); + break; + } + } + } + mHasUnsavedChanges = false; +} + +void LLKeyConflictHandler::clear() +{ + mHasUnsavedChanges = false; + mControlsMap.clear(); + mDefaultsMap.clear(); +} + +void LLKeyConflictHandler::resetKeyboardBindings() +{ + std::string filename = gDirUtilp->findFile("keys.xml", + gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""), + gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + + gViewerKeyboard.loadBindingsXML(filename); +} + +void LLKeyConflictHandler::generatePlaceholders() +{ + +} + +void LLKeyConflictHandler::registerTemporaryControl(EControlTypes control_type, EMouseClickType mouse, KEY key, MASK mask, U32 conflict_mask) +{ + LLKeyConflict *type_data = &mControlsMap[control_type]; + type_data->mAssignable = false; + type_data->mConflictMask = conflict_mask; + type_data->mKeyBind.addKeyData(mouse, key, mask); +} + diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h new file mode 100644 index 0000000000..79bd9b8438 --- /dev/null +++ b/indra/newview/llkeyconflict.h @@ -0,0 +1,214 @@ +/** + * @file llkeyconflict.h + * @brief + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2019, 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$ + */ + +#ifndef LL_LLKEYCONFLICT_H +#define LL_LLKEYCONFLICT_H + +#include "llkeybind.h" +#include "llviewerkeyboard.h" + + +class LLKeyConflict +{ +public: + LLKeyConflict() : mAssignable(true), mConflictMask(0) {} //temporary assignable, don't forget to change once all keys are recorded + LLKeyConflict(bool assignable, U32 conflict_mask) + : mAssignable(assignable), mConflictMask(conflict_mask) {} + LLKeyConflict(const LLKeyBind &bind, bool assignable, U32 conflict_mask) + : mAssignable(assignable), mConflictMask(conflict_mask), mKeyBind(bind) {} + + LLKeyData getPrimaryKeyData() { return mKeyBind.getKeyData(0); } + LLKeyData getKeyData(U32 index) { return mKeyBind.getKeyData(index); } + void setPrimaryKeyData(const LLKeyData& data) { mKeyBind.replaceKeyData(data, 0); } + void setKeyData(const LLKeyData& data, U32 index) { mKeyBind.replaceKeyData(data, index); } + bool canHandle(EMouseClickType mouse, KEY key, MASK mask) { return mKeyBind.canHandle(mouse, key, mask); } + + LLKeyBind mKeyBind; + bool mAssignable; // whether user can change key or key simply acts as placeholder + U32 mConflictMask; +}; + +class LLKeyConflictHandler +{ +public: + + enum EModes // partially repeats e_keyboard_mode + { + MODE_FIRST_PERSON, + MODE_THIRD_PERSON, + MODE_EDIT, + MODE_EDIT_AVATAR, + MODE_SITTING, + MODE_GENERAL, + MODE_COUNT + }; + + enum EConflictTypes // priority higherst to lowest + { + CONFLICT_LAND = 1, + CONFLICT_OBJECT = 2, + CONFLICT_TOUCH = 4, + CONFLICT_INTERACTIBLE = 8, + CONFLICT_AVATAR = 16, + CONFLICT_ANY = 511 + }; + + // todo, unfortunately will have to remove this and use map/array of strings + enum EControlTypes + { + CONTROL_VIEW_ACTIONS = 0, // Group control, for visual representation in view, not for use + CONTROL_ABOUT, + CONTROL_ORBIT, + CONTROL_PAN, + CONTROL_WORLD_MAP, + CONTROL_ZOOM, + CONTROL_INTERACTIONS, // Group control, for visual representation + CONTROL_BUILD, + //CONTROL_DRAG, + CONTROL_EDIT, + //CONTROL_MENU, + CONTROL_OPEN, + CONTROL_TOUCH, + CONTROL_WEAR, + CONTROL_MOVEMENTS, // Group control, for visual representation + CONTROL_MOVETO, + CONTROL_SIT, + CONTROL_TELEPORTTO, + CONTROL_FORWARD, + CONTROL_BACKWARD, + CONTROL_LEFT, // Check and sinc name with real movement names + CONTROL_RIGHT, + CONTROL_LSTRAFE, + CONTROL_RSTRAFE, + CONTROL_JUMP, + CONTROL_DOWN, + //CONTROL_RUN, + CONTROL_TOGGLE_RUN, + CONTROL_TOGGLE_FLY, + CONTROL_STOP, + CONTROL_CAMERA, // Group control, for visual representation + CONTROL_LOOK_UP, + CONTROL_LOOK_DOWN, + CONTROL_CAMERA_FORWARD, + CONTROL_CAMERA_BACKWARD, + CONTROL_CAMERA_FFORWARD, + CONTROL_CAMERA_FBACKWARD, + CONTROL_CAMERA_FSITTING, + CONTROL_CAMERA_BSITTING, + CONTROL_CAMERA_SOVER, + CONTROL_CAMERA_SUNDER, + CONTROL_CAMERA_SOVER_SITTING, + CONTROL_CAMERA_SUNDER_SITTING, + CONTROL_CAMERA_PANUP, + CONTROL_CAMERA_PANDOWN, + CONTROL_CAMERA_PANLEFT, + CONTROL_CAMERA_PANRIGHT, + CONTROL_CAMERA_PANIN, + CONTROL_CAMERA_PANOUT, + CONTROL_CAMERA_SPIN_CCW, + CONTROL_CAMERA_SPIN_CW, + CONTROL_CAMERA_SPIN_CCW_SITTING, + CONTROL_CAMERA_SPIN_CW_SITTING, + CONTROL_EDIT_TITLE, // Group control, for visual representation + CONTROL_EDIT_AV_SPIN_CCW, + CONTROL_EDIT_AV_SPIN_CW, + CONTROL_EDIT_AV_SPIN_OVER, + CONTROL_EDIT_AV_SPIN_UNDER, + CONTROL_EDIT_AV_MV_FORWARD, + CONTROL_EDIT_AV_MV_BACKWARD, + CONTROL_MEDIACONTENT, // Group control, for visual representation + CONTROL_PARCEL, // Play pause + CONTROL_MEDIA, // Play stop + CONTROL_VOICE, // Keep pressing for it to be ON + CONTROL_TOGGLE_VOICE, // Press once to ON/OFF + CONTROL_START_CHAT, // Press once to ON/OFF + CONTROL_START_GESTURE, // Press once to ON/OFF + CONTROL_RESERVED, // Special group control, controls that are disabled by default and not meant to be changed + CONTROL_DELETE, + CONTROL_RESERVED_MENU, + CONTROL_RESERVED_SELECT, + CONTROL_SHIFT_SELECT, + CONTROL_CNTRL_SELECT, + CONTROL_NUM_INDICES // Size, always should be last + }; + + // Note: missed selection and edition commands (would be really nice to go through selection via MB4/5 or wheel) + + LLKeyConflictHandler(); + LLKeyConflictHandler(EModes mode); + + bool canHandleControl(EControlTypes control_type, EMouseClickType mouse_ind, KEY key, MASK mask); + bool canHandleKey(EControlTypes control_type, KEY key, MASK mask); + bool canHandleMouse(EControlTypes control_type, EMouseClickType mouse_ind, MASK mask); + bool canHandleMouse(EControlTypes control_type, S32 mouse_ind, MASK mask); //Just for convinience + bool canAssignControl(EControlTypes control_type); + void registerControl(EControlTypes control_type, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask); //todo: return conflicts? + + LLKeyData getControl(EControlTypes control_type, U32 data_index); + + static std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata); + static std::string getControlName(EControlTypes control_type); + std::string getControlString(EControlTypes control_type, U32 data_index); + + + // Drops any changes loads controls with ones from 'saved settings' or from xml + void loadFromSettings(EModes load_mode); + // Saves settings to 'saved settings' or to xml + void saveToSettings(); + + LLKeyData getDefaultControl(EControlTypes control_type, U32 data_index); + // Resets keybinding to default variant from 'saved settings' or xml + void resetToDefault(EControlTypes control_type, U32 index); + void resetToDefault(EControlTypes control_type); + void resetToDefaults(EModes mode); + void resetToDefaults(); + void resetAllToDefaults(); + + bool empty() { return mControlsMap.empty(); } + void clear(); + + bool hasUnsavedChanges() { return mHasUnsavedChanges; } + EModes getLoadedMode() { return mLoadedMode; } + // todo: conflict search + +private: + // at the moment these kind of control is not savable, but takes part will take part in conflict resolution + void registerTemporaryControl(EControlTypes control_type, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask); + + typedef std::map control_map_t; + void loadFromSettings(const LLViewerKeyboard::KeyMode& keymode, control_map_t *destination); + void loadFromSettings(const EModes &load_mode, const std::string &filename, control_map_t *destination); + void resetKeyboardBindings(); + void generatePlaceholders(); //'headers' for ui and non-assignable values + + control_map_t mControlsMap; + control_map_t mDefaultsMap; + bool mHasUnsavedChanges; + EModes mLoadedMode; +}; + + +#endif // LL_LLKEYCONFLICT_H diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp index a14041717f..878810e0dd 100644 --- a/indra/newview/llviewerkeyboard.cpp +++ b/indra/newview/llviewerkeyboard.cpp @@ -603,6 +603,12 @@ void start_gesture( EKeystate s ) } } +void toggle_parcel_media(EKeystate s) +{ + bool pause = LLViewerMedia::isAnyMediaPlaying(); + LLViewerMedia::setAllMediaPaused(pause); +} + #define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION); REGISTER_KEYBOARD_ACTION("jump", agent_jump); REGISTER_KEYBOARD_ACTION("push_down", agent_push_down); @@ -644,6 +650,7 @@ REGISTER_KEYBOARD_ACTION("edit_avatar_move_backward", edit_avatar_move_backward) REGISTER_KEYBOARD_ACTION("stop_moving", stop_moving); REGISTER_KEYBOARD_ACTION("start_chat", start_chat); REGISTER_KEYBOARD_ACTION("start_gesture", start_gesture); +REGISTER_KEYBOARD_ACTION("toggle_parcel_media", toggle_parcel_media); #undef REGISTER_KEYBOARD_ACTION LLViewerKeyboard::LLViewerKeyboard() @@ -805,7 +812,7 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c mBindings[mode][index].mFunction = function; if (index == mBindingCount[mode]) - mBindingCount[mode]++; + mBindingCount[mode]++; return TRUE; } @@ -816,21 +823,25 @@ LLViewerKeyboard::KeyBinding::KeyBinding() command("command") {} -LLViewerKeyboard::KeyMode::KeyMode(EKeyboardMode _mode) -: bindings("binding"), - mode(_mode) +LLViewerKeyboard::KeyMode::KeyMode() +: bindings("binding") {} LLViewerKeyboard::Keys::Keys() -: first_person("first_person", KeyMode(MODE_FIRST_PERSON)), - third_person("third_person", KeyMode(MODE_THIRD_PERSON)), - edit("edit", KeyMode(MODE_EDIT)), - sitting("sitting", KeyMode(MODE_SITTING)), - edit_avatar("edit_avatar", KeyMode(MODE_EDIT_AVATAR)) +: first_person("first_person"), + third_person("third_person"), + edit("edit"), + sitting("sitting"), + edit_avatar("edit_avatar") {} S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename) { + for (S32 i = 0; i < MODE_COUNT; i++) + { + mBindingCount[i] = 0; + } + S32 binding_count = 0; Keys keys; LLSimpleXUIParser parser; @@ -838,16 +849,16 @@ S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename) if (parser.readXUI(filename, keys) && keys.validateBlock()) { - binding_count += loadBindingMode(keys.first_person); - binding_count += loadBindingMode(keys.third_person); - binding_count += loadBindingMode(keys.edit); - binding_count += loadBindingMode(keys.sitting); - binding_count += loadBindingMode(keys.edit_avatar); + binding_count += loadBindingMode(keys.first_person, MODE_FIRST_PERSON); + binding_count += loadBindingMode(keys.third_person, MODE_THIRD_PERSON); + binding_count += loadBindingMode(keys.edit, MODE_EDIT); + binding_count += loadBindingMode(keys.sitting, MODE_SITTING); + binding_count += loadBindingMode(keys.edit_avatar, MODE_EDIT_AVATAR); } return binding_count; } -S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode) +S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode, S32 mode) { S32 binding_count = 0; for (LLInitParam::ParamIterator::const_iterator it = keymode.bindings.begin(), @@ -855,12 +866,15 @@ S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode) it != end_it; ++it) { - KEY key; - MASK mask; - LLKeyboard::keyFromString(it->key, &key); - LLKeyboard::maskFromString(it->mask, &mask); - bindKey(keymode.mode, key, mask, it->command); - binding_count++; + if (!it->key.getValue().empty()) + { + KEY key; + MASK mask; + LLKeyboard::keyFromString(it->key, &key); + LLKeyboard::maskFromString(it->mask, &mask); + bindKey(mode, key, mask, it->command); + binding_count++; + } } return binding_count; diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h index 110dc89d28..2bfe285be4 100644 --- a/indra/newview/llviewerkeyboard.h +++ b/indra/newview/llviewerkeyboard.h @@ -71,8 +71,8 @@ public: struct KeyMode : public LLInitParam::Block { Multiple bindings; - EKeyboardMode mode; - KeyMode(EKeyboardMode mode); + + KeyMode(); }; struct Keys : public LLInitParam::Block @@ -100,7 +100,7 @@ public: void scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level); private: - S32 loadBindingMode(const LLViewerKeyboard::KeyMode& keymode); + S32 loadBindingMode(const LLViewerKeyboard::KeyMode& keymode, S32 mode); BOOL bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name); // Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 676f06bcb9..fcca081647 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -35,7 +35,6 @@ #include "llnotificationsutil.h" #include "llsdserialize.h" #include "llui.h" -#include "llkeybindings.h" #include "llkeyboard.h" #include "llagent.h" @@ -691,33 +690,38 @@ void LLVoiceClient::keyDown(KEY key, MASK mask) return; } - if (LLAgent::isActionAllowed("speak") && gControlBindings.canHandleKey(LLControlBindings::CONTROL_VOICE, key, mask)) + // + /*static LLCachedControl key_bind(gSavedSettings, "control_toggle_voice"); + LLKeyBind bind(key_bind); + if (LLAgent::isActionAllowed("speak") && bind().canHandleKey(key, mask)) { bool down = gKeyboard->getKeyDown(mPTTKey); if (down) { inputUserControlState(down); } - } + }*/ } void LLVoiceClient::keyUp(KEY key, MASK mask) { - if (gControlBindings.canHandleKey(LLControlBindings::CONTROL_VOICE, key, mask)) + /*static LLCachedControl key_bind(gSavedSettings, "control_toggle_voice"); + if (key_bind().canHandleKey(key, mask)) { bool down = gKeyboard->getKeyDown(mPTTKey); if (!down) { inputUserControlState(down); } - } + }*/ } void LLVoiceClient::updateMouseState(S32 click, MASK mask, bool down) { - if(LLAgent::isActionAllowed("speak") && gControlBindings.canHandleMouse(LLControlBindings::CONTROL_VOICE, click, mask)) + /*static LLCachedControl mouse_bind(gSavedSettings, "control_toggle_voice"); + if (mouse_bind().canHandleMouse((EMouseClickType)click, mask)) { inputUserControlState(down); - } + }*/ } diff --git a/indra/newview/skins/default/xui/en/floater_select_key.xml b/indra/newview/skins/default/xui/en/floater_select_key.xml index 4e89df5a73..c00b805954 100644 --- a/indra/newview/skins/default/xui/en/floater_select_key.xml +++ b/indra/newview/skins/default/xui/en/floater_select_key.xml @@ -7,7 +7,15 @@ height="90" layout="topleft" name="modal container" - width="240"> + width="272"> + + Keyboard + + + Mouse Buttons + - Press a key to set your Speak button trigger. + width="212"> +Press a key to set your trigger. +Allowed input: [INPUT]. + +