diff options
Diffstat (limited to 'indra/llui')
26 files changed, 556 insertions, 42 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index a0314cb5f2..69e1b57245 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -49,6 +49,7 @@ set(llui_SOURCE_FILES lllineeditor.cpp llloadingindicator.cpp lllocalcliprect.cpp + llluafloater.cpp llmenubutton.cpp llmenugl.cpp llmodaldialog.cpp @@ -164,6 +165,7 @@ set(llui_HEADER_FILES lllineeditor.h llloadingindicator.h lllocalcliprect.h + llluafloater.h llmenubutton.h llmenugl.h llmodaldialog.h diff --git a/indra/llui/llchat.h b/indra/llui/llchat.h index 5f75ed2f8d..8adb3a87ef 100644 --- a/indra/llui/llchat.h +++ b/indra/llui/llchat.h @@ -89,7 +89,8 @@ public: mPosAgent(), mURL(), mChatStyle(CHAT_STYLE_NORMAL), - mSessionID() + mSessionID(), + mIsScript(false) { } std::string mText; // UTF-8 line of text @@ -107,6 +108,22 @@ public: std::string mURL; EChatStyle mChatStyle; LLUUID mSessionID; + + bool mIsScript; }; +static const std::string LUA_PREFIX("[LUA]"); + +inline +std::string without_LUA_PREFIX(const std::string& string, bool is_lua) +{ + if (is_lua) + { + return string.substr(LUA_PREFIX.size()); + } + else + { + return string; + } +} #endif diff --git a/indra/llui/llcommandmanager.cpp b/indra/llui/llcommandmanager.cpp index 03717da80b..812a360190 100644 --- a/indra/llui/llcommandmanager.cpp +++ b/indra/llui/llcommandmanager.cpp @@ -32,6 +32,7 @@ #include "llcommandmanager.h" #include "lldir.h" #include "llerror.h" +#include "llsdutil.h" #include "llxuiparser.h" @@ -189,3 +190,8 @@ bool LLCommandManager::load() return true; } + +LLSD LLCommandManager::getCommandNames() +{ + return llsd::toArray(mCommands, [](const auto &cmd) { return cmd->name(); }); + } diff --git a/indra/llui/llcommandmanager.h b/indra/llui/llcommandmanager.h index e6df0d3a4b..69d631a398 100644 --- a/indra/llui/llcommandmanager.h +++ b/indra/llui/llcommandmanager.h @@ -192,6 +192,8 @@ public: LLCommand * getCommand(const LLCommandId& commandId); LLCommand * getCommand(const std::string& name); + LLSD getCommandNames(); + static bool load(); protected: diff --git a/indra/llui/llflashtimer.cpp b/indra/llui/llflashtimer.cpp index c3db24c987..2711e8088d 100644 --- a/indra/llui/llflashtimer.cpp +++ b/indra/llui/llflashtimer.cpp @@ -35,7 +35,7 @@ LLFlashTimer::LLFlashTimer(callback_t cb, S32 count, F32 period) mIsCurrentlyHighlighted(false), mUnset(false) { - mEventTimer.stop(); + stop(); // By default use settings from settings.xml to be able change them via Debug settings. See EXT-5973. // Due to Timer is implemented as derived class from EventTimer it is impossible to change period @@ -74,12 +74,12 @@ void LLFlashTimer::startFlashing() { mIsFlashingInProgress = true; mIsCurrentlyHighlighted = true; - mEventTimer.start(); + start(); } void LLFlashTimer::stopFlashing() { - mEventTimer.stop(); + stop(); mIsFlashingInProgress = false; mIsCurrentlyHighlighted = false; mCurrentTickCount = 0; diff --git a/indra/llui/llflashtimer.h b/indra/llui/llflashtimer.h index b55ce53fc0..988b577ed2 100644 --- a/indra/llui/llflashtimer.h +++ b/indra/llui/llflashtimer.h @@ -46,7 +46,7 @@ public: LLFlashTimer(callback_t cb = NULL, S32 count = 0, F32 period = 0.0); ~LLFlashTimer() {}; - /*virtual*/ bool tick(); + bool tick() override; void startFlashing(); void stopFlashing(); diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index a818e72f59..c4e6061a12 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -624,3 +624,8 @@ U32 LLFloaterReg::getVisibleFloaterInstanceCount() return count; } + +LLSD LLFloaterReg::getFloaterNames() +{ + return llsd::toArray(sGroupMap, [](const auto &pair) { return pair.first; }); +} diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h index 94a67c8d8b..2873080c99 100644 --- a/indra/llui/llfloaterreg.h +++ b/indra/llui/llfloaterreg.h @@ -153,6 +153,8 @@ public: static void blockShowFloaters(bool value) { sBlockShowFloaters = value;} static U32 getVisibleFloaterInstanceCount(); + + static LLSD getFloaterNames(); }; #endif diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp index 17641b8375..6e5f048c27 100644 --- a/indra/llui/llfloaterreglistener.cpp +++ b/indra/llui/llfloaterreglistener.cpp @@ -37,6 +37,8 @@ #include "llfloaterreg.h" #include "llfloater.h" #include "llbutton.h" +#include "llluafloater.h" +#include "resultset.h" LLFloaterRegListener::LLFloaterRegListener(): LLEventAPI("LLFloaterReg", @@ -72,6 +74,18 @@ LLFloaterRegListener::LLFloaterRegListener(): "Simulate clicking the named [\"button\"] in the visible floater named in [\"name\"]", &LLFloaterRegListener::clickButton, requiredNameButton); + + add("showLuaFloater", + "Open the new floater using XML file specified in [\"xml_path\"] with ID in [\"reqid\"]", + &LLLuaFloater::showLuaFloater, {llsd::map("xml_path", LLSD(), "reqid", LLSD())}); + add("getFloaterEvents", + "Return the table of Lua Floater events which are send to the script", + &LLFloaterRegListener::getLuaFloaterEvents); + + add("getFloaterNames", + "Return result set key [\"floaters\"] for names of all registered floaters", + &LLFloaterRegListener::getFloaterNames, + llsd::map("reply", LLSD::String())); } void LLFloaterRegListener::getBuildMap(const LLSD& event) const @@ -113,6 +127,24 @@ void LLFloaterRegListener::instanceVisible(const LLSD& event) const event); } +struct NameResultSet: public LL::ResultSet +{ + NameResultSet(): + LL::ResultSet("floaters"), + mNames(LLFloaterReg::getFloaterNames()) + {} + LLSD mNames; + + int getLength() const override { return narrow(mNames.size()); } + LLSD getSingle(int index) const override { return mNames[index]; } +}; + +void LLFloaterRegListener::getFloaterNames(const LLSD &event) const +{ + auto nameresult = new NameResultSet; + sendReply(llsd::map("floaters", nameresult->getKeyLength()), event); +} + void LLFloaterRegListener::clickButton(const LLSD& event) const { // If the caller requests a reply, build the reply. @@ -154,3 +186,8 @@ void LLFloaterRegListener::clickButton(const LLSD& event) const LLEventPumps::instance().obtain(replyPump).post(reply); } } + +void LLFloaterRegListener::getLuaFloaterEvents(const LLSD &event) const +{ + Response response(llsd::map("events", LLLuaFloater::getEventsData()), event); +} diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h index a36072892c..42e7178cbc 100644 --- a/indra/llui/llfloaterreglistener.h +++ b/indra/llui/llfloaterreglistener.h @@ -49,6 +49,9 @@ private: void toggleInstance(const LLSD& event) const; void instanceVisible(const LLSD& event) const; void clickButton(const LLSD& event) const; + void getFloaterNames(const LLSD &event) const; + + void getLuaFloaterEvents(const LLSD &event) const; }; #endif /* ! defined(LL_LLFLOATERREGLISTENER_H) */ diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp new file mode 100644 index 0000000000..ccdadc6ae0 --- /dev/null +++ b/indra/llui/llluafloater.cpp @@ -0,0 +1,324 @@ +/** + * @file llluafloater.cpp + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, 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 "llluafloater.h" + +#include "fsyspath.h" +#include "llevents.h" + +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llscrolllistctrl.h" +#include "lltexteditor.h" + +const std::string LISTENER_NAME("LLLuaFloater"); + +std::set<std::string> EVENT_LIST = { + "commit", + "double_click", + "mouse_enter", + "mouse_leave", + "mouse_down", + "mouse_up", + "right_mouse_down", + "right_mouse_up", + "post_build", + "floater_close", + "keystroke" +}; + +LLLuaFloater::LLLuaFloater(const LLSD &key) : + LLFloater(key), + mDispatchListener(LLUUID::generateNewID().asString(), "action"), + mReplyPumpName(key["reply"].asString()), + mReqID(key) +{ + auto ctrl_lookup = [this](const LLSD &event, std::function<LLSD(LLUICtrl*,const LLSD&)> cb) + { + LLUICtrl *ctrl = getChild<LLUICtrl>(event["ctrl_name"].asString()); + if (!ctrl) + { + LL_WARNS("LuaFloater") << "Control not found: " << event["ctrl_name"] << LL_ENDL; + return LLSD(); + } + return cb(ctrl, event); + }; + + LLSD requiredParams = llsd::map("ctrl_name", LLSD(), "value", LLSD()); + mDispatchListener.add("set_enabled", "", [ctrl_lookup](const LLSD &event) + { + return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { ctrl->setEnabled(event["value"].asBoolean()); return LLSD(); }); + }, requiredParams); + mDispatchListener.add("set_visible", "", [ctrl_lookup](const LLSD &event) + { + return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { ctrl->setVisible(event["value"].asBoolean()); return LLSD(); }); + }, requiredParams); + mDispatchListener.add("set_value", "", [ctrl_lookup](const LLSD &event) + { + return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { ctrl->setValue(event["value"]); return LLSD(); }); + }, requiredParams); + + mDispatchListener.add("add_list_element", "", [this](const LLSD &event) + { + LLScrollListCtrl *ctrl = getChild<LLScrollListCtrl>(event["ctrl_name"].asString()); + if(ctrl) + { + LLSD element_data = event["value"]; + if (element_data.isArray()) + { + for (const auto &row : llsd::inArray(element_data)) + { + ctrl->addElement(row); + } + } + else + { + ctrl->addElement(element_data); + } + } + }, requiredParams); + + mDispatchListener.add("clear_list", "", [this](const LLSD &event) + { + LLScrollListCtrl *ctrl = getChild<LLScrollListCtrl>(event["ctrl_name"].asString()); + if(ctrl) + { + ctrl->deleteAllItems(); + } + }, llsd::map("ctrl_name", LLSD())); + + mDispatchListener.add("add_text", "", [this](const LLSD &event) + { + LLTextEditor *editor = getChild<LLTextEditor>(event["ctrl_name"].asString()); + if (editor) + { + editor->pasteTextWithLinebreaks(stringize(event["value"])); + editor->addLineBreakChar(true); + } + }, requiredParams); + + mDispatchListener.add("set_label", "", [this](const LLSD &event) + { + LLButton *btn = getChild<LLButton>(event["ctrl_name"].asString()); + if (btn) + { + btn->setLabel((event["value"]).asString()); + } + }, requiredParams); + + mDispatchListener.add("set_title", "", [this](const LLSD &event) + { + setTitle(event["value"].asString()); + }, llsd::map("value", LLSD())); + + mDispatchListener.add("get_value", "", [ctrl_lookup](const LLSD &event) + { + return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { return llsd::map("value", ctrl->getValue()); }); + }, llsd::map("ctrl_name", LLSD(), "reqid", LLSD())); + + mDispatchListener.add("get_selected_id", "", [this](const LLSD &event) + { + LLScrollListCtrl *ctrl = getChild<LLScrollListCtrl>(event["ctrl_name"].asString()); + if (!ctrl) + { + LL_WARNS("LuaFloater") << "Control not found: " << event["ctrl_name"] << LL_ENDL; + return LLSD(); + } + return llsd::map("value", ctrl->getCurrentID()); + }, llsd::map("ctrl_name", LLSD(), "reqid", LLSD())); +} + +LLLuaFloater::~LLLuaFloater() +{ + //post empty LLSD() to indicate done, in case it wasn't handled by the script after CLOSE_EVENT + post(LLSD()); +} + +bool LLLuaFloater::postBuild() +{ + for (LLView *view : *getChildList()) + { + LLUICtrl *ctrl = dynamic_cast<LLUICtrl*>(view); + if (ctrl) + { + LLSD data; + data["ctrl_name"] = view->getName(); + + ctrl->setCommitCallback([this, data](LLUICtrl *ctrl, const LLSD ¶m) + { + LLSD event(data); + event["value"] = ctrl->getValue(); + postEvent(event, "commit"); + }); + } + } + + //optional field to send additional specified events to the script + if (mKey.has("extra_events")) + { + //the first value is ctrl name, the second contains array of events to send + for (const auto &[name, data] : llsd::inMap(mKey["extra_events"])) + { + for (const auto &event : llsd::inArray(data)) + { + registerCallback(name, event); + } + } + } + + //send pump name to the script after the floater is built + postEvent(llsd::map("command_name", mDispatchListener.getPumpName()), "post_build"); + + return true; +} + +void LLLuaFloater::onClose(bool app_quitting) +{ + postEvent(llsd::map("app_quitting", app_quitting), "floater_close"); +} + +bool event_is(const std::string &event_name, const std::string &list_event) +{ + llassert(EVENT_LIST.find(list_event) != EVENT_LIST.end()); + return (event_name == list_event); +} + +void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::string &event) +{ + LLUICtrl *ctrl = getChild<LLUICtrl>(ctrl_name); + if (!ctrl) return; + + LLSD data; + data["ctrl_name"] = ctrl_name; + data["event"] = event; + + auto mouse_event_cb = [this, data](LLUICtrl *ctrl, const LLSD ¶m) { post(data); }; + + auto mouse_event_coords_cb = [this, data](LLUICtrl *ctrl, S32 x, S32 y, MASK mask) + { + LLSD event(data); + post(event.with("x", x).with("y", y)); + }; + + auto post_with_value = [this, data](LLSD value) + { + LLSD event(data); + post(event.with("value", value)); + }; + + if (event_is(event, "mouse_enter")) + { + ctrl->setMouseEnterCallback(mouse_event_cb); + } + else if (event_is(event, "mouse_leave")) + { + ctrl->setMouseLeaveCallback(mouse_event_cb); + } + else if (event_is(event, "mouse_down")) + { + ctrl->setMouseDownCallback(mouse_event_coords_cb); + } + else if (event_is(event, "mouse_up")) + { + ctrl->setMouseUpCallback(mouse_event_coords_cb); + } + else if (event_is(event, "right_mouse_down")) + { + ctrl->setRightMouseDownCallback(mouse_event_coords_cb); + } + else if (event_is(event, "right_mouse_up")) + { + ctrl->setRightMouseUpCallback(mouse_event_coords_cb); + } + else if (event_is(event, "double_click")) + { + LLScrollListCtrl *list = dynamic_cast<LLScrollListCtrl *>(ctrl); + if (list) + { + list->setDoubleClickCallback( [post_with_value, list](){ post_with_value(LLSD(list->getCurrentID())); }); + } + else + { + ctrl->setDoubleClickCallback(mouse_event_coords_cb); + } + } + else if (event_is(event, "keystroke")) + { + LLTextEditor* text_editor = dynamic_cast<LLTextEditor*>(ctrl); + if (text_editor) + { + text_editor->setKeystrokeCallback([post_with_value](LLTextEditor *editor) { post_with_value(editor->getValue()); }); + } + LLLineEditor* line_editor = dynamic_cast<LLLineEditor*>(ctrl); + if (line_editor) + { + line_editor->setKeystrokeCallback([post_with_value](LLLineEditor *editor, void* userdata) { post_with_value(editor->getValue()); }, NULL); + } + } + else + { + LL_WARNS("LuaFloater") << "Can't register callback for unknown event: " << event << " , control: " << ctrl_name << LL_ENDL; + } +} + +void LLLuaFloater::post(const LLSD &data) +{ + // send event data to the script signed with ["reqid"] key + LLSD stamped_data(data); + mReqID.stamp(stamped_data); + LLEventPumps::instance().obtain(mReplyPumpName).post(stamped_data); +} + +void LLLuaFloater::postEvent(LLSD data, const std::string &event_name) +{ + llassert(EVENT_LIST.find(event_name) != EVENT_LIST.end()); + post(data.with("event", event_name)); +} + +void LLLuaFloater::showLuaFloater(const LLSD &data) +{ + fsyspath fs_path(data["xml_path"].asString()); + std::string path = fs_path.lexically_normal().u8string(); + if (!fs_path.is_absolute()) + { + std::string lib_path = gDirUtilp->getExpandedFilename(LL_PATH_SCRIPTS, "lua"); + path = (fsyspath(lib_path) / path).u8string(); + } + + LLLuaFloater *floater = new LLLuaFloater(data); + floater->buildFromFile(path); + floater->openFloater(floater->getKey()); +} + +LLSD LLLuaFloater::getEventsData() +{ + LLSD event_data; + for (auto &it : EVENT_LIST) + { + event_data.append(it); + } + return event_data; +} diff --git a/indra/llui/llluafloater.h b/indra/llui/llluafloater.h new file mode 100644 index 0000000000..41132f926d --- /dev/null +++ b/indra/llui/llluafloater.h @@ -0,0 +1,54 @@ +/** + * @file llluafloater.h + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, 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_LLLUAFLOATER_H +#define LL_LLLUAFLOATER_H + +#include "llfloater.h" +#include "lleventdispatcher.h" +#include "llevents.h" + +class LLLuaFloater : public LLFloater +{ +public: + LLLuaFloater(const LLSD &key); + bool postBuild(); + virtual ~LLLuaFloater(); + + void registerCallback(const std::string &ctrl_name, const std::string &event); + void onClose(bool app_quitting); + + void post(const LLSD &data); + void postEvent(LLSD data, const std::string &event); + static void showLuaFloater(const LLSD &data); + static LLSD getEventsData(); + +private: + LLReqID mReqID; + LLDispatchListener mDispatchListener; + + std::string mReplyPumpName; +}; +#endif diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 69ffa9a94f..cc770ca90a 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -2625,7 +2625,9 @@ void LLMenuGL::insert( S32 position, LLView * ctrl, bool arrange /*= true*/ ) { LLMenuItemGL * item = dynamic_cast<LLMenuItemGL *>(ctrl); - if (NULL == item || position < 0 || position >= mItems.size()) + // If position == size(), std::advance() will return end() -- which is + // okay, because insert(end()) is the same as append(). + if (NULL == item || position < 0 || position > mItems.size()) { return; } diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 66f84393fe..88608b20ab 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -562,9 +562,6 @@ public: // add a context menu branch bool appendContextSubMenu(LLMenuGL *menu); - const LLFontGL *getFont() const { return mFont; } - - protected: void createSpilloverBranch(); void cleanupSpilloverBranch(); // Add the menu item to this menu. @@ -810,9 +807,10 @@ public: void resetMenuTrigger() { mAltKeyTrigger = false; } -private: // add a menu - this will create a drop down menu. - virtual bool appendMenu( LLMenuGL* menu ); + virtual bool appendMenu(LLMenuGL *menu); + +private: // rearrange the child rects so they fit the shape of the menu // bar. virtual void arrange( void ); @@ -948,16 +946,18 @@ public: LLUICtrl::EnableCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); } - static void addCommit(view_listener_t* listener, const std::string& name) + typedef LLUICtrl::CommitCallbackInfo cb_info; + static void addCommit(view_listener_t *listener, const std::string &name, cb_info::EUntrustedCall handle_untrusted = cb_info::UNTRUSTED_ALLOW) { - LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, + cb_info([listener](LLUICtrl*, const LLSD& param){ return listener->handleEvent(param); }, handle_untrusted)); } - static void addMenu(view_listener_t* listener, const std::string& name) + static void addMenu(view_listener_t *listener, const std::string &name, cb_info::EUntrustedCall handle_untrusted = cb_info::UNTRUSTED_ALLOW) { // For now, add to both click and enable registries addEnable(listener, name); - addCommit(listener, name); + addCommit(listener, name, handle_untrusted); } static void cleanup() diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index cd80e7f63f..501ac26f9f 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -1243,7 +1243,7 @@ LLNotifications::LLNotifications() mIgnoreAllNotifications(false) { mListener.reset(new LLNotificationsListener(*this)); - LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2)); + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", { boost::bind(&LLNotifications::addFromCallback, this, _2) }); // touch the instance tracker for notification channels, so that it will still be around in our destructor LLInstanceTracker<LLNotificationChannel, std::string>::instanceCount(); diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 46286457cf..9b83da13ad 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -735,7 +735,7 @@ typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap; // all of the built-in tests should attach to the "Visible" channel // class LLNotificationChannelBase : - public LLEventTrackable, + public boost::signals2::trackable, public LLRefCount { LOG_CLASS(LLNotificationChannelBase); diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp index 9c1fc27c51..dc12834b3f 100644 --- a/indra/llui/llnotificationslistener.cpp +++ b/indra/llui/llnotificationslistener.cpp @@ -204,7 +204,7 @@ void LLNotificationsListener::ignore(const LLSD& params) const } } -class LLNotificationsListener::Forwarder: public LLEventTrackable +class LLNotificationsListener::Forwarder: public boost::signals2::trackable { LOG_CLASS(LLNotificationsListener::Forwarder); public: @@ -213,8 +213,10 @@ public: mRespond(false) { // Connect to the specified channel on construction. Because - // LLEventTrackable is a base, we should automatically disconnect when - // destroyed. + // boost::signals2::trackable is a base, because we use boost::bind() + // below, and because connectPassedFilter() directly calls + // boost::signals2::signal::connect(), we should automatically + // disconnect when destroyed. LLNotificationChannelPtr channelptr(llnotifications.getChannel(channel)); if (channelptr) { @@ -252,10 +254,10 @@ void LLNotificationsListener::forward(const LLSD& params) if (! forward) { // This is a request to stop forwarding notifications on the specified - // channel. The rest of the params don't matter. - // Because mForwarders contains scoped_ptrs, erasing the map entry - // DOES delete the heap Forwarder object. Because Forwarder derives - // from LLEventTrackable, destroying it disconnects it from the + // channel. The rest of the params don't matter. Because mForwarders + // contains scoped_ptrs, erasing the map entry DOES delete the heap + // Forwarder object. Because Forwarder derives from + // boost::signals2::trackable, destroying it disconnects it from the // channel. mForwarders.erase(channel); return; diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 445377d3a2..ea2caaa1c0 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1975,7 +1975,7 @@ bool LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) // set up the callbacks for all of the avatar/group menu items // (N.B. callbacks don't take const refs as id is local scope) bool is_group = (mContextMenuType == MENU_GROUP); - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + ScopedRegistrarHelper registrar; registrar.add("Url.ShowProfile", boost::bind(&LLScrollListCtrl::showProfile, id, is_group)); registrar.add("Url.SendIM", boost::bind(&LLScrollListCtrl::sendIM, id)); registrar.add("Url.AddFriend", boost::bind(&LLScrollListCtrl::addFriend, id)); diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index e2d31085c4..32fafe3c52 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -2091,7 +2091,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) // set up the callbacks for all of the potential menu items, N.B. we // don't use const ref strings in callbacks in case url goes out of scope - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + CommitRegistrarHelper registrar(LLUICtrl::CommitCallbackRegistry::currentRegistrar()); registrar.add("Url.Open", boost::bind(&LLUrlAction::openURL, url)); registrar.add("Url.OpenInternal", boost::bind(&LLUrlAction::openURLInternal, url)); registrar.add("Url.OpenExternal", boost::bind(&LLUrlAction::openURLExternal, url)); diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 3537c764b9..c8cde90032 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1131,7 +1131,7 @@ void LLTextEditor::removeChar() // Add a single character to the text S32 LLTextEditor::addChar(S32 pos, llwchar wc) { - if ((wstring_utf8_length(getWText()) + wchar_utf8_length(wc)) > mMaxTextByteLength) + if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) > mMaxTextByteLength) { LLUI::getInstance()->reportBadKeystroke(); return 0; @@ -1166,12 +1166,12 @@ S32 LLTextEditor::addChar(S32 pos, llwchar wc) void LLTextEditor::addChar(llwchar wc) { - if (!getEnabled()) + if( !getEnabled() ) { return; } - if (hasSelection()) + if( hasSelection() ) { deleteSelection(true); } @@ -1595,7 +1595,8 @@ void LLTextEditor::cleanStringForPaste(LLWString & clean_string) } -void LLTextEditor::pasteTextWithLinebreaks(LLWString & clean_string) +template <> +void LLTextEditor::pasteTextWithLinebreaks<LLWString>(const LLWString & clean_string) { std::basic_string<llwchar>::size_type start = 0; std::basic_string<llwchar>::size_type pos = clean_string.find('\n',start); diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index e9e7070414..765c88a933 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -34,6 +34,7 @@ #include "llstyle.h" #include "lleditmenuhandler.h" #include "llviewborder.h" // for params +#include "llstring.h" #include "lltextbase.h" #include "lltextvalidate.h" @@ -249,7 +250,9 @@ protected: // Undoable operations void addChar(llwchar c); // at mCursorPos S32 addChar(S32 pos, llwchar wc); +public: void addLineBreakChar(bool group_together = false); +protected: S32 overwriteChar(S32 pos, llwchar wc); void removeChar(); S32 removeChar(S32 pos); @@ -305,8 +308,17 @@ private: // void pasteHelper(bool is_primary); void cleanStringForPaste(LLWString & clean_string); - void pasteTextWithLinebreaks(LLWString & clean_string); +public: + template <typename STRINGTYPE> + void pasteTextWithLinebreaks(const STRINGTYPE& clean_string) + { + pasteTextWithLinebreaks<LLWString>(ll_convert(clean_string)); + } + template <> + void pasteTextWithLinebreaks<LLWString>(const LLWString & clean_string); + +private: void onKeyStroke(); // Concrete TextCmd sub-classes used by the LLTextEditor base class diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp index 9a087d8230..84f8b9daf0 100644 --- a/indra/llui/lltextvalidate.cpp +++ b/indra/llui/lltextvalidate.cpp @@ -31,6 +31,7 @@ #include "lltextvalidate.h" #include "llnotificationsutil.h" +#include "lltimer.h" #include "lltrans.h" #include "llresmgr.h" // for LLLocale diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index 5955a28fa3..6e6e332632 100644 --- a/indra/llui/lltoolbar.cpp +++ b/indra/llui/lltoolbar.cpp @@ -144,7 +144,7 @@ void LLToolBar::createContextMenu() { // Setup bindings specific to this instance for the context menu options - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar commit_reg; + CommitRegistrarHelper commit_reg(LLUICtrl::CommitCallbackRegistry::currentRegistrar()); commit_reg.add("Toolbars.EnableSetting", boost::bind(&LLToolBar::onSettingEnable, this, _2)); commit_reg.add("Toolbars.RemoveSelectedCommand", boost::bind(&LLToolBar::onRemoveSelectedCommand, this)); diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index e36dae3955..b4299ae8e5 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -169,8 +169,7 @@ mHelpImpl(NULL) LLFontGL::sShadowColor = LLUIColorTable::instance().getColor("ColorDropShadow"); - LLUICtrl::CommitCallbackRegistry::Registrar& reg = LLUICtrl::CommitCallbackRegistry::defaultRegistrar(); - + LLUICtrl::CommitRegistrarHelper reg(LLUICtrl::CommitCallbackRegistry::defaultRegistrar()); // Callbacks for associating controls with floater visibility: reg.add("Floater.Toggle", [](LLUICtrl* ctrl, const LLSD& param) -> void { LLFloaterReg::toggleInstance(param.asStringRef()); }); reg.add("Floater.ToggleOrBringToFront", [](LLUICtrl* ctrl, const LLSD& param) -> void { LLFloaterReg::toggleInstanceOrBringToFront(param.asStringRef()); }); diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index cbabb5a933..e3e8130f51 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -220,10 +220,10 @@ void LLUICtrl::initFromParams(const Params& p) } else { - commit_callback_t* initfunc = (CommitCallbackRegistry::getValue(p.init_callback.function_name)); - if (initfunc) + LLUICtrl::CommitCallbackInfo *info = (CommitCallbackRegistry::getValue(p.init_callback.function_name)); + if (info && info->callback_func) { - (*initfunc)(this, p.init_callback.parameter); + (info->callback_func)(this, p.init_callback.parameter); } } } @@ -283,13 +283,13 @@ LLUICtrl::commit_signal_t::slot_type LLUICtrl::initCommitCallback(const CommitCa { std::string function_name = cb.function_name; setFunctionName(function_name); - commit_callback_t* func = (CommitCallbackRegistry::getValue(function_name)); - if (func) + LLUICtrl::CommitCallbackInfo *info = (CommitCallbackRegistry::getValue(function_name)); + if (info && info->callback_func) { if (cb.parameter.isProvided()) - return boost::bind((*func), _1, cb.parameter); + return boost::bind((info->callback_func), _1, cb.parameter); else - return commit_signal_t::slot_type(*func); + return commit_signal_t::slot_type(info->callback_func); } else if (!function_name.empty()) { diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 8cd9950917..2c73ff6b57 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -274,11 +274,56 @@ public: template <typename F, typename DERIVED> class CallbackRegistry : public LLRegistrySingleton<std::string, F, DERIVED > {}; + struct CommitCallbackInfo + { + enum EUntrustedCall + { + UNTRUSTED_ALLOW, + UNTRUSTED_BLOCK, + UNTRUSTED_THROTTLE + }; + + CommitCallbackInfo(commit_callback_t func = {}, EUntrustedCall handle_untrusted = UNTRUSTED_ALLOW) : + callback_func(func), + handle_untrusted(handle_untrusted) + { + } - class CommitCallbackRegistry : public CallbackRegistry<commit_callback_t, CommitCallbackRegistry> + public: + commit_callback_t callback_func; + EUntrustedCall handle_untrusted; + }; + typedef LLUICtrl::CommitCallbackInfo cb_info; + class CommitCallbackRegistry : public CallbackRegistry<CommitCallbackInfo, CommitCallbackRegistry> { LLSINGLETON_EMPTY_CTOR(CommitCallbackRegistry); }; + + class CommitRegistrarHelper + { + public: + CommitRegistrarHelper(LLUICtrl::CommitCallbackRegistry::Registrar ®istrar) : mRegistrar(registrar) {} + + template <typename... ARGS> void add(const std::string &name, ARGS &&...args) + { + mRegistrar.add(name, {std::forward<ARGS>(args)...}); + } + private: + LLUICtrl::CommitCallbackRegistry::Registrar &mRegistrar; + }; + + class ScopedRegistrarHelper + { + public: + template <typename... ARGS> void add(const std::string &name, ARGS &&...args) + { + mRegistrar.add(name, {std::forward<ARGS>(args)...}); + } + + private: + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar mRegistrar; + }; + // the enable callback registry is also used for visiblity callbacks class EnableCallbackRegistry : public CallbackRegistry<enable_callback_t, EnableCallbackRegistry> { |