diff options
| author | gwigz <gwigz@users.noreply.github.com> | 2026-06-18 22:04:45 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-06-19 00:04:45 +0300 |
| commit | 2c591b1429f44795aceebd5c6f5ea6907b2a08ea (patch) | |
| tree | 89f6416ea920acfc381a3f35f23de45ad3b4c98f /indra | |
| parent | fc2e96135d0a55df5f3b668298fa72505d39413b (diff) | |
#5928 Gesture auto-complete, similar to emojis/mentions
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/llui/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/llui/llgestureautocompletehelper.cpp | 168 | ||||
| -rw-r--r-- | indra/llui/llgestureautocompletehelper.h | 83 | ||||
| -rw-r--r-- | indra/llui/lltexteditor.cpp | 7 | ||||
| -rw-r--r-- | indra/newview/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/newview/llfloatergestureautocompletepicker.cpp | 165 | ||||
| -rw-r--r-- | indra/newview/llfloatergestureautocompletepicker.h | 47 | ||||
| -rw-r--r-- | indra/newview/llfloaterimnearbychat.cpp | 100 | ||||
| -rw-r--r-- | indra/newview/llviewerfloaterreg.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/floater_gesture_autocomplete_picker.xml | 39 |
10 files changed, 612 insertions, 3 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 908e94b24c..1c9a16ba41 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -41,6 +41,7 @@ set(llui_SOURCE_FILES llfloaterreglistener.cpp llflyoutbutton.cpp llfocusmgr.cpp + llgestureautocompletehelper.cpp llfolderview.cpp llfolderviewitem.cpp llfolderviewmodel.cpp @@ -154,6 +155,7 @@ set(llui_HEADER_FILES llfloaterreglistener.h llflyoutbutton.h llfocusmgr.h + llgestureautocompletehelper.h llfolderview.h llfolderviewitem.h llfolderviewmodel.h diff --git a/indra/llui/llgestureautocompletehelper.cpp b/indra/llui/llgestureautocompletehelper.cpp new file mode 100644 index 0000000000..ca976fff10 --- /dev/null +++ b/indra/llui/llgestureautocompletehelper.cpp @@ -0,0 +1,168 @@ +/** + * @file llgestureautocompletehelper.cpp + * + * $LicenseInfo:firstyear=2026&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2026, 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 "llgestureautocompletehelper.h" + +#include "llfloater.h" +#include "llfloaterreg.h" +#include "llfocusmgr.h" +#include "lluictrl.h" + +constexpr char GESTURE_AUTOCOMPLETE_FLOATER[] = "gesture_autocomplete_picker"; + +bool LLGestureAutocompleteHelper::isActive(const LLUICtrl* ctrl) const +{ + return mHostHandle.get() == ctrl; +} + +void LLGestureAutocompleteHelper::showHelper( + LLUICtrl* host_ctrl, + const std::vector<Row>& rows, + size_t total, + const std::string& empty_text, + std::function<void(std::string)> commit_cb) +{ + if (mHelperHandle.isDead()) + { + LLFloater* helper_floater = LLFloaterReg::getInstance(GESTURE_AUTOCOMPLETE_FLOATER); + mHelperHandle = helper_floater->getHandle(); + mHelperCommitConn = helper_floater->setCommitCallback( + [this](LLUICtrl*, const LLSD& param) { onCommitGesture(param.asString()); }); + } + + setHostCtrl(host_ctrl); + mRows = rows; + mTotal = total; + mEmptyText = empty_text; + mGestureCommitCb = commit_cb; + + S32 floater_x, floater_y; + LLRect host_rect = host_ctrl->getRect(); + if (!host_ctrl->localPointToOtherView(0, host_rect.getHeight(), &floater_x, &floater_y, gFloaterView)) + { + LL_WARNS() << "Cannot show gesture autocomplete helper for non-floater controls." << LL_ENDL; + return; + } + + LLFloater* helper_floater = mHelperHandle.get(); + LLRect rect = helper_floater->getRect(); + rect.setLeftTopAndSize(floater_x, floater_y + rect.getHeight(), rect.getWidth(), rect.getHeight()); + helper_floater->setRect(rect); + + refreshPicker(); +} + +void LLGestureAutocompleteHelper::hideHelper(const LLUICtrl* ctrl) +{ + if (ctrl && !isActive(ctrl)) + { + return; + } + + setHostCtrl(nullptr); +} + +bool LLGestureAutocompleteHelper::handleKey(const LLUICtrl* ctrl, KEY key, MASK mask) +{ + if (mHelperHandle.isDead() || !isActive(ctrl)) + { + return false; + } + + return mHelperHandle.get()->handleKey(key, mask, true); +} + +void LLGestureAutocompleteHelper::onCommitGesture(const std::string& trigger) +{ + if (!mHostHandle.isDead() && mGestureCommitCb) + { + mGestureCommitCb(trigger); + } + + hideHelper(getHostCtrl()); +} + +void LLGestureAutocompleteHelper::refreshPicker() +{ + if (mHelperHandle.isDead()) + { + return; + } + + LLFloater* helper_floater = mHelperHandle.get(); + + if (helper_floater->isShown()) + { + helper_floater->onOpen(LLSD()); + } + else + { + helper_floater->openFloater(LLSD()); + } +} + +void LLGestureAutocompleteHelper::setHostCtrl(LLUICtrl* host_ctrl) +{ + const LLUICtrl* cur_host_ctrl = mHostHandle.get(); + + if (cur_host_ctrl != host_ctrl) + { + mHostCtrlFocusLostConn.disconnect(); + mHostHandle.markDead(); + mGestureCommitCb = {}; + mRows.clear(); + mEmptyText.clear(); + mTotal = 0; + + if (!mHelperHandle.isDead()) + { + mHelperHandle.get()->closeFloater(); + } + + if (host_ctrl) + { + mHostHandle = host_ctrl->getHandle(); + mHostCtrlFocusLostConn = host_ctrl->setFocusLostCallback( + [this](auto*) + { + // Scroll list grabs focus on click. + // Keep focus on the host when the click was ours. + LLFloater* helper_floater = mHelperHandle.get(); + if (helper_floater && gFocusMgr.childHasKeyboardFocus(helper_floater)) + { + if (LLUICtrl* host = getHostCtrl()) + { + host->setFocus(true); + } + return; + } + + hideHelper(getHostCtrl()); + }); + } + } +} diff --git a/indra/llui/llgestureautocompletehelper.h b/indra/llui/llgestureautocompletehelper.h new file mode 100644 index 0000000000..53000c0829 --- /dev/null +++ b/indra/llui/llgestureautocompletehelper.h @@ -0,0 +1,83 @@ +/** + * @file llgestureautocompletehelper.h + * + * $LicenseInfo:firstyear=2026&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2026, 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$ + */ + +#pragma once + +#include "llhandle.h" +#include "llsingleton.h" + +#include <boost/signals2.hpp> +#include <functional> +#include <string> +#include <vector> + +class LLFloater; +class LLUICtrl; + +class LLGestureAutocompleteHelper : public LLSingleton<LLGestureAutocompleteHelper> +{ + LLSINGLETON(LLGestureAutocompleteHelper) {} + ~LLGestureAutocompleteHelper() override {} + +public: + struct Row + { + std::string value; + std::string trigger; + std::string name; + }; + + bool isActive(const LLUICtrl* ctrl) const; + void showHelper( + LLUICtrl* host_ctrl, + const std::vector<Row>& rows, + size_t total, + const std::string& empty_text, + std::function<void(std::string)> commit_cb); + void hideHelper(const LLUICtrl* ctrl = nullptr); + bool handleKey(const LLUICtrl* ctrl, KEY key, MASK mask); + void onCommitGesture(const std::string& trigger); + + const std::vector<Row>& rows() const { return mRows; } + size_t total() const { return mTotal; } + const std::string& emptyText() const { return mEmptyText; } + +protected: + void setHostCtrl(LLUICtrl* host_ctrl); + LLUICtrl* getHostCtrl() const { return mHostHandle.get(); } + +private: + void refreshPicker(); + + LLHandle<LLUICtrl> mHostHandle; + LLHandle<LLFloater> mHelperHandle; + boost::signals2::connection mHostCtrlFocusLostConn; + boost::signals2::connection mHelperCommitConn; + std::function<void(std::string)> mGestureCommitCb; + + std::vector<Row> mRows; + std::string mEmptyText; + size_t mTotal = 0; +}; diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 7689b93374..5f1302df88 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -61,6 +61,7 @@ #include "lltooltip.h" #include "llmenugl.h" #include "llchatmentionhelper.h" +#include "llgestureautocompletehelper.h" #include <queue> #include "llcombobox.h" @@ -1950,7 +1951,8 @@ bool LLTextEditor::handleKeyHere(KEY key, MASK mask ) // not handled and let the parent take care of field movement. if (KEY_TAB == key && mTabsToNextField) { - return mShowChatMentionPicker && LLChatMentionHelper::instance().handleKey(this, key, mask); + return (mShowChatMentionPicker && LLChatMentionHelper::instance().handleKey(this, key, mask)) + || LLGestureAutocompleteHelper::instance().handleKey(this, key, mask); } if (mReadOnly && mScroller) @@ -1964,7 +1966,8 @@ bool LLTextEditor::handleKeyHere(KEY key, MASK mask ) if (!mReadOnly) { if ((mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) || - (mShowChatMentionPicker && LLChatMentionHelper::instance().handleKey(this, key, mask))) + (mShowChatMentionPicker && LLChatMentionHelper::instance().handleKey(this, key, mask)) || + LLGestureAutocompleteHelper::instance().handleKey(this, key, mask)) { return true; } diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 663b932f3b..3e0c343913 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -233,6 +233,7 @@ set(viewer_SOURCE_FILES llfloaterfonttest.cpp llfloaterforgetuser.cpp llfloatergesture.cpp + llfloatergestureautocompletepicker.cpp llfloatergltfasseteditor.cpp llfloatergodtools.cpp llfloatergotoline.cpp @@ -912,6 +913,7 @@ set(viewer_HEADER_FILES llfloaterfonttest.h llfloaterforgetuser.h llfloatergesture.h + llfloatergestureautocompletepicker.h llfloatergltfasseteditor.h llfloatergodtools.h llfloatergotoline.h diff --git a/indra/newview/llfloatergestureautocompletepicker.cpp b/indra/newview/llfloatergestureautocompletepicker.cpp new file mode 100644 index 0000000000..14d2065b5b --- /dev/null +++ b/indra/newview/llfloatergestureautocompletepicker.cpp @@ -0,0 +1,165 @@ +/** + * @file llfloatergestureautocompletepicker.cpp + * + * $LicenseInfo:firstyear=2026&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2026, 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 "llviewerprecompiledheaders.h" + +#include "llfloatergestureautocompletepicker.h" + +#include "llgestureautocompletehelper.h" +#include "llscrolllistctrl.h" +#include "llscrolllistitem.h" + +LLFloaterGestureAutocompletePicker::LLFloaterGestureAutocompletePicker(const LLSD& key) +: LLFloater(key), mGestureList(NULL) +{ + setFocusStealsFrontmost(false); + setBackgroundVisible(false); + setAutoFocus(false); +} + +bool LLFloaterGestureAutocompletePicker::postBuild() +{ + mGestureList = getChild<LLScrollListCtrl>("gesture_list"); + mGestureList->setCommitOnKeyboardMovement(false); + mGestureList->setCommitCallback(boost::bind(&LLFloaterGestureAutocompletePicker::commitSelected, this)); + + return LLFloater::postBuild(); +} + +void LLFloaterGestureAutocompletePicker::onOpen(const LLSD& key) +{ + LLGestureAutocompleteHelper& helper = LLGestureAutocompleteHelper::instance(); + mGestureList->clearRows(); + + const std::vector<LLGestureAutocompleteHelper::Row>& rows = helper.rows(); + + for (const auto& row : rows) + { + LLSD element; + element["value"] = row.value; + element["columns"][0]["column"] = "trigger"; + element["columns"][0]["value"] = row.trigger; + element["columns"][1]["column"] = "name"; + element["columns"][1]["value"] = row.name; + mGestureList->addElement(element); + } + + if (rows.empty() && !helper.emptyText().empty()) + { + LLSD element; + element["enabled"] = false; + element["columns"][0]["column"] = "trigger"; + element["columns"][0]["value"] = helper.emptyText(); + element["columns"][1]["column"] = "name"; + element["columns"][1]["value"] = LLStringUtil::null; + mGestureList->addElement(element); + } + + if (helper.total() > rows.size()) + { + LLSD element; + element["enabled"] = false; + element["columns"][0]["column"] = "trigger"; + element["columns"][0]["value"] = LLStringUtil::null; + element["columns"][1]["column"] = "name"; + + LLStringUtil::format_map_t args; + args["[COUNT]"] = llformat("%d", (S32)rows.size()); + args["[TOTAL]"] = llformat("%d", (S32)helper.total()); + element["columns"][1]["value"] = getString("showing_count", args); + + mGestureList->addElement(element); + } + + mGestureList->selectFirstItem(); + gFloaterView->adjustToFitScreen(this, false); +} + +bool LLFloaterGestureAutocompletePicker::handleKey(KEY key, MASK mask, bool called_from_parent) +{ + if (mask == MASK_NONE) + { + switch (key) + { + case KEY_UP: + mGestureList->selectPrevItem(); + mGestureList->scrollToShowSelected(); + return true; + case KEY_DOWN: + mGestureList->selectNextItem(); + mGestureList->scrollToShowSelected(); + return true; + case KEY_RETURN: + case KEY_TAB: + commitSelected(); + return true; + case KEY_ESCAPE: + LLGestureAutocompleteHelper::instance().hideHelper(); + return true; + case KEY_LEFT: + case KEY_RIGHT: + return true; + default: + break; + } + } + + return LLFloater::handleKey(key, mask, called_from_parent); +} + +void LLFloaterGestureAutocompletePicker::onClose(bool app_quitting) +{ + if (!app_quitting) + { + LLGestureAutocompleteHelper::instance().hideHelper(); + } +} + +void LLFloaterGestureAutocompletePicker::goneFromFront() +{ + LLGestureAutocompleteHelper::instance().hideHelper(); +} + +bool LLFloaterGestureAutocompletePicker::commitSelected() +{ + LLScrollListItem* item = mGestureList->getFirstSelected(); + + if (!item || !item->getEnabled()) + { + return false; + } + + const std::string value = mGestureList->getSelectedValue().asString(); + + if (value.empty()) + { + return false; + } + + setValue(value); + onCommit(); + + return true; +} diff --git a/indra/newview/llfloatergestureautocompletepicker.h b/indra/newview/llfloatergestureautocompletepicker.h new file mode 100644 index 0000000000..71f754138d --- /dev/null +++ b/indra/newview/llfloatergestureautocompletepicker.h @@ -0,0 +1,47 @@ +/** + * @file llfloatergestureautocompletepicker.h + * + * $LicenseInfo:firstyear=2026&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2026, 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$ + */ + +#pragma once + +#include "llfloater.h" + +class LLScrollListCtrl; + +class LLFloaterGestureAutocompletePicker : public LLFloater +{ +public: + LLFloaterGestureAutocompletePicker(const LLSD& key); + + bool postBuild() override; + void onOpen(const LLSD& key) override; + bool handleKey(KEY key, MASK mask, bool called_from_parent) override; + void onClose(bool app_quitting) override; + void goneFromFront() override; + +private: + bool commitSelected(); + + LLScrollListCtrl* mGestureList; +}; diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index f0d696361a..8fa183b180 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -55,6 +55,7 @@ #include "llfloaterimnearbychatlistener.h" #include "llagent.h" // gAgent #include "llgesturemgr.h" +#include "llgestureautocompletehelper.h" #include "llmultigesture.h" #include "llkeyboard.h" #include "llanimationstates.h" @@ -70,6 +71,8 @@ #include "llautoreplace.h" #include "lluiusage.h" +#include <map> + S32 LLFloaterIMNearbyChat::sLastSpecialChatChannel = 0; static LLFloaterIMNearbyChatListener sChatListener; @@ -77,6 +80,72 @@ static LLFloaterIMNearbyChatListener sChatListener; constexpr S32 EXPANDED_HEIGHT = 266; constexpr S32 COLLAPSED_HEIGHT = 60; constexpr S32 EXPANDED_MIN_HEIGHT = 150; +constexpr size_t MAX_GESTURE_AUTOCOMPLETE_ROWS = 50; + +namespace +{ +bool buildGestureAutocompleteRows( + const std::string& prefix, + std::vector<LLGestureAutocompleteHelper::Row>& rows, + size_t& total, + std::string& empty_text) +{ + rows.clear(); + total = 0; + empty_text.clear(); + + // Wait for at least one character after the slash before offering matches. + if (prefix.size() < 2 || prefix[0] != '/' || prefix.find_first_of(" \t") != std::string::npos) + { + return false; + } + + std::string lower_prefix = prefix; + LLStringUtil::toLower(lower_prefix); + + std::map<std::string, std::string> unique; + const LLGestureMgr::item_map_t& active = LLGestureMgr::instance().getActiveGestures(); + + for (const auto& entry : active) + { + LLMultiGesture* gesture = entry.second; + + if (!gesture || gesture->getTrigger().empty() || gesture->getTrigger()[0] != '/') + { + continue; + } + + std::string lower_trigger = gesture->getTrigger(); + LLStringUtil::toLower(lower_trigger); + + if (lower_trigger.compare(0, lower_prefix.size(), lower_prefix) != 0) + { + continue; + } + + unique.emplace( + gesture->getTrigger(), + gesture->mName); + } + + for (const auto& gesture : unique) + { + ++total; + + if (rows.size() < MAX_GESTURE_AUTOCOMPLETE_ROWS) + { + rows.push_back({ gesture.first, gesture.first, gesture.second }); + } + } + + if (rows.empty()) + { + empty_text = "No matching gestures"; + } + + return total > 0; +} +} // legacy callback glue void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel); @@ -501,8 +570,34 @@ void LLFloaterIMNearbyChat::onChatBoxKeystroke() KEY key = gKeyboard->currentKey(); + static LLCachedControl<bool> autocomplete_gestures(gSavedSettings, "ChatAutocompleteGestures", true); + + if (autocomplete_gestures) + { + std::vector<LLGestureAutocompleteHelper::Row> rows; + size_t total = 0; + std::string empty_text; + const std::string utf8_trigger = wstring_to_utf8str(raw_text); + + if (buildGestureAutocompleteRows(utf8_trigger, rows, total, empty_text)) + { + LLGestureAutocompleteHelper::instance().showHelper( + mInputEditor, + rows, + total, + empty_text, + [this](std::string trigger) + { + mInputEditor->setText(trigger + " "); + mInputEditor->endOfDoc(); + }); + return; + } + + LLGestureAutocompleteHelper::instance().hideHelper(mInputEditor); + } // Ignore "special" keys, like backspace, arrows, etc. - if (gSavedSettings.getBOOL("ChatAutocompleteGestures") + if (autocomplete_gestures && length > 1 && raw_text[0] == '/' && key < KEY_SPECIAL) @@ -589,6 +684,9 @@ void LLFloaterIMNearbyChat::sendChat( EChatType type ) LLWString text = mInputEditor->getConvertedText(); LLWStringUtil::trim(text); LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines. + + LLGestureAutocompleteHelper::instance().hideHelper(); + if (!text.empty()) { // Check if this is destined for another channel diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index eef31c7048..b034a934de 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -79,6 +79,7 @@ #include "llfloaterfonttest.h" #include "llfloaterforgetuser.h" #include "llfloatergesture.h" +#include "llfloatergestureautocompletepicker.h" #include "llfloatergltfasseteditor.h" #include "llfloatergodtools.h" #include "llfloatergridstatus.h" @@ -382,6 +383,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("font_test", "floater_font_test.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFontTest>); LLFloaterReg::add("forget_username", "floater_forget_user.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterForgetUser>); + LLFloaterReg::add("gesture_autocomplete_picker", "floater_gesture_autocomplete_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGestureAutocompletePicker>); LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGesture>); LLFloaterReg::add("gltf_asset_editor", "floater_gltf_asset_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGLTFAssetEditor>); LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGodTools>); diff --git a/indra/newview/skins/default/xui/en/floater_gesture_autocomplete_picker.xml b/indra/newview/skins/default/xui/en/floater_gesture_autocomplete_picker.xml new file mode 100644 index 0000000000..cc4a3133cb --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_gesture_autocomplete_picker.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + name="gesture_autocomplete_picker" + title="CHOOSE GESTURE" + single_instance="true" + can_minimize="false" + can_tear_off="false" + can_resize="true" + auto_close="true" + layout="topleft" + min_width="250" + chrome="true" + sound_flags="0" + height="136" + width="340"> + <floater.string + name="showing_count"> + Showing [COUNT] of [TOTAL] + </floater.string> + <scroll_list + follows="all" + height="130" + width="336" + layout="topleft" + left="3" + top="3" + name="gesture_list" + draw_heading="false" + multi_select="false"> + <scroll_list.columns + name="trigger" + label="Trigger" + width="128" /> + <scroll_list.columns + name="name" + label="Gesture" + dynamic_width="true" /> + </scroll_list> +</floater> |
