From e3ba75101a94cff9b1409c58f796587cf2702f10 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 21 Sep 2023 14:41:00 +0300 Subject: DRTVWR-589 - adding menu items to the top menu --- indra/llui/llmenugl.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 9d3be8d94f..1a330b18cc 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -555,11 +555,12 @@ public: // add a context menu branch BOOL appendContextSubMenu(LLMenuGL *menu); + // Add the menu item to this menu. + virtual BOOL append( LLMenuItemGL* item ); + protected: void createSpilloverBranch(); void cleanupSpilloverBranch(); - // Add the menu item to this menu. - virtual BOOL append( LLMenuItemGL* item ); // add a menu - this will create a cascading menu virtual BOOL appendMenu( LLMenuGL* menu ); @@ -798,9 +799,10 @@ public: void resetMenuTrigger() { mAltKeyTrigger = FALSE; } + // add a menu - this will create a drop down menu. + virtual BOOL appendMenu(LLMenuGL *menu); + private: - // add a menu - this will create a drop down menu. - virtual BOOL appendMenu( LLMenuGL* menu ); // rearrange the child rects so they fit the shape of the menu // bar. virtual void arrange( void ); -- cgit v1.2.3 From fac31ad392c3df22b2254a00e75c841050195763 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 21 Sep 2023 16:16:00 +0300 Subject: DRTVWR-589 - allow adding branch to the menu --- indra/llui/llmenugl.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 1a330b18cc..4f1098b1d8 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -558,13 +558,13 @@ public: // Add the menu item to this menu. virtual BOOL append( LLMenuItemGL* item ); + // add a menu - this will create a cascading menu + virtual BOOL appendMenu(LLMenuGL *menu); + protected: void createSpilloverBranch(); void cleanupSpilloverBranch(); - // add a menu - this will create a cascading menu - virtual BOOL appendMenu( LLMenuGL* menu ); - // Used in LLContextMenu and in LLTogleableMenu // to add an item of context menu branch bool addContextChild(LLView* view, S32 tab_group); -- cgit v1.2.3 From de61551df3219dae2238591bae5fa7b6c857e6b0 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Sat, 30 Sep 2023 11:51:09 -0400 Subject: DRTVWR-589: Emulate print() better, show output on Lua floater. Break out a lua_print_msg() function common to print_debug(), print_info() and print_warning(). Instead of accepting a single argument, lua_print_msg() accepts arbitrary arguments, passing each to the Lua tostring() function and concatenating the results. In addition to returning the combined string to its caller for level-appropriate logging, it also posts the message to a "lua output" LLEventPump for any interested party. Make LLFloaterLUADebug listen on "lua output" when the floater is constructed, storing the connection in an LLTempBoundListener to stop listening when the floater is destroyed. Append each message to the floater's output panel with a line break. Make LLTextEditor::addLineBreakChar() public. insertText("\n") only appends a little rectangle glyph. Enlarge the text capacity of the floater's output panel to be able to report whatever messages a Lua script wants to print. Add diagnostic logging for posting events from Lua, and receiving events to forward to Lua. Since lua_pop() is a macro implemented on lua_settop(), replace the awkward construct lua_pop(L, lua_gettop(L)) with lua_settop(L, 0). Use lambdas instead of std::bind() to connect LuaListener and LLLeapListener. --- indra/llui/lltexteditor.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra/llui') diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index f3939248c2..ec2b9a4b7d 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -241,7 +241,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); -- cgit v1.2.3 From b4583fac09657cb64ed02e82e12ce69c4ace225d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 12 Feb 2024 17:10:42 -0500 Subject: WIP: Changes towards supporting Lua console help text. --- indra/llui/lltexteditor.cpp | 2 +- indra/llui/lltexteditor.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 3d2a426913..99154bab83 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1504,7 +1504,7 @@ void LLTextEditor::cleanStringForPaste(LLWString & clean_string) } -void LLTextEditor::pasteTextWithLinebreaks(LLWString & clean_string) +void LLTextEditor::pasteTextWithLinebreaks(const LLWString & clean_string) { std::basic_string::size_type start = 0; std::basic_string::size_type pos = clean_string.find('\n',start); diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index ec2b9a4b7d..6cc2c32d4e 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -289,6 +289,8 @@ protected: void updateLinkSegments(); void keepSelectionOnReturn(bool keep) { mKeepSelectionOnReturn = keep; } class LLViewBorder* mBorder; + void pasteTextWithLinebreaks(const LLWString & clean_string); +// void pasteTextWithLinebreaks(const std::string & clean_string); private: // @@ -296,7 +298,6 @@ private: // void pasteHelper(bool is_primary); void cleanStringForPaste(LLWString & clean_string); - void pasteTextWithLinebreaks(LLWString & clean_string); void onKeyStroke(); -- cgit v1.2.3 From 3044a6e62e628fdb3c4b8832fd23e566216d7bb9 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 13 Feb 2024 12:24:13 -0500 Subject: Add help() function to Lua "builtins." help() with no argument lists all our viewer builtins. help(function, function, ...) shows help text for each named function. Each argument can be either a string or the function in question (e.g. help(help)). To support Lua-related text containing line breaks, make LLTextEditor:: pasteTextWithLinebreaks() a public template method. Change the existing implementation, which specifically accepts (const LLWString&), into its LLWString specialization. The generic template passes llconvert(arg) to that specialization, the one real implementation. Make LLFloaterLUADebug methods call pasteTextWithLinebreaks() instead of insertText(), which ignores newline characters. To allow help() to accept an actual function as well as a string name, add a lookup-by-function-pointer map to LuaFunction. (A Lua function does not store a name.) Make the constructor store an entry in the new lookup map as well as in the original registry map. Change LuaFunction::getRegistry() and getRegistered() to getState() and getRState(), respectively. Each returns a std::pair, but the first binds non-const references while the second binds const references. --- indra/llui/lltexteditor.cpp | 3 ++- indra/llui/lltexteditor.h | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 99154bab83..ccd04f83e7 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1504,7 +1504,8 @@ void LLTextEditor::cleanStringForPaste(LLWString & clean_string) } -void LLTextEditor::pasteTextWithLinebreaks(const LLWString & clean_string) +template <> +void LLTextEditor::pasteTextWithLinebreaks(const LLWString & clean_string) { std::basic_string::size_type start = 0; std::basic_string::size_type pos = clean_string.find('\n',start); diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 6cc2c32d4e..01b5ce5fbd 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" @@ -289,16 +290,24 @@ protected: void updateLinkSegments(); void keepSelectionOnReturn(bool keep) { mKeepSelectionOnReturn = keep; } class LLViewBorder* mBorder; - void pasteTextWithLinebreaks(const LLWString & clean_string); -// void pasteTextWithLinebreaks(const std::string & clean_string); private: // // Methods // - void pasteHelper(bool is_primary); + void pasteHelper(bool is_primary); void cleanStringForPaste(LLWString & clean_string); +public: + template + void pasteTextWithLinebreaks(const STRINGTYPE& clean_string) + { + pasteTextWithLinebreaks(ll_convert(clean_string)); + } + template <> + void pasteTextWithLinebreaks(const LLWString & clean_string); + +private: void onKeyStroke(); // Concrete TextCmd sub-classes used by the LLTextEditor base class -- cgit v1.2.3 From 72d68cbc078cf2c1b9dc3ff81c2c1965f5d6f8c5 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 12 Mar 2024 16:48:49 +0200 Subject: Initial implementation of LLLuaFloater --- indra/llui/CMakeLists.txt | 2 + indra/llui/llfloater.cpp | 4 + indra/llui/llfloater.h | 3 + indra/llui/llfloaterreglistener.cpp | 15 ++++ indra/llui/llfloaterreglistener.h | 2 + indra/llui/llluafloater.cpp | 162 ++++++++++++++++++++++++++++++++++++ indra/llui/llluafloater.h | 52 ++++++++++++ 7 files changed, 240 insertions(+) create mode 100644 indra/llui/llluafloater.cpp create mode 100644 indra/llui/llluafloater.h (limited to 'indra/llui') 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/llfloater.cpp b/indra/llui/llfloater.cpp index de3de53569..b9b69b5a33 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -3623,6 +3623,10 @@ void LLFloater::applyRelativePosition() translate(new_center.mX - cur_center.mX, new_center.mY - cur_center.mY); } +bool LLFloater::isDefaultBtnName(const std::string& name) +{ + return (std::find(std::begin(sButtonNames), std::end(sButtonNames), name) != std::end(sButtonNames)); +} LLCoordFloater::LLCoordFloater(F32 x, F32 y, LLFloater& floater) : coord_t((S32)x, (S32)y) diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 88f9e77777..9d49c4538e 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -372,6 +372,9 @@ public: void enableResizeCtrls(bool enable, bool width = true, bool height = true); bool isPositioning(LLFloaterEnums::EOpenPositioning p) const { return (p == mPositioning); } + + static bool isDefaultBtnName(const std::string& name); + protected: void applyControlsAndPosition(LLFloater* other); diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp index 7525b8cab3..6fee688121 100644 --- a/indra/llui/llfloaterreglistener.cpp +++ b/indra/llui/llfloaterreglistener.cpp @@ -37,6 +37,7 @@ #include "llfloaterreg.h" #include "llfloater.h" #include "llbutton.h" +#include "llluafloater.h" LLFloaterRegListener::LLFloaterRegListener(): LLEventAPI("LLFloaterReg", @@ -72,6 +73,15 @@ LLFloaterRegListener::LLFloaterRegListener(): "Simulate clicking the named [\"button\"] in the visible floater named in [\"name\"]", &LLFloaterRegListener::clickButton, requiredNameButton); + + LLSD requiredParams; + requiredParams["xml_path"] = LLSD(); + requiredParams["command_pump"] = LLSD(); + requiredParams["reqid"] = LLSD(); + add("showLuaFloater", + "Open the new floater using XML file specified in [\"xml_path\"]" + "with ID in [\"reqid\"], which sends UI events to even pump specified in [\"command_pump\"]", + &LLFloaterRegListener::showLuaFloater, requiredParams); } void LLFloaterRegListener::getBuildMap(const LLSD& event) const @@ -154,3 +164,8 @@ void LLFloaterRegListener::clickButton(const LLSD& event) const LLEventPumps::instance().obtain(replyPump).post(reply); } } + +void LLFloaterRegListener::showLuaFloater(const LLSD &event) const +{ + LLLuaFloater::showLuaFloater(event); +} diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h index 24311a2dfa..2d58303aa0 100644 --- a/indra/llui/llfloaterreglistener.h +++ b/indra/llui/llfloaterreglistener.h @@ -49,6 +49,8 @@ private: void toggleInstance(const LLSD& event) const; void instanceVisible(const LLSD& event) const; void clickButton(const LLSD& event) const; + + void showLuaFloater(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..3507c907a0 --- /dev/null +++ b/indra/llui/llluafloater.cpp @@ -0,0 +1,162 @@ +/** + * @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 +#include "llevents.h" + +#include "llcheckboxctrl.h" +#include "llcombobox.h" + +const std::string LISTENER_NAME("LLLuaFloater"); + +LLLuaFloater::LLLuaFloater(const LLSD &key) : + LLFloater(key), + mCommandPumpName(key["command_pump"].asString()), + mDispatcher("LLLuaFloater", "action"), + mReqID(key) +{ + mListenerPumpName = LLUUID::generateNewID().asString(); + + mBoundListener = LLEventPumps::instance().obtain(mListenerPumpName).listen(LISTENER_NAME, [this](const LLSD &event) + { + if (event.has("action")) + { + mDispatcher.try_call(event); + } + else + { + LL_WARNS("LuaFloater") << "Unknown message: " << event << LL_ENDL; + } + return false; + }); + + LLSD requiredParams; + requiredParams["ctrl_name"] = LLSD(); + requiredParams["value"] = LLSD(); + mDispatcher.add("set_enabled", "", [this](const LLSD &event) + { + LLUICtrl *ctrl = getChild(event["ctrl_name"].asString()); + if(ctrl) + { + ctrl->setEnabled(event["value"].asBoolean()); + } + }, requiredParams); + mDispatcher.add("set_visible", "", [this](const LLSD &event) + { + LLUICtrl *ctrl = getChild(event["ctrl_name"].asString()); + if(ctrl) + { + ctrl->setVisible(event["value"].asBoolean()); + } + }, requiredParams); + mDispatcher.add("set_value", "", [this](const LLSD &event) + { + LLUICtrl *ctrl = getChild(event["ctrl_name"].asString()); + if(ctrl) + { + ctrl->setValue(event["value"]); + } + }, requiredParams); + + requiredParams = LLSD().with("value", LLSD()); + mDispatcher.add("set_title", "", [this](const LLSD &event) + { + setTitle(event["value"].asString()); + }); +} + +BOOL LLLuaFloater::postBuild() +{ + child_list_t::const_iterator iter = getChildList()->begin(); + child_list_t::const_iterator end = getChildList()->end(); + for (; iter != end; ++iter) + { + LLView *view = *iter; + if (!view) continue; + + LLSD data; + data["ctrl_name"] = view->getName(); + data["event"] = "click"; + + LLButton* btn = dynamic_cast(view); + if (btn && !isDefaultBtnName(btn->getName())) + { + data["ctrl_type"] = "LLButton"; + btn->setCommitCallback([this, data](LLUICtrl *ctrl, const LLSD ¶m) { post(data); }); + } + LLCheckBoxCtrl* check = dynamic_cast(view); + if (check) + { + data["ctrl_type"] = "LLCheckBoxCtrl"; + check->setCommitCallback([this, data](LLUICtrl *ctrl, const LLSD ¶m) + { + LLSD event(data); + event["value"] = ctrl->getValue(); + post(event); + }); + } + LLComboBox *combo = dynamic_cast(view); + if (combo) + { + data["ctrl_type"] = "LLComboBox"; + combo->setCommitCallback([this, data](LLUICtrl* ctrl, const LLSD ¶m) + { + LLSD event(data); + event["value"] = dynamic_cast(ctrl)->getValue(); + post(event); + }); + } + } + + post(LLSD().with("command_name", mListenerPumpName).with("event", "post_build")); + + return true; +} + +void LLLuaFloater::onClose(bool app_quitting) +{ + post(LLSD().with("event", "floater_close")); +} + +void LLLuaFloater::post(const LLSD &data) +{ + LLSD stamped_data(data); + mReqID.stamp(stamped_data); + LLEventPumps::instance().obtain(mCommandPumpName).post(stamped_data); +} + +void LLLuaFloater::showLuaFloater(const LLSD &data) +{ + std::filesystem::path fs_path(data["xml_path"].asString()); + + LLLuaFloater *floater = new LLLuaFloater(data); + floater->buildFromFile(fs_path.lexically_normal().string()); + floater->openFloater(floater->getKey()); +} + + diff --git a/indra/llui/llluafloater.h b/indra/llui/llluafloater.h new file mode 100644 index 0000000000..0b7e86746a --- /dev/null +++ b/indra/llui/llluafloater.h @@ -0,0 +1,52 @@ +/** + * @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(); + + void onClose(bool app_quitting); + + void post(const LLSD &data); + static void showLuaFloater(const LLSD &data); + +private: + LLReqID mReqID; + LLEventDispatcher mDispatcher; + LLTempBoundListener mBoundListener; + + std::string mListenerPumpName; + std::string mCommandPumpName; +}; +#endif -- cgit v1.2.3 From 45fcb914c89ff721833497bfb021b7583f24bd1c Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 14 Mar 2024 15:29:47 +0200 Subject: Send additional events to the script when specified --- indra/llui/llluafloater.cpp | 78 ++++++++++++++++++++++++++++++++++++++++++++- indra/llui/llluafloater.h | 1 + 2 files changed, 78 insertions(+), 1 deletion(-) (limited to 'indra/llui') diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp index 3507c907a0..5b50d85811 100644 --- a/indra/llui/llluafloater.cpp +++ b/indra/llui/llluafloater.cpp @@ -34,6 +34,15 @@ const std::string LISTENER_NAME("LLLuaFloater"); +const std::string COMMIT_EVENT("commit"); +const std::string MOUSE_ENTER_EVENT("mouse_enter"); +const std::string MOUSE_LEAVE_EVENT("mouse_leave"); +const std::string MOUSE_DOWN_EVENT("mouse_down"); +const std::string MOUSE_UP_EVENT("mouse_up"); +const std::string RIGHT_MOUSE_DOWN_EVENT("right_mouse_down"); +const std::string RIGHT_MOUSE_UP_EVENT("right_mouse_up"); +const std::string DOUBLE_CLICK_EVENT("double_click"); + LLLuaFloater::LLLuaFloater(const LLSD &key) : LLFloater(key), mCommandPumpName(key["command_pump"].asString()), @@ -101,7 +110,7 @@ BOOL LLLuaFloater::postBuild() LLSD data; data["ctrl_name"] = view->getName(); - data["event"] = "click"; + data["event"] = COMMIT_EVENT; LLButton* btn = dynamic_cast(view); if (btn && !isDefaultBtnName(btn->getName())) @@ -133,6 +142,22 @@ BOOL LLLuaFloater::postBuild() } } + //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 + const LLSD &events_map = mKey["extra_events"]; + for (LLSD::map_const_iterator it = events_map.beginMap(); it != events_map.endMap(); ++it) + { + std::string name = (*it).first; + LLSD data = (*it).second; + for (LLSD::array_const_iterator events_it = data.beginArray(); events_it != data.endArray(); ++events_it) + { + registerCallback(name, events_it->asString()); + } + } + } + post(LLSD().with("command_name", mListenerPumpName).with("event", "post_build")); return true; @@ -143,6 +168,57 @@ void LLLuaFloater::onClose(bool app_quitting) post(LLSD().with("event", "floater_close")); } +void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::string &event) +{ + LLUICtrl *ctrl = getChild(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)); + }; + + if (event == MOUSE_ENTER_EVENT) + { + ctrl->setMouseEnterCallback(mouse_event_cb); + } + else if (event == MOUSE_LEAVE_EVENT) + { + ctrl->setMouseLeaveCallback(mouse_event_cb); + } + else if (event == MOUSE_DOWN_EVENT) + { + ctrl->setMouseDownCallback(mouse_event_coords_cb); + } + else if (event == MOUSE_UP_EVENT) + { + ctrl->setMouseUpCallback(mouse_event_coords_cb); + } + else if (event == RIGHT_MOUSE_DOWN_EVENT) + { + ctrl->setRightMouseDownCallback(mouse_event_coords_cb); + } + else if (event == RIGHT_MOUSE_UP_EVENT) + { + ctrl->setRightMouseUpCallback(mouse_event_coords_cb); + } + else if (event == DOUBLE_CLICK_EVENT) + { + ctrl->setDoubleClickCallback(mouse_event_coords_cb); + } + else + { + LL_WARNS("LuaFloater") << "Can't register callback for unknown event: " << event << " ,control: " << ctrl_name << LL_ENDL; + } +} + void LLLuaFloater::post(const LLSD &data) { LLSD stamped_data(data); diff --git a/indra/llui/llluafloater.h b/indra/llui/llluafloater.h index 0b7e86746a..eec6180bee 100644 --- a/indra/llui/llluafloater.h +++ b/indra/llui/llluafloater.h @@ -36,6 +36,7 @@ public: LLLuaFloater(const LLSD &key); BOOL postBuild(); + void registerCallback(const std::string &ctrl_name, const std::string &event); void onClose(bool app_quitting); void post(const LLSD &data); -- cgit v1.2.3 From fdfff5305bc9d97bb27d36a7fe18bab693e42aed Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Fri, 15 Mar 2024 18:20:42 +0200 Subject: set commit callback for all buttons including minimize, maximize --- indra/llui/llluafloater.cpp | 77 +++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 44 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp index 5b50d85811..b60a893f12 100644 --- a/indra/llui/llluafloater.cpp +++ b/indra/llui/llluafloater.cpp @@ -34,14 +34,19 @@ const std::string LISTENER_NAME("LLLuaFloater"); -const std::string COMMIT_EVENT("commit"); -const std::string MOUSE_ENTER_EVENT("mouse_enter"); -const std::string MOUSE_LEAVE_EVENT("mouse_leave"); -const std::string MOUSE_DOWN_EVENT("mouse_down"); -const std::string MOUSE_UP_EVENT("mouse_up"); -const std::string RIGHT_MOUSE_DOWN_EVENT("right_mouse_down"); -const std::string RIGHT_MOUSE_UP_EVENT("right_mouse_up"); -const std::string DOUBLE_CLICK_EVENT("double_click"); +std::map EVENT_LIST = +{ + {"COMMIT_EVENT", "commit"}, + {"DOUBLE_CLICK_EVENT", "double_click"}, + {"MOUSE_ENTER_EVENT", "mouse_enter"}, + {"MOUSE_LEAVE_EVENT", "mouse_leave"}, + {"MOUSE_DOWN_EVENT", "mouse_down"}, + {"MOUSE_UP_EVENT", "mouse_up"}, + {"RIGHT_MOUSE_DOWN_EVENT", "right_mouse_down"}, + {"RIGHT_MOUSE_UP_EVENT", "right_mouse_up"}, + {"POST_BUILD_EVENT", "post_build"}, + {"CLOSE_EVENT", "floater_close"} +}; LLLuaFloater::LLLuaFloater(const LLSD &key) : LLFloater(key), @@ -108,36 +113,18 @@ BOOL LLLuaFloater::postBuild() LLView *view = *iter; if (!view) continue; - LLSD data; - data["ctrl_name"] = view->getName(); - data["event"] = COMMIT_EVENT; - - LLButton* btn = dynamic_cast(view); - if (btn && !isDefaultBtnName(btn->getName())) + LLUICtrl *ctrl = dynamic_cast(view); + if (ctrl) { - data["ctrl_type"] = "LLButton"; - btn->setCommitCallback([this, data](LLUICtrl *ctrl, const LLSD ¶m) { post(data); }); - } - LLCheckBoxCtrl* check = dynamic_cast(view); - if (check) - { - data["ctrl_type"] = "LLCheckBoxCtrl"; - check->setCommitCallback([this, data](LLUICtrl *ctrl, const LLSD ¶m) + LLSD data; + data["ctrl_name"] = view->getName(); + data["event"] = EVENT_LIST["COMMIT_EVENT"]; + + ctrl->setCommitCallback([this, data](LLUICtrl *ctrl, const LLSD ¶m) { LLSD event(data); event["value"] = ctrl->getValue(); - post(event); - }); - } - LLComboBox *combo = dynamic_cast(view); - if (combo) - { - data["ctrl_type"] = "LLComboBox"; - combo->setCommitCallback([this, data](LLUICtrl* ctrl, const LLSD ¶m) - { - LLSD event(data); - event["value"] = dynamic_cast(ctrl)->getValue(); - post(event); + post(event); }); } } @@ -158,14 +145,15 @@ BOOL LLLuaFloater::postBuild() } } - post(LLSD().with("command_name", mListenerPumpName).with("event", "post_build")); + //send pump name to the script after the floater is built + post(LLSD().with("command_name", mListenerPumpName).with("event", EVENT_LIST["POST_BUILD_EVENT"])); return true; } void LLLuaFloater::onClose(bool app_quitting) { - post(LLSD().with("event", "floater_close")); + post(LLSD().with("event", EVENT_LIST["CLOSE_EVENT"])); } void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::string &event) @@ -185,42 +173,43 @@ void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::str post(event.with("x", x).with("y", y)); }; - if (event == MOUSE_ENTER_EVENT) + if (event == EVENT_LIST["MOUSE_ENTER_EVENT"]) { ctrl->setMouseEnterCallback(mouse_event_cb); } - else if (event == MOUSE_LEAVE_EVENT) + else if (event == EVENT_LIST["MOUSE_LEAVE_EVENT"]) { ctrl->setMouseLeaveCallback(mouse_event_cb); } - else if (event == MOUSE_DOWN_EVENT) + else if (event == EVENT_LIST["MOUSE_DOWN_EVENT"]) { ctrl->setMouseDownCallback(mouse_event_coords_cb); } - else if (event == MOUSE_UP_EVENT) + else if (event == EVENT_LIST["MOUSE_UP_EVENT"]) { ctrl->setMouseUpCallback(mouse_event_coords_cb); } - else if (event == RIGHT_MOUSE_DOWN_EVENT) + else if (event == EVENT_LIST["RIGHT_MOUSE_DOWN_EVENT"]) { ctrl->setRightMouseDownCallback(mouse_event_coords_cb); } - else if (event == RIGHT_MOUSE_UP_EVENT) + else if (event == EVENT_LIST["RIGHT_MOUSE_UP_EVENT"]) { ctrl->setRightMouseUpCallback(mouse_event_coords_cb); } - else if (event == DOUBLE_CLICK_EVENT) + else if (event == EVENT_LIST["DOUBLE_CLICK_EVENT"]) { ctrl->setDoubleClickCallback(mouse_event_coords_cb); } else { - LL_WARNS("LuaFloater") << "Can't register callback for unknown event: " << event << " ,control: " << ctrl_name << LL_ENDL; + 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(mCommandPumpName).post(stamped_data); -- cgit v1.2.3 From 052fdac5187cc529bbbe9be0c8d0f27516058ebd Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Mon, 18 Mar 2024 15:13:25 +0200 Subject: update to use new lua leap; initial support for scroll list --- indra/llui/llfloaterreglistener.cpp | 21 ++++++++--- indra/llui/llfloaterreglistener.h | 1 + indra/llui/llluafloater.cpp | 70 ++++++++++++++++++++++++++++++------- indra/llui/llluafloater.h | 3 +- 4 files changed, 77 insertions(+), 18 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp index 6fee688121..bdf26c1db8 100644 --- a/indra/llui/llfloaterreglistener.cpp +++ b/indra/llui/llfloaterreglistener.cpp @@ -76,12 +76,12 @@ LLFloaterRegListener::LLFloaterRegListener(): LLSD requiredParams; requiredParams["xml_path"] = LLSD(); - requiredParams["command_pump"] = LLSD(); - requiredParams["reqid"] = LLSD(); add("showLuaFloater", - "Open the new floater using XML file specified in [\"xml_path\"]" - "with ID in [\"reqid\"], which sends UI events to even pump specified in [\"command_pump\"]", + "Open the new floater using XML file specified in [\"xml_path\"]", &LLFloaterRegListener::showLuaFloater, requiredParams); + add("getFloaterEvents", + "Return the table of Lua Floater events which are send to the script", + &LLFloaterRegListener::getLuaFloaterEvents); } void LLFloaterRegListener::getBuildMap(const LLSD& event) const @@ -169,3 +169,16 @@ void LLFloaterRegListener::showLuaFloater(const LLSD &event) const { LLLuaFloater::showLuaFloater(event); } + +void LLFloaterRegListener::getLuaFloaterEvents(const LLSD &event) const +{ + if (event.has("reply")) + { + LLSD events_data = LLLuaFloater::getEventsData(); + + LLReqID reqID(event); + LLSD reply(reqID.makeResponse()); + LLEventPumps::instance().obtain(event["reply"]).post(reply.with("events", events_data)); + } +} + diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h index 2d58303aa0..cbfb7855b9 100644 --- a/indra/llui/llfloaterreglistener.h +++ b/indra/llui/llfloaterreglistener.h @@ -51,6 +51,7 @@ private: void clickButton(const LLSD& event) const; void showLuaFloater(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 index b60a893f12..36dd0d58bd 100644 --- a/indra/llui/llluafloater.cpp +++ b/indra/llui/llluafloater.cpp @@ -31,6 +31,7 @@ #include "llcheckboxctrl.h" #include "llcombobox.h" +#include "llscrolllistctrl.h" const std::string LISTENER_NAME("LLLuaFloater"); @@ -50,9 +51,8 @@ std::map EVENT_LIST = LLLuaFloater::LLLuaFloater(const LLSD &key) : LLFloater(key), - mCommandPumpName(key["command_pump"].asString()), - mDispatcher("LLLuaFloater", "action"), - mReqID(key) + mCommandPumpName(key["reply"].asString()), + mDispatcher("LLLuaFloater", "action") { mListenerPumpName = LLUUID::generateNewID().asString(); @@ -69,9 +69,7 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : return false; }); - LLSD requiredParams; - requiredParams["ctrl_name"] = LLSD(); - requiredParams["value"] = LLSD(); + LLSD requiredParams = LLSD().with("ctrl_name", LLSD()).with("value", LLSD()); mDispatcher.add("set_enabled", "", [this](const LLSD &event) { LLUICtrl *ctrl = getChild(event["ctrl_name"].asString()); @@ -96,12 +94,39 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : ctrl->setValue(event["value"]); } }, requiredParams); + mDispatcher.add("add_list_element", "", [this](const LLSD &event) + { + LLScrollListCtrl *ctrl = getChild(event["ctrl_name"].asString()); + if(ctrl) + { + ctrl->addElement(event["value"]); + } + }, requiredParams); requiredParams = LLSD().with("value", LLSD()); mDispatcher.add("set_title", "", [this](const LLSD &event) { setTitle(event["value"].asString()); - }); + }, requiredParams); + + requiredParams = LLSD().with("ctrl_name", LLSD()).with("reqid", LLSD()); + mDispatcher.add("get_value", "", [this](const LLSD &event) + { + LLUICtrl *ctrl = getChild(event["ctrl_name"].asString()); + if(ctrl) + { + LLSD response; + response["value"] = ctrl->getValue(); + response["reqid"] = event["reqid"]; + post(response); + } + }, requiredParams); +} + +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() @@ -199,7 +224,20 @@ void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::str } else if (event == EVENT_LIST["DOUBLE_CLICK_EVENT"]) { - ctrl->setDoubleClickCallback(mouse_event_coords_cb); + LLScrollListCtrl *list = dynamic_cast(ctrl); + if (list) + { + list->setDoubleClickCallback( + [this, data, list]() + { + LLSD event(data); + post(event.with("value", list->getCurrentID())); + }); + } + else + { + ctrl->setDoubleClickCallback(mouse_event_coords_cb); + } } else { @@ -209,10 +247,8 @@ void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::str 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(mCommandPumpName).post(stamped_data); + //send event data to the script + LLEventPumps::instance().obtain(mCommandPumpName).post(data); } void LLLuaFloater::showLuaFloater(const LLSD &data) @@ -224,4 +260,12 @@ void LLLuaFloater::showLuaFloater(const LLSD &data) floater->openFloater(floater->getKey()); } - +LLSD LLLuaFloater::getEventsData() +{ + LLSD event_data; + for (auto &it : EVENT_LIST) + { + event_data[it.first] = it.second; + } + return event_data; +} diff --git a/indra/llui/llluafloater.h b/indra/llui/llluafloater.h index eec6180bee..0dd39e7d1e 100644 --- a/indra/llui/llluafloater.h +++ b/indra/llui/llluafloater.h @@ -35,15 +35,16 @@ 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); static void showLuaFloater(const LLSD &data); + static LLSD getEventsData(); private: - LLReqID mReqID; LLEventDispatcher mDispatcher; LLTempBoundListener mBoundListener; -- cgit v1.2.3 From ad1f5ac8906316f8e90355a4ebdbf33400758080 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 19 Mar 2024 15:32:47 +0200 Subject: search xml file in the lib, if path is not full; add test lua floater scripts --- indra/llui/llluafloater.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp index 36dd0d58bd..27ae85c844 100644 --- a/indra/llui/llluafloater.cpp +++ b/indra/llui/llluafloater.cpp @@ -254,9 +254,15 @@ void LLLuaFloater::post(const LLSD &data) void LLLuaFloater::showLuaFloater(const LLSD &data) { std::filesystem::path fs_path(data["xml_path"].asString()); - + std::string path = fs_path.lexically_normal().string(); + if (!fs_path.is_absolute()) + { + std::string lib_path = gDirUtilp->getExpandedFilename(LL_PATH_SCRIPTS, "lua"); + path = (std::filesystem::path(lib_path) / path).u8string(); + } + LLLuaFloater *floater = new LLLuaFloater(data); - floater->buildFromFile(fs_path.lexically_normal().string()); + floater->buildFromFile(path); floater->openFloater(floater->getKey()); } -- cgit v1.2.3 From ba6784647b53919c09ef339fd99af152aa0f8458 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Wed, 20 Mar 2024 23:21:48 +0200 Subject: LLLuaFloater code clean up --- indra/llui/llfloater.cpp | 4 ---- indra/llui/llfloater.h | 3 --- indra/llui/llfloaterreglistener.cpp | 20 +++---------------- indra/llui/llfloaterreglistener.h | 1 - indra/llui/llluafloater.cpp | 39 +++++++++++++++---------------------- indra/llui/llluafloater.h | 3 ++- 6 files changed, 21 insertions(+), 49 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index b9b69b5a33..de3de53569 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -3623,10 +3623,6 @@ void LLFloater::applyRelativePosition() translate(new_center.mX - cur_center.mX, new_center.mY - cur_center.mY); } -bool LLFloater::isDefaultBtnName(const std::string& name) -{ - return (std::find(std::begin(sButtonNames), std::end(sButtonNames), name) != std::end(sButtonNames)); -} LLCoordFloater::LLCoordFloater(F32 x, F32 y, LLFloater& floater) : coord_t((S32)x, (S32)y) diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 9d49c4538e..88f9e77777 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -372,9 +372,6 @@ public: void enableResizeCtrls(bool enable, bool width = true, bool height = true); bool isPositioning(LLFloaterEnums::EOpenPositioning p) const { return (p == mPositioning); } - - static bool isDefaultBtnName(const std::string& name); - protected: void applyControlsAndPosition(LLFloater* other); diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp index bdf26c1db8..8316101264 100644 --- a/indra/llui/llfloaterreglistener.cpp +++ b/indra/llui/llfloaterreglistener.cpp @@ -74,11 +74,9 @@ LLFloaterRegListener::LLFloaterRegListener(): &LLFloaterRegListener::clickButton, requiredNameButton); - LLSD requiredParams; - requiredParams["xml_path"] = LLSD(); add("showLuaFloater", - "Open the new floater using XML file specified in [\"xml_path\"]", - &LLFloaterRegListener::showLuaFloater, requiredParams); + "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); @@ -165,20 +163,8 @@ void LLFloaterRegListener::clickButton(const LLSD& event) const } } -void LLFloaterRegListener::showLuaFloater(const LLSD &event) const -{ - LLLuaFloater::showLuaFloater(event); -} - void LLFloaterRegListener::getLuaFloaterEvents(const LLSD &event) const { - if (event.has("reply")) - { - LLSD events_data = LLLuaFloater::getEventsData(); - - LLReqID reqID(event); - LLSD reply(reqID.makeResponse()); - LLEventPumps::instance().obtain(event["reply"]).post(reply.with("events", events_data)); - } + Response response(llsd::map("events", LLLuaFloater::getEventsData()), event); } diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h index cbfb7855b9..9cb0af2de5 100644 --- a/indra/llui/llfloaterreglistener.h +++ b/indra/llui/llfloaterreglistener.h @@ -50,7 +50,6 @@ private: void instanceVisible(const LLSD& event) const; void clickButton(const LLSD& event) const; - void showLuaFloater(const LLSD &event) const; void getLuaFloaterEvents(const LLSD &event) const; }; diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp index 27ae85c844..668c0edc53 100644 --- a/indra/llui/llluafloater.cpp +++ b/indra/llui/llluafloater.cpp @@ -51,8 +51,9 @@ std::map EVENT_LIST = LLLuaFloater::LLLuaFloater(const LLSD &key) : LLFloater(key), - mCommandPumpName(key["reply"].asString()), - mDispatcher("LLLuaFloater", "action") + mReplyPumpName(key["reply"].asString()), + mDispatcher("LLLuaFloater", "action"), + mReqID(key) { mListenerPumpName = LLUUID::generateNewID().asString(); @@ -69,7 +70,7 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : return false; }); - LLSD requiredParams = LLSD().with("ctrl_name", LLSD()).with("value", LLSD()); + LLSD requiredParams = llsd::map("ctrl_name", LLSD(), "value", LLSD()); mDispatcher.add("set_enabled", "", [this](const LLSD &event) { LLUICtrl *ctrl = getChild(event["ctrl_name"].asString()); @@ -103,13 +104,11 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : } }, requiredParams); - requiredParams = LLSD().with("value", LLSD()); mDispatcher.add("set_title", "", [this](const LLSD &event) { setTitle(event["value"].asString()); - }, requiredParams); + }, llsd::map("value", LLSD())); - requiredParams = LLSD().with("ctrl_name", LLSD()).with("reqid", LLSD()); mDispatcher.add("get_value", "", [this](const LLSD &event) { LLUICtrl *ctrl = getChild(event["ctrl_name"].asString()); @@ -120,7 +119,7 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : response["reqid"] = event["reqid"]; post(response); } - }, requiredParams); + }, llsd::map("ctrl_name", LLSD(), "reqid", LLSD())); } LLLuaFloater::~LLLuaFloater() @@ -131,13 +130,8 @@ LLLuaFloater::~LLLuaFloater() BOOL LLLuaFloater::postBuild() { - child_list_t::const_iterator iter = getChildList()->begin(); - child_list_t::const_iterator end = getChildList()->end(); - for (; iter != end; ++iter) + for (LLView *view : *getChildList()) { - LLView *view = *iter; - if (!view) continue; - LLUICtrl *ctrl = dynamic_cast(view); if (ctrl) { @@ -158,27 +152,24 @@ BOOL LLLuaFloater::postBuild() if (mKey.has("extra_events")) { //the first value is ctrl name, the second contains array of events to send - const LLSD &events_map = mKey["extra_events"]; - for (LLSD::map_const_iterator it = events_map.beginMap(); it != events_map.endMap(); ++it) + for (const auto &[name, data] : llsd::inMap(mKey["extra_events"])) { - std::string name = (*it).first; - LLSD data = (*it).second; - for (LLSD::array_const_iterator events_it = data.beginArray(); events_it != data.endArray(); ++events_it) + for (const auto &event : llsd::inArray(data)) { - registerCallback(name, events_it->asString()); + registerCallback(name, event); } } } //send pump name to the script after the floater is built - post(LLSD().with("command_name", mListenerPumpName).with("event", EVENT_LIST["POST_BUILD_EVENT"])); + post(llsd::map("command_name", mListenerPumpName, "event", EVENT_LIST["POST_BUILD_EVENT"])); return true; } void LLLuaFloater::onClose(bool app_quitting) { - post(LLSD().with("event", EVENT_LIST["CLOSE_EVENT"])); + post(llsd::map("event", EVENT_LIST["CLOSE_EVENT"], "app_quitting", app_quitting)); } void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::string &event) @@ -247,8 +238,10 @@ void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::str void LLLuaFloater::post(const LLSD &data) { - //send event data to the script - LLEventPumps::instance().obtain(mCommandPumpName).post(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::showLuaFloater(const LLSD &data) diff --git a/indra/llui/llluafloater.h b/indra/llui/llluafloater.h index 0dd39e7d1e..b9f96f0ad3 100644 --- a/indra/llui/llluafloater.h +++ b/indra/llui/llluafloater.h @@ -45,10 +45,11 @@ public: static LLSD getEventsData(); private: + LLReqID mReqID; LLEventDispatcher mDispatcher; LLTempBoundListener mBoundListener; std::string mListenerPumpName; - std::string mCommandPumpName; + std::string mReplyPumpName; }; #endif -- cgit v1.2.3 From 76752d6fc00a2789d96480da2a1e862ffecc812a Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 21 Mar 2024 18:26:48 +0200 Subject: Switch to LLDispatchListener --- indra/llui/llluafloater.cpp | 68 ++++++++++++++++----------------------------- indra/llui/llluafloater.h | 4 +-- 2 files changed, 25 insertions(+), 47 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp index 668c0edc53..4ae0e28963 100644 --- a/indra/llui/llluafloater.cpp +++ b/indra/llui/llluafloater.cpp @@ -49,53 +49,40 @@ std::map EVENT_LIST = {"CLOSE_EVENT", "floater_close"} }; + + LLLuaFloater::LLLuaFloater(const LLSD &key) : - LLFloater(key), + LLFloater(key), + mDispatchListener(LLUUID::generateNewID().asString(), "action"), mReplyPumpName(key["reply"].asString()), - mDispatcher("LLLuaFloater", "action"), mReqID(key) { - mListenerPumpName = LLUUID::generateNewID().asString(); - - mBoundListener = LLEventPumps::instance().obtain(mListenerPumpName).listen(LISTENER_NAME, [this](const LLSD &event) - { - if (event.has("action")) - { - mDispatcher.try_call(event); - } - else + auto ctrl_lookup = [this](const LLSD &event, std::function cb) + { + LLUICtrl *ctrl = getChild(event["ctrl_name"].asString()); + if (!ctrl) { - LL_WARNS("LuaFloater") << "Unknown message: " << event << LL_ENDL; + LL_WARNS("LuaFloater") << "Control not found: " << event["ctrl_name"] << LL_ENDL; + return LLSD(); } - return false; - }); + return cb(ctrl, event); + }; LLSD requiredParams = llsd::map("ctrl_name", LLSD(), "value", LLSD()); - mDispatcher.add("set_enabled", "", [this](const LLSD &event) + mDispatchListener.add("set_enabled", "", [this, ctrl_lookup](const LLSD &event) { - LLUICtrl *ctrl = getChild(event["ctrl_name"].asString()); - if(ctrl) - { - ctrl->setEnabled(event["value"].asBoolean()); - } + return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { ctrl->setEnabled(event["value"].asBoolean()); return LLSD(); }); }, requiredParams); - mDispatcher.add("set_visible", "", [this](const LLSD &event) + mDispatchListener.add("set_visible", "", [this, ctrl_lookup](const LLSD &event) { - LLUICtrl *ctrl = getChild(event["ctrl_name"].asString()); - if(ctrl) - { - ctrl->setVisible(event["value"].asBoolean()); - } + return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { ctrl->setVisible(event["value"].asBoolean()); return LLSD(); }); }, requiredParams); - mDispatcher.add("set_value", "", [this](const LLSD &event) + mDispatchListener.add("set_value", "", [this, ctrl_lookup](const LLSD &event) { - LLUICtrl *ctrl = getChild(event["ctrl_name"].asString()); - if(ctrl) - { - ctrl->setValue(event["value"]); - } + return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { ctrl->setValue(event["value"]); return LLSD(); }); }, requiredParams); - mDispatcher.add("add_list_element", "", [this](const LLSD &event) + + mDispatchListener.add("add_list_element", "", [this](const LLSD &event) { LLScrollListCtrl *ctrl = getChild(event["ctrl_name"].asString()); if(ctrl) @@ -104,21 +91,14 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : } }, requiredParams); - mDispatcher.add("set_title", "", [this](const LLSD &event) + mDispatchListener.add("set_title", "", [this](const LLSD &event) { setTitle(event["value"].asString()); }, llsd::map("value", LLSD())); - mDispatcher.add("get_value", "", [this](const LLSD &event) + mDispatchListener.add("get_value", "", [this, ctrl_lookup](const LLSD &event) { - LLUICtrl *ctrl = getChild(event["ctrl_name"].asString()); - if(ctrl) - { - LLSD response; - response["value"] = ctrl->getValue(); - response["reqid"] = event["reqid"]; - post(response); - } + return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { return llsd::map("value", ctrl->getValue()); }); }, llsd::map("ctrl_name", LLSD(), "reqid", LLSD())); } @@ -162,7 +142,7 @@ BOOL LLLuaFloater::postBuild() } //send pump name to the script after the floater is built - post(llsd::map("command_name", mListenerPumpName, "event", EVENT_LIST["POST_BUILD_EVENT"])); + post(llsd::map("command_name", mDispatchListener.getPumpName(), "event", EVENT_LIST["POST_BUILD_EVENT"])); return true; } diff --git a/indra/llui/llluafloater.h b/indra/llui/llluafloater.h index b9f96f0ad3..d4c16745ee 100644 --- a/indra/llui/llluafloater.h +++ b/indra/llui/llluafloater.h @@ -46,10 +46,8 @@ public: private: LLReqID mReqID; - LLEventDispatcher mDispatcher; - LLTempBoundListener mBoundListener; + LLDispatchListener mDispatchListener; - std::string mListenerPumpName; std::string mReplyPumpName; }; #endif -- cgit v1.2.3 From 4ffdae72392ba2f081edf8d740b688b95ac4fc65 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 21 Mar 2024 20:24:24 +0200 Subject: Accept an array for "add_list_item" and change EVENT_LIST type --- indra/llui/llluafloater.cpp | 73 ++++++++++++++++++++++++++++----------------- indra/llui/llluafloater.h | 1 + 2 files changed, 47 insertions(+), 27 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp index 4ae0e28963..23a336a1e8 100644 --- a/indra/llui/llluafloater.cpp +++ b/indra/llui/llluafloater.cpp @@ -35,22 +35,19 @@ const std::string LISTENER_NAME("LLLuaFloater"); -std::map EVENT_LIST = -{ - {"COMMIT_EVENT", "commit"}, - {"DOUBLE_CLICK_EVENT", "double_click"}, - {"MOUSE_ENTER_EVENT", "mouse_enter"}, - {"MOUSE_LEAVE_EVENT", "mouse_leave"}, - {"MOUSE_DOWN_EVENT", "mouse_down"}, - {"MOUSE_UP_EVENT", "mouse_up"}, - {"RIGHT_MOUSE_DOWN_EVENT", "right_mouse_down"}, - {"RIGHT_MOUSE_UP_EVENT", "right_mouse_up"}, - {"POST_BUILD_EVENT", "post_build"}, - {"CLOSE_EVENT", "floater_close"} +std::set EVENT_LIST = { + "commit", + "double_click", + "mouse_enter", + "mouse_leave", + "mouse_down", + "mouse_up", + "right_mouse_down", + "right_mouse_up", + "post_build", + "floater_close" }; - - LLLuaFloater::LLLuaFloater(const LLSD &key) : LLFloater(key), mDispatchListener(LLUUID::generateNewID().asString(), "action"), @@ -87,7 +84,18 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : LLScrollListCtrl *ctrl = getChild(event["ctrl_name"].asString()); if(ctrl) { - ctrl->addElement(event["value"]); + 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); @@ -117,13 +125,12 @@ BOOL LLLuaFloater::postBuild() { LLSD data; data["ctrl_name"] = view->getName(); - data["event"] = EVENT_LIST["COMMIT_EVENT"]; ctrl->setCommitCallback([this, data](LLUICtrl *ctrl, const LLSD ¶m) { LLSD event(data); event["value"] = ctrl->getValue(); - post(event); + postEvent(event, "commit"); }); } } @@ -142,14 +149,20 @@ BOOL LLLuaFloater::postBuild() } //send pump name to the script after the floater is built - post(llsd::map("command_name", mDispatchListener.getPumpName(), "event", EVENT_LIST["POST_BUILD_EVENT"])); + postEvent(llsd::map("command_name", mDispatchListener.getPumpName()), "post_build"); return true; } void LLLuaFloater::onClose(bool app_quitting) { - post(llsd::map("event", EVENT_LIST["CLOSE_EVENT"], "app_quitting", 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) @@ -169,31 +182,31 @@ void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::str post(event.with("x", x).with("y", y)); }; - if (event == EVENT_LIST["MOUSE_ENTER_EVENT"]) + if (event_is(event, "mouse_enter")) { ctrl->setMouseEnterCallback(mouse_event_cb); } - else if (event == EVENT_LIST["MOUSE_LEAVE_EVENT"]) + else if (event_is(event, "mouse_leave")) { ctrl->setMouseLeaveCallback(mouse_event_cb); } - else if (event == EVENT_LIST["MOUSE_DOWN_EVENT"]) + else if (event_is(event, "mouse_down")) { ctrl->setMouseDownCallback(mouse_event_coords_cb); } - else if (event == EVENT_LIST["MOUSE_UP_EVENT"]) + else if (event_is(event, "mouse_up")) { ctrl->setMouseUpCallback(mouse_event_coords_cb); } - else if (event == EVENT_LIST["RIGHT_MOUSE_DOWN_EVENT"]) + else if (event_is(event, "right_mouse_down")) { ctrl->setRightMouseDownCallback(mouse_event_coords_cb); } - else if (event == EVENT_LIST["RIGHT_MOUSE_UP_EVENT"]) + else if (event_is(event, "right_mouse_up")) { ctrl->setRightMouseUpCallback(mouse_event_coords_cb); } - else if (event == EVENT_LIST["DOUBLE_CLICK_EVENT"]) + else if (event_is(event, "double_click")) { LLScrollListCtrl *list = dynamic_cast(ctrl); if (list) @@ -224,6 +237,12 @@ void LLLuaFloater::post(const LLSD &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) { std::filesystem::path fs_path(data["xml_path"].asString()); @@ -244,7 +263,7 @@ LLSD LLLuaFloater::getEventsData() LLSD event_data; for (auto &it : EVENT_LIST) { - event_data[it.first] = it.second; + event_data.append(it); } return event_data; } diff --git a/indra/llui/llluafloater.h b/indra/llui/llluafloater.h index d4c16745ee..ccc3ccb39b 100644 --- a/indra/llui/llluafloater.h +++ b/indra/llui/llluafloater.h @@ -41,6 +41,7 @@ public: 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(); -- cgit v1.2.3 From 7b149485e091880269dd9d7941cca47da49e652f Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 21 Mar 2024 22:05:37 +0200 Subject: mac build fix --- indra/llui/llluafloater.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp index 23a336a1e8..afc287a864 100644 --- a/indra/llui/llluafloater.cpp +++ b/indra/llui/llluafloater.cpp @@ -66,15 +66,15 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : }; LLSD requiredParams = llsd::map("ctrl_name", LLSD(), "value", LLSD()); - mDispatchListener.add("set_enabled", "", [this, ctrl_lookup](const LLSD &event) + 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", "", [this, ctrl_lookup](const LLSD &event) + 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", "", [this, ctrl_lookup](const LLSD &event) + 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); @@ -104,7 +104,7 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : setTitle(event["value"].asString()); }, llsd::map("value", LLSD())); - mDispatchListener.add("get_value", "", [this, ctrl_lookup](const LLSD &event) + 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())); -- cgit v1.2.3 From 41e14d35ae2dfa644716cb195545d59c468538c5 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Mon, 25 Mar 2024 15:06:11 +0200 Subject: Add keystroke event support and allow adding text lines to the line editor --- indra/llui/llluafloater.cpp | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp index afc287a864..8f624788c2 100644 --- a/indra/llui/llluafloater.cpp +++ b/indra/llui/llluafloater.cpp @@ -32,6 +32,7 @@ #include "llcheckboxctrl.h" #include "llcombobox.h" #include "llscrolllistctrl.h" +#include "lltexteditor.h" const std::string LISTENER_NAME("LLLuaFloater"); @@ -45,7 +46,8 @@ std::set EVENT_LIST = { "right_mouse_down", "right_mouse_up", "post_build", - "floater_close" + "floater_close", + "keystroke" }; LLLuaFloater::LLLuaFloater(const LLSD &key) : @@ -99,6 +101,16 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : } }, requiredParams); + mDispatchListener.add("add_text", "", [this](const LLSD &event) + { + LLTextEditor *editor = getChild(event["ctrl_name"].asString()); + if (editor) + { + editor->pasteTextWithLinebreaks(stringize(event["value"])); + editor->addLineBreakChar(true); + } + }, requiredParams); + mDispatchListener.add("set_title", "", [this](const LLSD &event) { setTitle(event["value"].asString()); @@ -182,6 +194,12 @@ void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::str 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); @@ -211,18 +229,26 @@ void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::str LLScrollListCtrl *list = dynamic_cast(ctrl); if (list) { - list->setDoubleClickCallback( - [this, data, list]() - { - LLSD event(data); - post(event.with("value", list->getCurrentID())); - }); + list->setDoubleClickCallback( [this, 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(ctrl); + if (text_editor) + { + text_editor->setKeystrokeCallback([this, post_with_value](LLTextEditor *editor) { post_with_value(editor->getValue()); }); + } + LLLineEditor* line_editor = dynamic_cast(ctrl); + if (line_editor) + { + line_editor->setKeystrokeCallback([this, 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; -- cgit v1.2.3 From 7f39a5bb109338b201c9cd0d3a40baac2b2e4fc1 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Mon, 25 Mar 2024 17:10:46 +0200 Subject: mac build fix --- indra/llui/llluafloater.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp index 8f624788c2..268075b05d 100644 --- a/indra/llui/llluafloater.cpp +++ b/indra/llui/llluafloater.cpp @@ -194,7 +194,7 @@ void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::str post(event.with("x", x).with("y", y)); }; - auto post_with_value = [this, data](LLSD& value) + auto post_with_value = [this, data](LLSD value) { LLSD event(data); post(event.with("value", value)); @@ -229,7 +229,7 @@ void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::str LLScrollListCtrl *list = dynamic_cast(ctrl); if (list) { - list->setDoubleClickCallback( [this, post_with_value, list](){ post_with_value(LLSD(list->getCurrentID())); }); + list->setDoubleClickCallback( [post_with_value, list](){ post_with_value(LLSD(list->getCurrentID())); }); } else { @@ -241,12 +241,12 @@ void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::str LLTextEditor* text_editor = dynamic_cast(ctrl); if (text_editor) { - text_editor->setKeystrokeCallback([this, post_with_value](LLTextEditor *editor) { post_with_value(editor->getValue()); }); + text_editor->setKeystrokeCallback([post_with_value](LLTextEditor *editor) { post_with_value(editor->getValue()); }); } LLLineEditor* line_editor = dynamic_cast(ctrl); if (line_editor) { - line_editor->setKeystrokeCallback([this, post_with_value](LLLineEditor *editor, void* userdata) { post_with_value(editor->getValue()); }, NULL); + line_editor->setKeystrokeCallback([post_with_value](LLLineEditor *editor, void* userdata) { post_with_value(editor->getValue()); }, NULL); } } else -- cgit v1.2.3 From e399b02e3306a249cb161f07cac578d3f2617bab Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 3 Apr 2024 12:31:43 -0400 Subject: Introduce fsyspath subclass of std::filesystem::path. Our std::strings are UTF-8 encoded, so conversion from std::string to std::filesystem::path must use UTF-8 decoding. The native Windows std::filesystem::path constructor and assignment operator accepting std::string use "native narrow encoding," which mangles path strings containing UTF-8 encoded non-ASCII characters. fsyspath's std::string constructor and assignment operator explicitly engage std::filesystem::u8path() to handle encoding. u8path() is deprecated in C++20, but once we adapt fsyspath's conversion to C++20 conventions, consuming code need not be modified. --- indra/llui/llluafloater.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp index 268075b05d..e584a67a00 100644 --- a/indra/llui/llluafloater.cpp +++ b/indra/llui/llluafloater.cpp @@ -26,7 +26,7 @@ #include "llluafloater.h" -#include +#include "fsyspath.h" #include "llevents.h" #include "llcheckboxctrl.h" @@ -271,12 +271,12 @@ void LLLuaFloater::postEvent(LLSD data, const std::string &event_name) void LLLuaFloater::showLuaFloater(const LLSD &data) { - std::filesystem::path fs_path(data["xml_path"].asString()); - std::string path = fs_path.lexically_normal().string(); + 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 = (std::filesystem::path(lib_path) / path).u8string(); + path = (fsyspath(lib_path) / path).u8string(); } LLLuaFloater *floater = new LLLuaFloater(data); -- cgit v1.2.3 From c231c97eeefc484b74198ba86251054b7dc0e6bb Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 2 May 2024 21:13:28 -0400 Subject: WIP: In llcallbacklist.h, add singleton LLLater for time delays. The big idea is to reduce the number of per-tick callbacks asking, "Is it time yet? Is it time yet?" We do that for LLEventTimer and LLEventTimeout. LLLater presents doAtTime(LLDate), with doAfterInterval() and doPeriodically() methods implemented using doAtTime(). All return handles. The free functions doAfterInterval() and doPeriodically() now forward to the corresponding LLLater methods. LLLater also presents isRunning(handle) and cancel(handle). LLLater borrows the tactic of LLEventTimer: while there's at least one running timer, it registers an LLCallbackList tick() callback to service ready timers. But instead of looping over all of them asking, "Are you ready?" it keeps them in a priority queue ordered by desired timestamp, and only touches those whose timestamp has been reached. Also, it honors a maximum time slice: once the ready timers have run for longer than the limit, it defers processing other ready timers to the next tick() call. The intent is to consume fewer cycles per tick() call, both by the management machinery and the timers themselves. Revamp LLCallbackList to accept C++ callables in addition to (classic C function pointer, void*) pairs. Make addFunction() return a handle (different than LLLater handles) that can be passed to a new deleteFunction() overload, since std::function instances can't be compared for equality. In fact, implement LLCallbackList using boost::signals2::signal, which provides almost exactly what we want. LLCallbackList continues to accept (function pointer, void*) pairs, but now we store a lambda that calls the function pointer with that void*. It takes less horsing around to create a C++ callable from a (function pointer, void*) pair than the other way around. For containsFunction() and deleteFunction(), such pairs are the keys for a lookup table whose values are handles. Instead of having a static global LLCallbackList gIdleCallbacks, make LLCallbackList an LLSingleton to guarantee initialization. For backwards compatibility, gIdleCallbacks is now a macro for LLCallbackList::instance(). Move doOnIdleOneTime() and doOnIdleRepeating() functions to LLCallbackList methods, but for backwards compatibility continue providing free functions. Reimplement LLEventTimer using LLLater::doPeriodically(). One implication is that LLEventTimer need no longer be derived from LLInstanceTracker, which we used to iterate over all instances every tick. Give it start() and stop() methods, since some subclasses (e.g. LLFlashTimer) used to call its member LLTimer's start() and stop(). Remove updateClass(): LLCallbackList::callFunctions() now takes care of that. Remove LLToastLifeTimer::start() and stop(), since LLEventTimer now provides those. Remove getRemainingTimeF32(), since LLLater does not (yet) provide that feature. While at it, make LLEventTimer::tick() return bool instead of BOOL, and change existing overrides. Make LLApp::stepFrame() call LLCallbackList::callFunctions() instead of LLEventTimer::updateClass(). We could have refactored LLEventTimer to use the mechanism now built into LLLater, but frankly the LLEventTimer API is rather clumsy. You MUST derive a subclass and override tick(), and you must instantiate your subclass on the heap because, when your tick() override returns false, LLEventTimer deletes its subclass instance. The LLLater API is simpler to use, and LLEventTimer is much simplified by using it. Merge lleventfilter.h's LLEventTimeoutBase into LLEventTimeout, and likewise merge LLEventThrottleBase into LLEventThrottle. The separation was for testability, but now that they're no longer based on LLTimer, it becomes harder to use dummy time for testing. Temporarily skip tests based on LLEventTimeoutBase and LLEventThrottleBase. Instead of listening for LLEventPump("mainloop") ticks and using LLTimer, LLEventTimeout now uses LLLater::doAfterInterval(). Instead of LLTimer and LLEventTimeout, LLEventThrottle likewise now uses LLLater::doAfterInterval(). Recast a couple local LLEventTimeout pre-lambda callable classes with lambdas. Dignify F64 with a new typedef LLDate::timestamp. LLDate heavily depends on that as its base time representation, but there are those who question use of floating-point for time. This is a step towards insulating us from any future change. --- indra/llui/llflashtimer.cpp | 14 +++++++------- indra/llui/llflashtimer.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llflashtimer.cpp b/indra/llui/llflashtimer.cpp index 39793316f4..4a5b220008 100644 --- a/indra/llui/llflashtimer.cpp +++ b/indra/llui/llflashtimer.cpp @@ -31,11 +31,11 @@ LLFlashTimer::LLFlashTimer(callback_t cb, S32 count, F32 period) : LLEventTimer(period), mCallback(cb), mCurrentTickCount(0), - mIsFlashingInProgress(false), - mIsCurrentlyHighlighted(false), - mUnset(false) + mIsFlashingInProgress(false), + 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 @@ -53,7 +53,7 @@ void LLFlashTimer::unset() mCallback = NULL; } -BOOL LLFlashTimer::tick() +bool LLFlashTimer::tick() { mIsCurrentlyHighlighted = !mIsCurrentlyHighlighted; @@ -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 db8d49f009..4a2088734d 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(); -- cgit v1.2.3 From c3da5bb12d1c7c173929433589a4068555791bea Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 15 May 2024 09:11:29 -0400 Subject: Manual whitespace fixes (fix_whitespace.py). --- indra/llui/llmenugl.h | 1248 ++++++------ indra/llui/lltexteditor.cpp | 4634 +++++++++++++++++++++---------------------- indra/llui/lltexteditor.h | 456 ++--- 3 files changed, 3169 insertions(+), 3169 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index fdbfb38474..e8d6043e54 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -1,25 +1,25 @@ -/** +/** * @file llmenugl.h * @brief Declaration of the opengl based menu system. * * $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$ */ @@ -45,183 +45,183 @@ extern S32 MENU_BAR_WIDTH; class LLMenuKeyboardBinding { public: - KEY mKey; - MASK mMask; + KEY mKey; + MASK mMask; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLMenuItemGL // -// The LLMenuItemGL represents a single menu item in a menu. +// The LLMenuItemGL represents a single menu item in a menu. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLMenuItemGL: public LLUICtrl, public ll::ui::SearchableControl { public: - struct Params : public LLInitParam::Block - { - Optional shortcut; - Optional jump_key; - Optional use_mac_ctrl, - allow_key_repeat; - - Ignored rect, - left, - top, - right, - bottom, - width, - height, - bottom_delta, - left_delta; - - Optional enabled_color, - disabled_color, - highlight_bg_color, - highlight_fg_color; - - - Params(); - }; + struct Params : public LLInitParam::Block + { + Optional shortcut; + Optional jump_key; + Optional use_mac_ctrl, + allow_key_repeat; + + Ignored rect, + left, + top, + right, + bottom, + width, + height, + bottom_delta, + left_delta; + + Optional enabled_color, + disabled_color, + highlight_bg_color, + highlight_fg_color; + + + Params(); + }; protected: - LLMenuItemGL(const Params&); - friend class LLUICtrlFactory; + LLMenuItemGL(const Params&); + friend class LLUICtrlFactory; public: - // LLView overrides - /*virtual*/ void onVisibilityChange(BOOL new_visibility); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); - - // LLUICtrl overrides - /*virtual*/ void setValue(const LLSD& value); - /*virtual*/ LLSD getValue() const; - - virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - - LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); } - - void setJumpKey(KEY key); - KEY getJumpKey() const { return mJumpKey; } - - // set the font used by this item. - void setFont(const LLFontGL* font) { mFont = font; } - const LLFontGL* getFont() const { return mFont; } - - // returns the height in pixels for the current font. - virtual U32 getNominalHeight( void ) const; - - // Marks item as not needing space for check marks or accelerator keys - virtual void setBriefItem(BOOL brief); - virtual BOOL isBriefItem() const; - - virtual BOOL addToAcceleratorList(std::list *listp); - void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; } - BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; } - - // change the label - void setLabel( const LLStringExplicit& label ) { mLabel = label; } - std::string getLabel( void ) const { return mLabel.getString(); } - virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); - - // Get the parent menu for this item - virtual class LLMenuGL* getMenu() const; - - // returns the normal width of this control in pixels - this is - // used for calculating the widest item, as well as for horizontal - // arrangement. - virtual U32 getNominalWidth( void ) const; - - // buildDrawLabel() - constructs the string used during the draw() - // function. This reduces the overall string manipulation, but can - // lead to visual errors if the state of the object changes - // without the knowledge of the menu item. For example, if a - // boolean being watched is changed outside of the menu item's - // onCommit() function, the draw buffer will not be updated and will - // reflect the wrong value. If this ever becomes an issue, there - // are ways to fix this. - // Returns the enabled state of the item. - virtual void buildDrawLabel( void ); - - // for branching menu items, bring sub menus up to root level of menu hierarchy - virtual void updateBranchParent( LLView* parentp ){}; - - virtual void onCommit( void ); - - virtual void setHighlight( BOOL highlight ); - virtual BOOL getHighlight() const { return mHighlight; } - - // determine if this represents an active sub-menu - virtual BOOL isActive( void ) const { return FALSE; } - - // determine if this represents an open sub-menu - virtual BOOL isOpen( void ) const { return FALSE; } - - virtual void setEnabledSubMenus(BOOL enable){}; - - // LLView Functionality - virtual BOOL handleKeyHere( KEY key, MASK mask ); - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); - virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); - - virtual void onMouseEnter(S32 x, S32 y, MASK mask); - virtual void onMouseLeave(S32 x, S32 y, MASK mask); - - virtual void draw( void ); - - BOOL getHover() const { return mGotHover; } - - void setDrawTextDisabled(BOOL disabled) { mDrawTextDisabled = disabled; } - BOOL getDrawTextDisabled() const { return mDrawTextDisabled; } + // LLView overrides + /*virtual*/ void onVisibilityChange(BOOL new_visibility); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); + + // LLUICtrl overrides + /*virtual*/ void setValue(const LLSD& value); + /*virtual*/ LLSD getValue() const; + + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + + LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); } + + void setJumpKey(KEY key); + KEY getJumpKey() const { return mJumpKey; } + + // set the font used by this item. + void setFont(const LLFontGL* font) { mFont = font; } + const LLFontGL* getFont() const { return mFont; } + + // returns the height in pixels for the current font. + virtual U32 getNominalHeight( void ) const; + + // Marks item as not needing space for check marks or accelerator keys + virtual void setBriefItem(BOOL brief); + virtual BOOL isBriefItem() const; + + virtual BOOL addToAcceleratorList(std::list *listp); + void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; } + BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; } + + // change the label + void setLabel( const LLStringExplicit& label ) { mLabel = label; } + std::string getLabel( void ) const { return mLabel.getString(); } + virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); + + // Get the parent menu for this item + virtual class LLMenuGL* getMenu() const; + + // returns the normal width of this control in pixels - this is + // used for calculating the widest item, as well as for horizontal + // arrangement. + virtual U32 getNominalWidth( void ) const; + + // buildDrawLabel() - constructs the string used during the draw() + // function. This reduces the overall string manipulation, but can + // lead to visual errors if the state of the object changes + // without the knowledge of the menu item. For example, if a + // boolean being watched is changed outside of the menu item's + // onCommit() function, the draw buffer will not be updated and will + // reflect the wrong value. If this ever becomes an issue, there + // are ways to fix this. + // Returns the enabled state of the item. + virtual void buildDrawLabel( void ); + + // for branching menu items, bring sub menus up to root level of menu hierarchy + virtual void updateBranchParent( LLView* parentp ){}; + + virtual void onCommit( void ); + + virtual void setHighlight( BOOL highlight ); + virtual BOOL getHighlight() const { return mHighlight; } + + // determine if this represents an active sub-menu + virtual BOOL isActive( void ) const { return FALSE; } + + // determine if this represents an open sub-menu + virtual BOOL isOpen( void ) const { return FALSE; } + + virtual void setEnabledSubMenus(BOOL enable){}; + + // LLView Functionality + virtual BOOL handleKeyHere( KEY key, MASK mask ); + virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); + virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + + virtual void onMouseEnter(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); + + virtual void draw( void ); + + BOOL getHover() const { return mGotHover; } + + void setDrawTextDisabled(BOOL disabled) { mDrawTextDisabled = disabled; } + BOOL getDrawTextDisabled() const { return mDrawTextDisabled; } protected: - void setHover(BOOL hover) { mGotHover = hover; } + void setHover(BOOL hover) { mGotHover = hover; } - // This function appends the character string representation of - // the current accelerator key and mask to the provided string. - void appendAcceleratorString( std::string& st ) const; + // This function appends the character string representation of + // the current accelerator key and mask to the provided string. + void appendAcceleratorString( std::string& st ) const; - virtual std::string _getSearchText() const - { - return mLabel.getString(); - } + virtual std::string _getSearchText() const + { + return mLabel.getString(); + } protected: - KEY mAcceleratorKey; - MASK mAcceleratorMask; - // mLabel contains the actual label specified by the user. - LLUIString mLabel; - - // The draw labels contain some of the labels that we draw during - // the draw() routine. This optimizes away some of the string - // manipulation. - LLUIString mDrawBoolLabel; - LLUIString mDrawAccelLabel; - LLUIString mDrawBranchLabel; - - LLUIColor mEnabledColor; - LLUIColor mDisabledColor; - LLUIColor mHighlightBackground; - LLUIColor mHighlightForeground; - - BOOL mHighlight; + KEY mAcceleratorKey; + MASK mAcceleratorMask; + // mLabel contains the actual label specified by the user. + LLUIString mLabel; + + // The draw labels contain some of the labels that we draw during + // the draw() routine. This optimizes away some of the string + // manipulation. + LLUIString mDrawBoolLabel; + LLUIString mDrawAccelLabel; + LLUIString mDrawBranchLabel; + + LLUIColor mEnabledColor; + LLUIColor mDisabledColor; + LLUIColor mHighlightBackground; + LLUIColor mHighlightForeground; + + BOOL mHighlight; private: - // Keyboard and mouse variables - BOOL mAllowKeyRepeat; - BOOL mGotHover; + // Keyboard and mouse variables + BOOL mAllowKeyRepeat; + BOOL mGotHover; - // If true, suppress normal space for check marks on the left and accelerator - // keys on the right. - BOOL mBriefItem; + // If true, suppress normal space for check marks on the left and accelerator + // keys on the right. + BOOL mBriefItem; - // Font for this item - const LLFontGL* mFont; - BOOL mDrawTextDisabled; + // Font for this item + const LLFontGL* mFont; + BOOL mDrawTextDisabled; - KEY mJumpKey; + KEY mJumpKey; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -232,22 +232,22 @@ private: class LLMenuItemSeparatorGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block - { + struct Params : public LLInitParam::Block + { Optional on_visible; Params(); - }; + }; LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p = LLMenuItemSeparatorGL::Params()); - /*virtual*/ void draw( void ); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ void draw( void ); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); virtual void buildDrawLabel(); - /*virtual*/ U32 getNominalHeight( void ) const; + /*virtual*/ U32 getNominalHeight( void ) const; private: enable_signal_t mVisibleSignal; @@ -263,49 +263,49 @@ private: class LLMenuItemCallGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block - { - Optional on_enable; - Optional on_click; - Optional on_visible; - Params() - : on_enable("on_enable"), - on_click("on_click"), - on_visible("on_visible") - {} - }; + struct Params : public LLInitParam::Block + { + Optional on_enable; + Optional on_click; + Optional on_visible; + Params() + : on_enable("on_enable"), + on_click("on_click"), + on_visible("on_visible") + {} + }; protected: - LLMenuItemCallGL(const Params&); - friend class LLUICtrlFactory; - void updateEnabled( void ); - void updateVisible( void ); + LLMenuItemCallGL(const Params&); + friend class LLUICtrlFactory; + void updateEnabled( void ); + void updateVisible( void ); public: - void initFromParams(const Params& p); - - // called to rebuild the draw label - virtual void buildDrawLabel( void ); - - virtual void onCommit( void ); - - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - virtual BOOL handleKeyHere(KEY key, MASK mask); - - //virtual void draw(); - - boost::signals2::connection setClickCallback( const commit_signal_t::slot_type& cb ) - { - return setCommitCallback(cb); - } - - boost::signals2::connection setEnableCallback( const enable_signal_t::slot_type& cb ) - { - return mEnableSignal.connect(cb); - } - + void initFromParams(const Params& p); + + // called to rebuild the draw label + virtual void buildDrawLabel( void ); + + virtual void onCommit( void ); + + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + virtual BOOL handleKeyHere(KEY key, MASK mask); + + //virtual void draw(); + + boost::signals2::connection setClickCallback( const commit_signal_t::slot_type& cb ) + { + return setCommitCallback(cb); + } + + boost::signals2::connection setEnableCallback( const enable_signal_t::slot_type& cb ) + { + return mEnableSignal.connect(cb); + } + private: - enable_signal_t mEnableSignal; - enable_signal_t mVisibleSignal; + enable_signal_t mEnableSignal; + enable_signal_t mVisibleSignal; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -318,40 +318,40 @@ private: // EFFICIENT because it may need to be checked a lot. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLMenuItemCheckGL -: public LLMenuItemCallGL +class LLMenuItemCheckGL +: public LLMenuItemCallGL { public: - struct Params : public LLInitParam::Block - { - Optional on_check; - Params() - : on_check("on_check") - {} - }; + struct Params : public LLInitParam::Block + { + Optional on_check; + Params() + : on_check("on_check") + {} + }; protected: - LLMenuItemCheckGL(const Params&); - friend class LLUICtrlFactory; + LLMenuItemCheckGL(const Params&); + friend class LLUICtrlFactory; public: - - void initFromParams(const Params& p); - - virtual void onCommit( void ); - - virtual void setValue(const LLSD& value); - virtual LLSD getValue() const; - - // called to rebuild the draw label - virtual void buildDrawLabel( void ); - - boost::signals2::connection setCheckCallback( const enable_signal_t::slot_type& cb ) - { - return mCheckSignal.connect(cb); - } - + + void initFromParams(const Params& p); + + virtual void onCommit( void ); + + virtual void setValue(const LLSD& value); + virtual LLSD getValue() const; + + // called to rebuild the draw label + virtual void buildDrawLabel( void ); + + boost::signals2::connection setCheckCallback( const enable_signal_t::slot_type& cb ) + { + return mCheckSignal.connect(cb); + } + private: - enable_signal_t mCheckSignal; + enable_signal_t mCheckSignal; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -368,199 +368,199 @@ private: // child widget registry struct MenuRegistry : public LLChildRegistry { - LLSINGLETON_EMPTY_CTOR(MenuRegistry); + LLSINGLETON_EMPTY_CTOR(MenuRegistry); }; -class LLMenuGL -: public LLUICtrl +class LLMenuGL +: public LLUICtrl { public: - struct Params : public LLInitParam::Block - { - Optional jump_key; - Optional horizontal_layout, - can_tear_off, - drop_shadow, - bg_visible, - create_jump_keys, - keep_fixed_size, - scrollable; - Optional max_scrollable_items; - Optional preferred_width; - Optional bg_color; - Optional shortcut_pad; - - Params() - : jump_key("jump_key", KEY_NONE), - horizontal_layout("horizontal_layout"), - can_tear_off("tear_off", false), - drop_shadow("drop_shadow", true), - bg_visible("bg_visible", true), - create_jump_keys("create_jump_keys", false), - keep_fixed_size("keep_fixed_size", false), - bg_color("bg_color", LLUIColorTable::instance().getColor( "MenuDefaultBgColor" )), - scrollable("scrollable", false), - max_scrollable_items("max_scrollable_items", U32_MAX), - preferred_width("preferred_width", U32_MAX), - shortcut_pad("shortcut_pad") - { - addSynonym(bg_visible, "opaque"); - addSynonym(bg_color, "color"); - addSynonym(can_tear_off, "can_tear_off"); - } - }; - - // my valid children are contained in MenuRegistry - typedef MenuRegistry child_registry_t; - - void initFromParams(const Params&); - - // textual artwork which menugl-imitators may want to match - static const std::string BOOLEAN_TRUE_PREFIX; - static const std::string BRANCH_SUFFIX; - static const std::string ARROW_UP; - static const std::string ARROW_DOWN; - - // for scrollable menus - typedef enum e_scrolling_direction - { - SD_UP = 0, - SD_DOWN = 1, - SD_BEGIN = 2, - SD_END = 3 - } EScrollingDirection; + struct Params : public LLInitParam::Block + { + Optional jump_key; + Optional horizontal_layout, + can_tear_off, + drop_shadow, + bg_visible, + create_jump_keys, + keep_fixed_size, + scrollable; + Optional max_scrollable_items; + Optional preferred_width; + Optional bg_color; + Optional shortcut_pad; + + Params() + : jump_key("jump_key", KEY_NONE), + horizontal_layout("horizontal_layout"), + can_tear_off("tear_off", false), + drop_shadow("drop_shadow", true), + bg_visible("bg_visible", true), + create_jump_keys("create_jump_keys", false), + keep_fixed_size("keep_fixed_size", false), + bg_color("bg_color", LLUIColorTable::instance().getColor( "MenuDefaultBgColor" )), + scrollable("scrollable", false), + max_scrollable_items("max_scrollable_items", U32_MAX), + preferred_width("preferred_width", U32_MAX), + shortcut_pad("shortcut_pad") + { + addSynonym(bg_visible, "opaque"); + addSynonym(bg_color, "color"); + addSynonym(can_tear_off, "can_tear_off"); + } + }; + + // my valid children are contained in MenuRegistry + typedef MenuRegistry child_registry_t; + + void initFromParams(const Params&); + + // textual artwork which menugl-imitators may want to match + static const std::string BOOLEAN_TRUE_PREFIX; + static const std::string BRANCH_SUFFIX; + static const std::string ARROW_UP; + static const std::string ARROW_DOWN; + + // for scrollable menus + typedef enum e_scrolling_direction + { + SD_UP = 0, + SD_DOWN = 1, + SD_BEGIN = 2, + SD_END = 3 + } EScrollingDirection; protected: - LLMenuGL(const LLMenuGL::Params& p); - friend class LLUICtrlFactory; - // let branching menu items use my protected traversal methods - friend class LLMenuItemBranchGL; + LLMenuGL(const LLMenuGL::Params& p); + friend class LLUICtrlFactory; + // let branching menu items use my protected traversal methods + friend class LLMenuItemBranchGL; public: - virtual ~LLMenuGL( void ); - - void parseChildXML(LLXMLNodePtr child, LLView* parent); - - // LLView Functionality - /*virtual*/ BOOL handleUnicodeCharHere( llwchar uni_char ); - /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); - /*virtual*/ BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); - /*virtual*/ void draw( void ); - /*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha); - /*virtual*/ void setVisible(BOOL visible); - /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); + virtual ~LLMenuGL( void ); + + void parseChildXML(LLXMLNodePtr child, LLView* parent); + + // LLView Functionality + /*virtual*/ BOOL handleUnicodeCharHere( llwchar uni_char ); + /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + /*virtual*/ void draw( void ); + /*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha); + /*virtual*/ void setVisible(BOOL visible); + /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); /*virtual*/ void deleteAllChildren(); - /*virtual*/ void removeChild( LLView* ctrl); - /*virtual*/ BOOL postBuild(); - - virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - - LLMenuGL* findChildMenuByName(const std::string& name, BOOL recurse) const; - - BOOL clearHoverItem(); - - // return the name label - const std::string& getLabel( void ) const { return mLabel.getString(); } - void setLabel(const LLStringExplicit& label) { mLabel = label; } - - // background colors - void setBackgroundColor( const LLUIColor& color ) { mBackgroundColor = color; } - const LLUIColor& getBackgroundColor() const { return mBackgroundColor; } - void setBackgroundVisible( BOOL b ) { mBgVisible = b; } - void setCanTearOff(BOOL tear_off); - - // add a separator to this menu - virtual BOOL addSeparator(); - - // for branching menu items, bring sub menus up to root level of menu hierarchy - virtual void updateParent( LLView* parentp ); - - // setItemEnabled() - pass the name and the enable flag for a - // menu item. TRUE will make sure it's enabled, FALSE will disable - // it. - void setItemEnabled( const std::string& name, BOOL enable ); - - // propagate message to submenus - void setEnabledSubMenus(BOOL enable); - - void setItemVisible( const std::string& name, BOOL visible); + /*virtual*/ void removeChild( LLView* ctrl); + /*virtual*/ BOOL postBuild(); + + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + + LLMenuGL* findChildMenuByName(const std::string& name, BOOL recurse) const; + + BOOL clearHoverItem(); + + // return the name label + const std::string& getLabel( void ) const { return mLabel.getString(); } + void setLabel(const LLStringExplicit& label) { mLabel = label; } + + // background colors + void setBackgroundColor( const LLUIColor& color ) { mBackgroundColor = color; } + const LLUIColor& getBackgroundColor() const { return mBackgroundColor; } + void setBackgroundVisible( BOOL b ) { mBgVisible = b; } + void setCanTearOff(BOOL tear_off); + + // add a separator to this menu + virtual BOOL addSeparator(); + + // for branching menu items, bring sub menus up to root level of menu hierarchy + virtual void updateParent( LLView* parentp ); + + // setItemEnabled() - pass the name and the enable flag for a + // menu item. TRUE will make sure it's enabled, FALSE will disable + // it. + void setItemEnabled( const std::string& name, BOOL enable ); + + // propagate message to submenus + void setEnabledSubMenus(BOOL enable); + + void setItemVisible( const std::string& name, BOOL visible); void setItemLabel(const std::string &name, const std::string &label); - - // sets the left,bottom corner of menu, useful for popups - void setLeftAndBottom(S32 left, S32 bottom); - virtual BOOL handleJumpKey(KEY key); + // sets the left,bottom corner of menu, useful for popups + void setLeftAndBottom(S32 left, S32 bottom); - virtual BOOL jumpKeysActive(); + virtual BOOL handleJumpKey(KEY key); - virtual BOOL isOpen(); + virtual BOOL jumpKeysActive(); - void needsArrange() { mNeedsArrange = TRUE; } - // Shape this menu to fit the current state of the children, and - // adjust the child rects to fit. This is called automatically - // when you add items. *FIX: We may need to deal with visibility - // arrangement. - virtual void arrange( void ); - void arrangeAndClear( void ); + virtual BOOL isOpen(); - // remove all items on the menu - void empty( void ); + void needsArrange() { mNeedsArrange = TRUE; } + // Shape this menu to fit the current state of the children, and + // adjust the child rects to fit. This is called automatically + // when you add items. *FIX: We may need to deal with visibility + // arrangement. + virtual void arrange( void ); + void arrangeAndClear( void ); - // erase group of items from menu - void erase( S32 begin, S32 end, bool arrange = true ); + // remove all items on the menu + void empty( void ); - // add new item at position - void insert( S32 begin, LLView * ctrl, bool arrange = true ); + // erase group of items from menu + void erase( S32 begin, S32 end, bool arrange = true ); - void setItemLastSelected(LLMenuItemGL* item); // must be in menu - U32 getItemCount(); // number of menu items - LLMenuItemGL* getItem(S32 number); // 0 = first item + // add new item at position + void insert( S32 begin, LLView * ctrl, bool arrange = true ); + + void setItemLastSelected(LLMenuItemGL* item); // must be in menu + U32 getItemCount(); // number of menu items + LLMenuItemGL* getItem(S32 number); // 0 = first item LLMenuItemGL* getItem(std::string name); - LLMenuItemGL* getHighlightedItem(); + LLMenuItemGL* getHighlightedItem(); + + LLMenuItemGL* highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); + LLMenuItemGL* highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); - LLMenuItemGL* highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); - LLMenuItemGL* highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); + void buildDrawLabels(); + void createJumpKeys(); - void buildDrawLabels(); - void createJumpKeys(); + // Show popup at a specific location, in the spawn_view's coordinate frame + static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x = 0, S32 mouse_y = 0); - // Show popup at a specific location, in the spawn_view's coordinate frame - static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x = 0, S32 mouse_y = 0); + // Whether to drop shadow menu bar + void setDropShadowed( const BOOL shadowed ); - // Whether to drop shadow menu bar - void setDropShadowed( const BOOL shadowed ); + void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item->getHandle(); } + LLMenuItemGL* getParentMenuItem() const { return dynamic_cast(mParentMenuItem.get()); } - void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item->getHandle(); } - LLMenuItemGL* getParentMenuItem() const { return dynamic_cast(mParentMenuItem.get()); } + void setTornOff(BOOL torn_off); + BOOL getTornOff() { return mTornOff; } - void setTornOff(BOOL torn_off); - BOOL getTornOff() { return mTornOff; } + BOOL getCanTearOff() { return mTearOffItem != NULL; } - BOOL getCanTearOff() { return mTearOffItem != NULL; } + KEY getJumpKey() const { return mJumpKey; } + void setJumpKey(KEY key) { mJumpKey = key; } - KEY getJumpKey() const { return mJumpKey; } - void setJumpKey(KEY key) { mJumpKey = key; } + static void setKeyboardMode(BOOL mode) { sKeyboardMode = mode; } + static BOOL getKeyboardMode() { return sKeyboardMode; } - static void setKeyboardMode(BOOL mode) { sKeyboardMode = mode; } - static BOOL getKeyboardMode() { return sKeyboardMode; } + S32 getShortcutPad() { return mShortcutPad; } - S32 getShortcutPad() { return mShortcutPad; } + bool scrollItems(EScrollingDirection direction); + BOOL isScrollable() const { return mScrollable; } - bool scrollItems(EScrollingDirection direction); - BOOL isScrollable() const { return mScrollable; } + static class LLMenuHolderGL* sMenuContainer; - static class LLMenuHolderGL* sMenuContainer; - - void resetScrollPositionOnShow(bool reset_scroll_pos) { mResetScrollPositionOnShow = reset_scroll_pos; } - bool isScrollPositionOnShowReset() { return mResetScrollPositionOnShow; } + void resetScrollPositionOnShow(bool reset_scroll_pos) { mResetScrollPositionOnShow = reset_scroll_pos; } + bool isScrollPositionOnShowReset() { return mResetScrollPositionOnShow; } - void setAlwaysShowMenu(BOOL show) { mAlwaysShowMenu = show; } - BOOL getAlwaysShowMenu() { return mAlwaysShowMenu; } + void setAlwaysShowMenu(BOOL show) { mAlwaysShowMenu = show; } + BOOL getAlwaysShowMenu() { return mAlwaysShowMenu; } - // add a context menu branch - BOOL appendContextSubMenu(LLMenuGL *menu); + // add a context menu branch + BOOL appendContextSubMenu(LLMenuGL *menu); // Add the menu item to this menu. virtual BOOL append( LLMenuItemGL* item ); @@ -571,31 +571,31 @@ public: const LLFontGL *getFont() const { return mFont; } protected: - void createSpilloverBranch(); - void cleanupSpilloverBranch(); - - // Used in LLContextMenu and in LLTogleableMenu - // to add an item of context menu branch - bool addContextChild(LLView* view, S32 tab_group); - - // TODO: create accessor methods for these? - typedef std::list< LLMenuItemGL* > item_list_t; - item_list_t mItems; - LLMenuItemGL*mFirstVisibleItem; - LLMenuItemGL *mArrowUpItem, *mArrowDownItem; - - typedef std::map navigation_key_map_t; - navigation_key_map_t mJumpKeys; - S32 mLastMouseX; - S32 mLastMouseY; - S32 mMouseVelX; - S32 mMouseVelY; - U32 mMaxScrollableItems; - U32 mPreferredWidth; - BOOL mHorizontalLayout; - BOOL mScrollable; - BOOL mKeepFixedSize; - BOOL mNeedsArrange; + void createSpilloverBranch(); + void cleanupSpilloverBranch(); + + // Used in LLContextMenu and in LLTogleableMenu + // to add an item of context menu branch + bool addContextChild(LLView* view, S32 tab_group); + + // TODO: create accessor methods for these? + typedef std::list< LLMenuItemGL* > item_list_t; + item_list_t mItems; + LLMenuItemGL*mFirstVisibleItem; + LLMenuItemGL *mArrowUpItem, *mArrowDownItem; + + typedef std::map navigation_key_map_t; + navigation_key_map_t mJumpKeys; + S32 mLastMouseX; + S32 mLastMouseY; + S32 mMouseVelX; + S32 mMouseVelY; + U32 mMaxScrollableItems; + U32 mPreferredWidth; + BOOL mHorizontalLayout; + BOOL mScrollable; + BOOL mKeepFixedSize; + BOOL mNeedsArrange; // Font for top menu items only const LLFontGL* mFont; @@ -603,27 +603,27 @@ protected: private: - static LLColor4 sDefaultBackgroundColor; - static BOOL sKeyboardMode; - - BOOL mAlwaysShowMenu; - - LLUIColor mBackgroundColor; - BOOL mBgVisible; - LLHandle mParentMenuItem; - LLUIString mLabel; - BOOL mDropShadowed; // Whether to drop shadow - bool mHasSelection; - LLFrameTimer mFadeTimer; - LLTimer mScrollItemsTimer; - BOOL mTornOff; - class LLMenuItemTearOffGL* mTearOffItem; - class LLMenuItemBranchGL* mSpilloverBranch; - LLMenuGL* mSpilloverMenu; - KEY mJumpKey; - BOOL mCreateJumpKeys; - S32 mShortcutPad; - bool mResetScrollPositionOnShow; + static LLColor4 sDefaultBackgroundColor; + static BOOL sKeyboardMode; + + BOOL mAlwaysShowMenu; + + LLUIColor mBackgroundColor; + BOOL mBgVisible; + LLHandle mParentMenuItem; + LLUIString mLabel; + BOOL mDropShadowed; // Whether to drop shadow + bool mHasSelection; + LLFrameTimer mFadeTimer; + LLTimer mScrollItemsTimer; + BOOL mTornOff; + class LLMenuItemTearOffGL* mTearOffItem; + class LLMenuItemBranchGL* mSpilloverBranch; + LLMenuGL* mSpilloverMenu; + KEY mJumpKey; + BOOL mCreateJumpKeys; + S32 mShortcutPad; + bool mResetScrollPositionOnShow; }; // end class LLMenuGL @@ -638,61 +638,61 @@ private: class LLMenuItemBranchGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block - { - Optional branch; - }; + struct Params : public LLInitParam::Block + { + Optional branch; + }; protected: - LLMenuItemBranchGL(const Params&); - friend class LLUICtrlFactory; + LLMenuItemBranchGL(const Params&); + friend class LLUICtrlFactory; public: - virtual ~LLMenuItemBranchGL(); - - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual ~LLMenuItemBranchGL(); - virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - // check if we've used these accelerators already - virtual BOOL addToAcceleratorList(std::list *listp); + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - // called to rebuild the draw label - virtual void buildDrawLabel( void ); + // check if we've used these accelerators already + virtual BOOL addToAcceleratorList(std::list *listp); - virtual void onCommit( void ); + // called to rebuild the draw label + virtual void buildDrawLabel( void ); - virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + virtual void onCommit( void ); - // set the hover status (called by it's menu) and if the object is - // active. This is used for behavior transfer. - virtual void setHighlight( BOOL highlight ); + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); - virtual BOOL handleKeyHere(KEY key, MASK mask); + // set the hover status (called by it's menu) and if the object is + // active. This is used for behavior transfer. + virtual void setHighlight( BOOL highlight ); - virtual BOOL isActive() const; + virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual BOOL isOpen() const; + virtual BOOL isActive() const; - LLMenuGL* getBranch() const { return (LLMenuGL*)mBranchHandle.get(); } + virtual BOOL isOpen() const; - virtual void updateBranchParent( LLView* parentp ); + LLMenuGL* getBranch() const { return (LLMenuGL*)mBranchHandle.get(); } - // LLView Functionality - virtual void onVisibilityChange( BOOL curVisibilityIn ); + virtual void updateBranchParent( LLView* parentp ); - virtual void draw(); + // LLView Functionality + virtual void onVisibilityChange( BOOL curVisibilityIn ); - virtual void setEnabledSubMenus(BOOL enabled) { if (getBranch()) getBranch()->setEnabledSubMenus(enabled); } + virtual void draw(); - virtual void openMenu(); + virtual void setEnabledSubMenus(BOOL enabled) { if (getBranch()) getBranch()->setEnabledSubMenus(enabled); } - virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE) const; - virtual LLView* findChildView(const std::string& name, BOOL recurse = TRUE) const; + virtual void openMenu(); + + virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE) const; + virtual LLView* findChildView(const std::string& name, BOOL recurse = TRUE) const; private: - LLHandle mBranchHandle; + LLHandle mBranchHandle; }; // end class LLMenuItemBranchGL @@ -705,44 +705,44 @@ class LLContextMenu : public LLMenuGL { public: - struct Params : public LLInitParam::Block - { - Params() - { - changeDefault(visible, false); - } - }; + struct Params : public LLInitParam::Block + { + Params() + { + changeDefault(visible, false); + } + }; protected: - LLContextMenu(const Params& p); - friend class LLUICtrlFactory; + LLContextMenu(const Params& p); + friend class LLUICtrlFactory; public: - virtual ~LLContextMenu() {} + virtual ~LLContextMenu() {} + + // LLView Functionality + // can't set visibility directly, must call show or hide + virtual void setVisible (BOOL visible); - // LLView Functionality - // can't set visibility directly, must call show or hide - virtual void setVisible (BOOL visible); - - virtual void show (S32 x, S32 y, LLView* spawning_view = NULL); - virtual void hide (); + virtual void show (S32 x, S32 y, LLView* spawning_view = NULL); + virtual void hide (); - virtual BOOL handleHover ( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseUp ( S32 x, S32 y, MASK mask ); + virtual BOOL handleHover ( S32 x, S32 y, MASK mask ); + virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleRightMouseUp ( S32 x, S32 y, MASK mask ); - virtual bool addChild (LLView* view, S32 tab_group = 0); + virtual bool addChild (LLView* view, S32 tab_group = 0); - LLHandle getHandle() { return getDerivedHandle(); } + LLHandle getHandle() { return getDerivedHandle(); } - LLView* getSpawningView() const { return mSpawningViewHandle.get(); } - void setSpawningView(LLHandle spawning_view) { mSpawningViewHandle = spawning_view; } + LLView* getSpawningView() const { return mSpawningViewHandle.get(); } + void setSpawningView(LLHandle spawning_view) { mSpawningViewHandle = spawning_view; } protected: - BOOL mHoveredAnyItem; - LLMenuItemGL* mHoverItem; - LLRootHandle mHandle; - LLHandle mSpawningViewHandle; + BOOL mHoveredAnyItem; + LLMenuItemGL* mHoverItem; + LLRootHandle mHandle; + LLHandle mSpawningViewHandle; }; //----------------------------------------------------------------------------- @@ -752,28 +752,28 @@ protected: class LLContextMenuBranch : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block - { - Mandatory branch; - }; + struct Params : public LLInitParam::Block + { + Mandatory branch; + }; - LLContextMenuBranch(const Params&); + LLContextMenuBranch(const Params&); - virtual ~LLContextMenuBranch(); + virtual ~LLContextMenuBranch(); - // called to rebuild the draw label - virtual void buildDrawLabel( void ); + // called to rebuild the draw label + virtual void buildDrawLabel( void ); - // onCommit() - do the primary funcationality of the menu item. - virtual void onCommit( void ); + // onCommit() - do the primary funcationality of the menu item. + virtual void onCommit( void ); - LLContextMenu* getBranch() { return mBranch.get(); } - void setHighlight( BOOL highlight ); + LLContextMenu* getBranch() { return mBranch.get(); } + void setHighlight( BOOL highlight ); protected: - void showSubMenu(); + void showSubMenu(); - LLHandle mBranch; + LLHandle mBranch; }; @@ -786,43 +786,43 @@ protected: class LLMenuBarGL : public LLMenuGL { public: - struct Params : public LLInitParam::Block - {}; - LLMenuBarGL( const Params& p ); - virtual ~LLMenuBarGL(); + struct Params : public LLInitParam::Block + {}; + LLMenuBarGL( const Params& p ); + virtual ~LLMenuBarGL(); - /*virtual*/ BOOL handleAcceleratorKey(KEY key, MASK mask); - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); - /*virtual*/ BOOL handleJumpKey(KEY key); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleAcceleratorKey(KEY key, MASK mask); + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); + /*virtual*/ BOOL handleJumpKey(KEY key); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - /*virtual*/ void draw(); - /*virtual*/ BOOL jumpKeysActive(); + /*virtual*/ void draw(); + /*virtual*/ BOOL jumpKeysActive(); - // add a vertical separator to this menu - virtual BOOL addSeparator(); + // add a vertical separator to this menu + virtual BOOL addSeparator(); - // LLView Functionality - virtual BOOL handleHover( S32 x, S32 y, MASK mask ); + // LLView Functionality + virtual BOOL handleHover( S32 x, S32 y, MASK mask ); - // Returns x position of rightmost child, usually Help menu - S32 getRightmostMenuEdge(); + // Returns x position of rightmost child, usually Help menu + S32 getRightmostMenuEdge(); - void resetMenuTrigger() { mAltKeyTrigger = FALSE; } + void resetMenuTrigger() { mAltKeyTrigger = FALSE; } // add a menu - this will create a drop down menu. virtual BOOL appendMenu(LLMenuGL *menu); private: - // rearrange the child rects so they fit the shape of the menu - // bar. - virtual void arrange( void ); + // rearrange the child rects so they fit the shape of the menu + // bar. + virtual void arrange( void ); - void checkMenuTrigger(); + void checkMenuTrigger(); - std::list mAccelerators; - BOOL mAltKeyTrigger; + std::list mAccelerators; + BOOL mAltKeyTrigger; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -833,39 +833,39 @@ private: class LLMenuHolderGL : public LLPanel { public: - struct Params : public LLInitParam::Block - {}; - LLMenuHolderGL(const Params& p); - virtual ~LLMenuHolderGL() {} + struct Params : public LLInitParam::Block + {}; + LLMenuHolderGL(const Params& p); + virtual ~LLMenuHolderGL() {} - virtual BOOL hideMenus(); - void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - void setCanHide(BOOL can_hide) { mCanHide = can_hide; } + virtual BOOL hideMenus(); + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + void setCanHide(BOOL can_hide) { mCanHide = can_hide; } - // LLView functionality - virtual void draw(); - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + // LLView functionality + virtual void draw(); + virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - // Close context menus on right mouse up not handled by menus. - /*virtual*/ BOOL handleRightMouseUp( S32 x, S32 y, MASK mask ); + // Close context menus on right mouse up not handled by menus. + /*virtual*/ BOOL handleRightMouseUp( S32 x, S32 y, MASK mask ); - virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - virtual const LLRect getMenuRect() const { return getLocalRect(); } - LLView*const getVisibleMenu() const; - virtual BOOL hasVisibleMenu() const {return getVisibleMenu() != NULL;} + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual const LLRect getMenuRect() const { return getLocalRect(); } + LLView*const getVisibleMenu() const; + virtual BOOL hasVisibleMenu() const {return getVisibleMenu() != NULL;} - static void setActivatedItem(LLMenuItemGL* item); + static void setActivatedItem(LLMenuItemGL* item); - // Need to detect if mouse-up after context menu spawn has moved. - // If not, need to keep the menu up. - static LLCoordGL sContextMenuSpawnPos; + // Need to detect if mouse-up after context menu spawn has moved. + // If not, need to keep the menu up. + static LLCoordGL sContextMenuSpawnPos; private: - static LLHandle sItemLastSelectedHandle; - static LLFrameTimer sItemActivationTimer; + static LLHandle sItemLastSelectedHandle; + static LLFrameTimer sItemActivationTimer; - BOOL mCanHide; + BOOL mCanHide; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -877,26 +877,26 @@ private: class LLTearOffMenu : public LLFloater { public: - static LLTearOffMenu* create(LLMenuGL* menup); - virtual ~LLTearOffMenu(); + static LLTearOffMenu* create(LLMenuGL* menup); + virtual ~LLTearOffMenu(); - virtual void draw(void); - virtual void onFocusReceived(); - virtual void onFocusLost(); - virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); - virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual void translate(S32 x, S32 y); + virtual void draw(void); + virtual void onFocusReceived(); + virtual void onFocusLost(); + virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual void translate(S32 x, S32 y); - void updateSize(); + void updateSize(); private: - LLTearOffMenu(LLMenuGL* menup); - - void closeTearOff(); - - LLView* mOldParent; - LLMenuGL* mMenu; - S32 mTargetHeight; + LLTearOffMenu(LLMenuGL* menup); + + void closeTearOff(); + + LLView* mOldParent; + LLMenuGL* mMenu; + S32 mTargetHeight; bool mQuitRequested; }; @@ -909,16 +909,16 @@ private: class LLMenuItemTearOffGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block - {}; + struct Params : public LLInitParam::Block + {}; + + LLMenuItemTearOffGL( const Params& ); - LLMenuItemTearOffGL( const Params& ); - - virtual void onCommit(void); - virtual void draw(void); - virtual U32 getNominalHeight() const; + virtual void onCommit(void); + virtual void draw(void); + virtual U32 getNominalHeight() const; - LLFloater* getParentFloater(); + LLFloater* getParentFloater(); }; @@ -926,13 +926,13 @@ public: class LLEditMenuHandlerMgr { public: - LLEditMenuHandlerMgr& getInstance() { - static LLEditMenuHandlerMgr instance; - return instance; - } - virtual ~LLEditMenuHandlerMgr() {} + LLEditMenuHandlerMgr& getInstance() { + static LLEditMenuHandlerMgr instance; + return instance; + } + virtual ~LLEditMenuHandlerMgr() {} private: - LLEditMenuHandlerMgr() {}; + LLEditMenuHandlerMgr() {}; }; @@ -941,40 +941,40 @@ private: class view_listener_t : public boost::signals2::trackable { public: - virtual bool handleEvent(const LLSD& userdata) = 0; - view_listener_t() { sListeners.insert(this); } - virtual ~view_listener_t() { sListeners.erase(this); } - - static void addEnable(view_listener_t* listener, const std::string& name) - { - LLUICtrl::EnableCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); - } - - static void addCommit(view_listener_t* listener, const std::string& name) - { - LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); - } - - static void addMenu(view_listener_t* listener, const std::string& name) - { - // For now, add to both click and enable registries - addEnable(listener, name); - addCommit(listener, name); - } - - static void cleanup() - { - listener_vector_t listeners(sListeners.begin(), sListeners.end()); - sListeners.clear(); - - std::for_each(listeners.begin(), listeners.end(), DeletePointer()); - listeners.clear(); - } + virtual bool handleEvent(const LLSD& userdata) = 0; + view_listener_t() { sListeners.insert(this); } + virtual ~view_listener_t() { sListeners.erase(this); } + + static void addEnable(view_listener_t* listener, const std::string& name) + { + LLUICtrl::EnableCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); + } + + static void addCommit(view_listener_t* listener, const std::string& name) + { + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); + } + + static void addMenu(view_listener_t* listener, const std::string& name) + { + // For now, add to both click and enable registries + addEnable(listener, name); + addCommit(listener, name); + } + + static void cleanup() + { + listener_vector_t listeners(sListeners.begin(), sListeners.end()); + sListeners.clear(); + + std::for_each(listeners.begin(), listeners.end(), DeletePointer()); + listeners.clear(); + } private: - typedef std::set listener_map_t; - typedef std::vector listener_vector_t; - static listener_map_t sListeners; + typedef std::set listener_map_t; + typedef std::vector listener_vector_t; + static listener_map_t sListeners; }; #endif // LL_LLMENUGL_H diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index d6fc7d5377..348a4603de 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1,24 +1,24 @@ -/** +/** * @file lltexteditor.cpp * * $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$ */ @@ -32,7 +32,7 @@ #include "llfontfreetype.h" // for LLFontFreetype::FIRST_CHAR #include "llfontgl.h" -#include "llgl.h" // LLGLSUIDefault() +#include "llgl.h" // LLGLSUIDefault() #include "lllocalcliprect.h" #include "llrender.h" #include "llui.h" @@ -64,105 +64,105 @@ #include #include "llcombobox.h" -// +// // Globals // static LLDefaultChildRegistry::Register r("simple_text_editor"); // Compiler optimization, generate extern template template class LLTextEditor* LLView::getChild( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; // // Constants // -const S32 SPACES_PER_TAB = 4; -const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on +const S32 SPACES_PER_TAB = 4; +const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on /////////////////////////////////////////////////////////////////// class LLTextEditor::TextCmdInsert : public LLTextBase::TextCmd { public: - TextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws, LLTextSegmentPtr segment) - : TextCmd(pos, group_with_next, segment), mWString(ws) - { - } - virtual ~TextCmdInsert() {} - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - *delta = insert(editor, getPosition(), mWString ); - LLWStringUtil::truncate(mWString, *delta); - //mWString = wstring_truncate(mWString, *delta); - return (*delta != 0); - } - virtual S32 undo( LLTextBase* editor ) - { - remove(editor, getPosition(), mWString.length() ); - return getPosition(); - } - virtual S32 redo( LLTextBase* editor ) - { - insert(editor, getPosition(), mWString ); - return getPosition() + mWString.length(); - } + TextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws, LLTextSegmentPtr segment) + : TextCmd(pos, group_with_next, segment), mWString(ws) + { + } + virtual ~TextCmdInsert() {} + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + *delta = insert(editor, getPosition(), mWString ); + LLWStringUtil::truncate(mWString, *delta); + //mWString = wstring_truncate(mWString, *delta); + return (*delta != 0); + } + virtual S32 undo( LLTextBase* editor ) + { + remove(editor, getPosition(), mWString.length() ); + return getPosition(); + } + virtual S32 redo( LLTextBase* editor ) + { + insert(editor, getPosition(), mWString ); + return getPosition() + mWString.length(); + } private: - LLWString mWString; + LLWString mWString; }; /////////////////////////////////////////////////////////////////// class LLTextEditor::TextCmdAddChar : public LLTextBase::TextCmd { public: - TextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc, LLTextSegmentPtr segment) - : TextCmd(pos, group_with_next, segment), mWString(1, wc), mBlockExtensions(FALSE) - { - } - virtual void blockExtensions() - { - mBlockExtensions = TRUE; - } - virtual BOOL canExtend(S32 pos) const - { - // cannot extend text with custom segments - if (!mSegments.empty()) return FALSE; - - return !mBlockExtensions && (pos == getPosition() + (S32)mWString.length()); - } - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - *delta = insert(editor, getPosition(), mWString); - LLWStringUtil::truncate(mWString, *delta); - //mWString = wstring_truncate(mWString, *delta); - return (*delta != 0); - } - virtual BOOL extendAndExecute( LLTextBase* editor, S32 pos, llwchar wc, S32* delta ) - { - LLWString ws; - ws += wc; - - *delta = insert(editor, pos, ws); - if( *delta > 0 ) - { - mWString += wc; - } - return (*delta != 0); - } - virtual S32 undo( LLTextBase* editor ) - { - remove(editor, getPosition(), mWString.length() ); - return getPosition(); - } - virtual S32 redo( LLTextBase* editor ) - { - insert(editor, getPosition(), mWString ); - return getPosition() + mWString.length(); - } + TextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc, LLTextSegmentPtr segment) + : TextCmd(pos, group_with_next, segment), mWString(1, wc), mBlockExtensions(FALSE) + { + } + virtual void blockExtensions() + { + mBlockExtensions = TRUE; + } + virtual BOOL canExtend(S32 pos) const + { + // cannot extend text with custom segments + if (!mSegments.empty()) return FALSE; + + return !mBlockExtensions && (pos == getPosition() + (S32)mWString.length()); + } + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + *delta = insert(editor, getPosition(), mWString); + LLWStringUtil::truncate(mWString, *delta); + //mWString = wstring_truncate(mWString, *delta); + return (*delta != 0); + } + virtual BOOL extendAndExecute( LLTextBase* editor, S32 pos, llwchar wc, S32* delta ) + { + LLWString ws; + ws += wc; + + *delta = insert(editor, pos, ws); + if( *delta > 0 ) + { + mWString += wc; + } + return (*delta != 0); + } + virtual S32 undo( LLTextBase* editor ) + { + remove(editor, getPosition(), mWString.length() ); + return getPosition(); + } + virtual S32 redo( LLTextBase* editor ) + { + insert(editor, getPosition(), mWString ); + return getPosition() + mWString.length(); + } private: - LLWString mWString; - BOOL mBlockExtensions; + LLWString mWString; + BOOL mBlockExtensions; }; @@ -171,30 +171,30 @@ private: class LLTextEditor::TextCmdOverwriteChar : public LLTextBase::TextCmd { public: - TextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc) - : TextCmd(pos, group_with_next), mChar(wc), mOldChar(0) {} - - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - mOldChar = editor->getWText()[getPosition()]; - overwrite(editor, getPosition(), mChar); - *delta = 0; - return TRUE; - } - virtual S32 undo( LLTextBase* editor ) - { - overwrite(editor, getPosition(), mOldChar); - return getPosition(); - } - virtual S32 redo( LLTextBase* editor ) - { - overwrite(editor, getPosition(), mChar); - return getPosition()+1; - } + TextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc) + : TextCmd(pos, group_with_next), mChar(wc), mOldChar(0) {} + + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + mOldChar = editor->getWText()[getPosition()]; + overwrite(editor, getPosition(), mChar); + *delta = 0; + return TRUE; + } + virtual S32 undo( LLTextBase* editor ) + { + overwrite(editor, getPosition(), mOldChar); + return getPosition(); + } + virtual S32 redo( LLTextBase* editor ) + { + overwrite(editor, getPosition(), mChar); + return getPosition()+1; + } private: - llwchar mChar; - llwchar mOldChar; + llwchar mChar; + llwchar mOldChar; }; /////////////////////////////////////////////////////////////////// @@ -202,114 +202,114 @@ private: class LLTextEditor::TextCmdRemove : public LLTextBase::TextCmd { public: - TextCmdRemove( S32 pos, BOOL group_with_next, S32 len, segment_vec_t& segments ) : - TextCmd(pos, group_with_next), mLen(len) - { - std::swap(mSegments, segments); - } - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - mWString = editor->getWText().substr(getPosition(), mLen); - *delta = remove(editor, getPosition(), mLen ); - return (*delta != 0); - } - virtual S32 undo( LLTextBase* editor ) - { - insert(editor, getPosition(), mWString); - return getPosition() + mWString.length(); - } - virtual S32 redo( LLTextBase* editor ) - { - remove(editor, getPosition(), mLen ); - return getPosition(); - } + TextCmdRemove( S32 pos, BOOL group_with_next, S32 len, segment_vec_t& segments ) : + TextCmd(pos, group_with_next), mLen(len) + { + std::swap(mSegments, segments); + } + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + mWString = editor->getWText().substr(getPosition(), mLen); + *delta = remove(editor, getPosition(), mLen ); + return (*delta != 0); + } + virtual S32 undo( LLTextBase* editor ) + { + insert(editor, getPosition(), mWString); + return getPosition() + mWString.length(); + } + virtual S32 redo( LLTextBase* editor ) + { + remove(editor, getPosition(), mLen ); + return getPosition(); + } private: - LLWString mWString; - S32 mLen; + LLWString mWString; + S32 mLen; }; /////////////////////////////////////////////////////////////////// LLTextEditor::Params::Params() -: default_text("default_text"), - prevalidate_callback("prevalidate_callback"), - embedded_items("embedded_items", false), - ignore_tab("ignore_tab", true), - auto_indent("auto_indent", true), - default_color("default_color"), +: default_text("default_text"), + prevalidate_callback("prevalidate_callback"), + embedded_items("embedded_items", false), + ignore_tab("ignore_tab", true), + auto_indent("auto_indent", true), + default_color("default_color"), commit_on_focus_lost("commit_on_focus_lost", false), - show_context_menu("show_context_menu"), - show_emoji_helper("show_emoji_helper"), - enable_tooltip_paste("enable_tooltip_paste") + show_context_menu("show_context_menu"), + show_emoji_helper("show_emoji_helper"), + enable_tooltip_paste("enable_tooltip_paste") { - addSynonym(prevalidate_callback, "text_type"); + addSynonym(prevalidate_callback, "text_type"); } LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : - LLTextBase(p), - mAutoreplaceCallback(), - mBaseDocIsPristine(TRUE), - mPristineCmd( NULL ), - mLastCmd( NULL ), - mDefaultColor( p.default_color() ), - mAutoIndent(p.auto_indent), - mCommitOnFocusLost( p.commit_on_focus_lost), - mAllowEmbeddedItems( p.embedded_items ), - mMouseDownX(0), - mMouseDownY(0), - mTabsToNextField(p.ignore_tab), - mPrevalidateFunc(p.prevalidate_callback()), - mShowContextMenu(p.show_context_menu), - mShowEmojiHelper(p.show_emoji_helper), - mEnableTooltipPaste(p.enable_tooltip_paste), - mPassDelete(FALSE), - mKeepSelectionOnReturn(false) -{ - mSourceID.generate(); - - //FIXME: use image? - LLViewBorder::Params params; - params.name = "text ed border"; - params.rect = getLocalRect(); - params.bevel_style = LLViewBorder::BEVEL_IN; - params.border_thickness = 1; - params.visible = p.border_visible; - mBorder = LLUICtrlFactory::create (params); - addChild( mBorder ); - setText(p.default_text()); - - mParseOnTheFly = TRUE; + LLTextBase(p), + mAutoreplaceCallback(), + mBaseDocIsPristine(TRUE), + mPristineCmd( NULL ), + mLastCmd( NULL ), + mDefaultColor( p.default_color() ), + mAutoIndent(p.auto_indent), + mCommitOnFocusLost( p.commit_on_focus_lost), + mAllowEmbeddedItems( p.embedded_items ), + mMouseDownX(0), + mMouseDownY(0), + mTabsToNextField(p.ignore_tab), + mPrevalidateFunc(p.prevalidate_callback()), + mShowContextMenu(p.show_context_menu), + mShowEmojiHelper(p.show_emoji_helper), + mEnableTooltipPaste(p.enable_tooltip_paste), + mPassDelete(FALSE), + mKeepSelectionOnReturn(false) +{ + mSourceID.generate(); + + //FIXME: use image? + LLViewBorder::Params params; + params.name = "text ed border"; + params.rect = getLocalRect(); + params.bevel_style = LLViewBorder::BEVEL_IN; + params.border_thickness = 1; + params.visible = p.border_visible; + mBorder = LLUICtrlFactory::create (params); + addChild( mBorder ); + setText(p.default_text()); + + mParseOnTheFly = TRUE; } void LLTextEditor::initFromParams( const LLTextEditor::Params& p) { - LLTextBase::initFromParams(p); + LLTextBase::initFromParams(p); - // HACK: text editors always need to be enabled so that we can scroll - LLView::setEnabled(true); + // HACK: text editors always need to be enabled so that we can scroll + LLView::setEnabled(true); + + if (p.commit_on_focus_lost.isProvided()) + { + mCommitOnFocusLost = p.commit_on_focus_lost; + } - if (p.commit_on_focus_lost.isProvided()) - { - mCommitOnFocusLost = p.commit_on_focus_lost; - } - - updateAllowingLanguageInput(); + updateAllowingLanguageInput(); } LLTextEditor::~LLTextEditor() { - gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() while LLTextEditor still valid + gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() while LLTextEditor still valid - // Scrollbar is deleted by LLView - std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); - mUndoStack.clear(); - // Mark the menu as dead or its retained in memory till shutdown. - LLContextMenu* menu = static_cast(mContextMenuHandle.get()); - if(menu) - { - menu->die(); - mContextMenuHandle.markDead(); - } + // Scrollbar is deleted by LLView + std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); + mUndoStack.clear(); + // Mark the menu as dead or its retained in memory till shutdown. + LLContextMenu* menu = static_cast(mContextMenuHandle.get()); + if(menu) + { + menu->die(); + mContextMenuHandle.markDead(); + } } //////////////////////////////////////////////////////////// @@ -318,649 +318,649 @@ LLTextEditor::~LLTextEditor() void LLTextEditor::setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params) { - // validate incoming text if necessary - if (mPrevalidateFunc) - { - LLWString test_text = utf8str_to_wstring(utf8str); - if (!mPrevalidateFunc(test_text)) - { - // not valid text, nothing to do - return; - } - } + // validate incoming text if necessary + if (mPrevalidateFunc) + { + LLWString test_text = utf8str_to_wstring(utf8str); + if (!mPrevalidateFunc(test_text)) + { + // not valid text, nothing to do + return; + } + } - blockUndo(); - deselect(); - - mParseOnTheFly = FALSE; - LLTextBase::setText(utf8str, input_params); - mParseOnTheFly = TRUE; + blockUndo(); + deselect(); - resetDirty(); + mParseOnTheFly = FALSE; + LLTextBase::setText(utf8str, input_params); + mParseOnTheFly = TRUE; + + resetDirty(); } void LLTextEditor::selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap) { - if (search_text_in.empty()) - { - return; - } - - LLWString text = getWText(); - LLWString search_text = utf8str_to_wstring(search_text_in); - if (case_insensitive) - { - LLWStringUtil::toLower(text); - LLWStringUtil::toLower(search_text); - } - - if (mIsSelecting) - { - LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); - - if (selected_text == search_text) - { - // We already have this word selected, we are searching for the next. - setCursorPos(mCursorPos + search_text.size()); - } - } - - S32 loc = text.find(search_text,mCursorPos); - - // If Maybe we wrapped, search again - if (wrap && (-1 == loc)) - { - loc = text.find(search_text); - } - - // If still -1, then search_text just isn't found. + if (search_text_in.empty()) + { + return; + } + + LLWString text = getWText(); + LLWString search_text = utf8str_to_wstring(search_text_in); + if (case_insensitive) + { + LLWStringUtil::toLower(text); + LLWStringUtil::toLower(search_text); + } + + if (mIsSelecting) + { + LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); + + if (selected_text == search_text) + { + // We already have this word selected, we are searching for the next. + setCursorPos(mCursorPos + search_text.size()); + } + } + + S32 loc = text.find(search_text,mCursorPos); + + // If Maybe we wrapped, search again + if (wrap && (-1 == loc)) + { + loc = text.find(search_text); + } + + // If still -1, then search_text just isn't found. if (-1 == loc) - { - mIsSelecting = FALSE; - mSelectionEnd = 0; - mSelectionStart = 0; - return; - } + { + mIsSelecting = FALSE; + mSelectionEnd = 0; + mSelectionStart = 0; + return; + } + + setCursorPos(loc); - setCursorPos(loc); - - mIsSelecting = TRUE; - mSelectionEnd = mCursorPos; - mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size())); + mIsSelecting = TRUE; + mSelectionEnd = mCursorPos; + mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size())); } BOOL LLTextEditor::replaceText(const std::string& search_text_in, const std::string& replace_text, - BOOL case_insensitive, BOOL wrap) + BOOL case_insensitive, BOOL wrap) { - BOOL replaced = FALSE; + BOOL replaced = FALSE; - if (search_text_in.empty()) - { - return replaced; - } + if (search_text_in.empty()) + { + return replaced; + } - LLWString search_text = utf8str_to_wstring(search_text_in); - if (mIsSelecting) - { - LLWString text = getWText(); - LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); + LLWString search_text = utf8str_to_wstring(search_text_in); + if (mIsSelecting) + { + LLWString text = getWText(); + LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); - if (case_insensitive) - { - LLWStringUtil::toLower(selected_text); - LLWStringUtil::toLower(search_text); - } + if (case_insensitive) + { + LLWStringUtil::toLower(selected_text); + LLWStringUtil::toLower(search_text); + } - if (selected_text == search_text) - { - insertText(replace_text); - replaced = TRUE; - } - } + if (selected_text == search_text) + { + insertText(replace_text); + replaced = TRUE; + } + } - selectNext(search_text_in, case_insensitive, wrap); - return replaced; + selectNext(search_text_in, case_insensitive, wrap); + return replaced; } void LLTextEditor::replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive) { - startOfDoc(); - selectNext(search_text, case_insensitive, FALSE); + startOfDoc(); + selectNext(search_text, case_insensitive, FALSE); - BOOL replaced = TRUE; - while ( replaced ) - { - replaced = replaceText(search_text,replace_text, case_insensitive, FALSE); - } + BOOL replaced = TRUE; + while ( replaced ) + { + replaced = replaceText(search_text,replace_text, case_insensitive, FALSE); + } } S32 LLTextEditor::prevWordPos(S32 cursorPos) const { - LLWString wtext(getWText()); - while( (cursorPos > 0) && (wtext[cursorPos-1] == ' ') ) - { - cursorPos--; - } - while( (cursorPos > 0) && LLWStringUtil::isPartOfWord( wtext[cursorPos-1] ) ) - { - cursorPos--; - } - return cursorPos; + LLWString wtext(getWText()); + while( (cursorPos > 0) && (wtext[cursorPos-1] == ' ') ) + { + cursorPos--; + } + while( (cursorPos > 0) && LLWStringUtil::isPartOfWord( wtext[cursorPos-1] ) ) + { + cursorPos--; + } + return cursorPos; } S32 LLTextEditor::nextWordPos(S32 cursorPos) const { - LLWString wtext(getWText()); - while( (cursorPos < getLength()) && LLWStringUtil::isPartOfWord( wtext[cursorPos] ) ) - { - cursorPos++; - } - while( (cursorPos < getLength()) && (wtext[cursorPos] == ' ') ) - { - cursorPos++; - } - return cursorPos; + LLWString wtext(getWText()); + while( (cursorPos < getLength()) && LLWStringUtil::isPartOfWord( wtext[cursorPos] ) ) + { + cursorPos++; + } + while( (cursorPos < getLength()) && (wtext[cursorPos] == ' ') ) + { + cursorPos++; + } + return cursorPos; } -const LLTextSegmentPtr LLTextEditor::getPreviousSegment() const +const LLTextSegmentPtr LLTextEditor::getPreviousSegment() const { - static LLPointer index_segment = new LLIndexSegment; + static LLPointer index_segment = new LLIndexSegment; - index_segment->setStart(mCursorPos); - index_segment->setEnd(mCursorPos); + index_segment->setStart(mCursorPos); + index_segment->setEnd(mCursorPos); - // find segment index at character to left of cursor (or rightmost edge of selection) - segment_set_t::const_iterator it = mSegments.lower_bound(index_segment); + // find segment index at character to left of cursor (or rightmost edge of selection) + segment_set_t::const_iterator it = mSegments.lower_bound(index_segment); - if (it != mSegments.end()) - { - return *it; - } - else - { - return LLTextSegmentPtr(); - } + if (it != mSegments.end()) + { + return *it; + } + else + { + return LLTextSegmentPtr(); + } } void LLTextEditor::getSelectedSegments(LLTextEditor::segment_vec_t& segments) const { - S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos; - S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos; + S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos; + S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos; - return getSegmentsInRange(segments, left, right, true); + return getSegmentsInRange(segments, left, right, true); } void LLTextEditor::getSegmentsInRange(LLTextEditor::segment_vec_t& segments_out, S32 start, S32 end, bool include_partial) const { - segment_set_t::const_iterator first_it = getSegIterContaining(start); - segment_set_t::const_iterator end_it = getSegIterContaining(end - 1); - if (end_it != mSegments.end()) ++end_it; + segment_set_t::const_iterator first_it = getSegIterContaining(start); + segment_set_t::const_iterator end_it = getSegIterContaining(end - 1); + if (end_it != mSegments.end()) ++end_it; - for (segment_set_t::const_iterator it = first_it; it != end_it; ++it) - { - LLTextSegmentPtr segment = *it; - if (include_partial - || (segment->getStart() >= start - && segment->getEnd() <= end)) - { - segments_out.push_back(segment); - } - } + for (segment_set_t::const_iterator it = first_it; it != end_it; ++it) + { + LLTextSegmentPtr segment = *it; + if (include_partial + || (segment->getStart() >= start + && segment->getEnd() <= end)) + { + segments_out.push_back(segment); + } + } } void LLTextEditor::setShowEmojiHelper(bool show) { - if (!mShowEmojiHelper) - { - LLEmojiHelper::instance().hideHelper(this); - } + if (!mShowEmojiHelper) + { + LLEmojiHelper::instance().hideHelper(this); + } - mShowEmojiHelper = show; + mShowEmojiHelper = show; } BOOL LLTextEditor::selectionContainsLineBreaks() { - if (hasSelection()) - { - S32 left = llmin(mSelectionStart, mSelectionEnd); - S32 right = left + llabs(mSelectionStart - mSelectionEnd); + if (hasSelection()) + { + S32 left = llmin(mSelectionStart, mSelectionEnd); + S32 right = left + llabs(mSelectionStart - mSelectionEnd); - LLWString wtext = getWText(); - for( S32 i = left; i < right; i++ ) - { - if (wtext[i] == '\n') - { - return TRUE; - } - } - } - return FALSE; + LLWString wtext = getWText(); + for( S32 i = left; i < right; i++ ) + { + if (wtext[i] == '\n') + { + return TRUE; + } + } + } + return FALSE; } S32 LLTextEditor::indentLine( S32 pos, S32 spaces ) { - // Assumes that pos is at the start of the line - // spaces may be positive (indent) or negative (unindent). - // Returns the actual number of characters added or removed. - - llassert(pos >= 0); - llassert(pos <= getLength() ); - - S32 delta_spaces = 0; - - if (spaces >= 0) - { - // Indent - for(S32 i=0; i < spaces; i++) - { - delta_spaces += addChar(pos, ' '); - } - } - else - { - // Unindent - for(S32 i=0; i < -spaces; i++) - { - LLWString wtext = getWText(); - if (wtext[pos] == ' ') - { - delta_spaces += remove( pos, 1, FALSE ); - } - } - } - - return delta_spaces; + // Assumes that pos is at the start of the line + // spaces may be positive (indent) or negative (unindent). + // Returns the actual number of characters added or removed. + + llassert(pos >= 0); + llassert(pos <= getLength() ); + + S32 delta_spaces = 0; + + if (spaces >= 0) + { + // Indent + for(S32 i=0; i < spaces; i++) + { + delta_spaces += addChar(pos, ' '); + } + } + else + { + // Unindent + for(S32 i=0; i < -spaces; i++) + { + LLWString wtext = getWText(); + if (wtext[pos] == ' ') + { + delta_spaces += remove( pos, 1, FALSE ); + } + } + } + + return delta_spaces; } void LLTextEditor::indentSelectedLines( S32 spaces ) { - if( hasSelection() ) - { - LLWString text = getWText(); - S32 left = llmin( mSelectionStart, mSelectionEnd ); - S32 right = left + llabs( mSelectionStart - mSelectionEnd ); - BOOL cursor_on_right = (mSelectionEnd > mSelectionStart); - S32 cur = left; - - // Expand left to start of line - while( (cur > 0) && (text[cur] != '\n') ) - { - cur--; - } - left = cur; - if( cur > 0 ) - { - left++; - } - - // Expand right to end of line - if( text[right - 1] == '\n' ) - { - right--; - } - else - { - while( (text[right] != '\n') && (right <= getLength() ) ) - { - right++; - } - } - - // Disabling parsing on the fly to avoid updating text segments - // until all indentation commands are executed. - mParseOnTheFly = FALSE; - - // Find each start-of-line and indent it - do - { - if( text[cur] == '\n' ) - { - cur++; - } - - S32 delta_spaces = indentLine( cur, spaces ); - if( delta_spaces > 0 ) - { - cur += delta_spaces; - } - right += delta_spaces; - - text = getWText(); - - // Find the next new line - while( (cur < right) && (text[cur] != '\n') ) - { - cur++; - } - } - while( cur < right ); - - mParseOnTheFly = TRUE; - - if( (right < getLength()) && (text[right] == '\n') ) - { - right++; - } - - // Set the selection and cursor - if( cursor_on_right ) - { - mSelectionStart = left; - mSelectionEnd = right; - } - else - { - mSelectionStart = right; - mSelectionEnd = left; - } - setCursorPos(mSelectionEnd); - } + if( hasSelection() ) + { + LLWString text = getWText(); + S32 left = llmin( mSelectionStart, mSelectionEnd ); + S32 right = left + llabs( mSelectionStart - mSelectionEnd ); + BOOL cursor_on_right = (mSelectionEnd > mSelectionStart); + S32 cur = left; + + // Expand left to start of line + while( (cur > 0) && (text[cur] != '\n') ) + { + cur--; + } + left = cur; + if( cur > 0 ) + { + left++; + } + + // Expand right to end of line + if( text[right - 1] == '\n' ) + { + right--; + } + else + { + while( (text[right] != '\n') && (right <= getLength() ) ) + { + right++; + } + } + + // Disabling parsing on the fly to avoid updating text segments + // until all indentation commands are executed. + mParseOnTheFly = FALSE; + + // Find each start-of-line and indent it + do + { + if( text[cur] == '\n' ) + { + cur++; + } + + S32 delta_spaces = indentLine( cur, spaces ); + if( delta_spaces > 0 ) + { + cur += delta_spaces; + } + right += delta_spaces; + + text = getWText(); + + // Find the next new line + while( (cur < right) && (text[cur] != '\n') ) + { + cur++; + } + } + while( cur < right ); + + mParseOnTheFly = TRUE; + + if( (right < getLength()) && (text[right] == '\n') ) + { + right++; + } + + // Set the selection and cursor + if( cursor_on_right ) + { + mSelectionStart = left; + mSelectionEnd = right; + } + else + { + mSelectionStart = right; + mSelectionEnd = left; + } + setCursorPos(mSelectionEnd); + } } //virtual BOOL LLTextEditor::canSelectAll() const { - return TRUE; + return TRUE; } // virtual void LLTextEditor::selectAll() { - mSelectionStart = getLength(); - mSelectionEnd = 0; - setCursorPos(mSelectionEnd); - updatePrimary(); + mSelectionStart = getLength(); + mSelectionEnd = 0; + setCursorPos(mSelectionEnd); + updatePrimary(); } void LLTextEditor::selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos) { - setCursorPos(prev_cursor_pos); - startSelection(); - setCursorPos(next_cursor_pos); - endSelection(); + setCursorPos(prev_cursor_pos); + startSelection(); + setCursorPos(next_cursor_pos); + endSelection(); } void LLTextEditor::insertEmoji(llwchar emoji) { - LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL; - auto styleParams = LLStyle::Params(); - styleParams.font = LLFontGL::getFontEmoji(); - auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this); - insert(mCursorPos, LLWString(1, emoji), false, segment); - setCursorPos(mCursorPos + 1); + LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL; + auto styleParams = LLStyle::Params(); + styleParams.font = LLFontGL::getFontEmoji(); + auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this); + insert(mCursorPos, LLWString(1, emoji), false, segment); + setCursorPos(mCursorPos + 1); } void LLTextEditor::handleEmojiCommit(llwchar emoji) { - S32 shortCodePos; - if (LLEmojiHelper::isCursorInEmojiCode(getWText(), mCursorPos, &shortCodePos)) - { - remove(shortCodePos, mCursorPos - shortCodePos, true); - setCursorPos(shortCodePos); + S32 shortCodePos; + if (LLEmojiHelper::isCursorInEmojiCode(getWText(), mCursorPos, &shortCodePos)) + { + remove(shortCodePos, mCursorPos - shortCodePos, true); + setCursorPos(shortCodePos); - insertEmoji(emoji); - } + insertEmoji(emoji); + } } BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - // set focus first, in case click callbacks want to change it - // RN: do we really need to have a tab stop? - if (hasTabStop()) - { - setFocus( TRUE ); - } - - // Let scrollbar have first dibs - handled = LLTextBase::handleMouseDown(x, y, mask); - - if( !handled ) - { - if (!(mask & MASK_SHIFT)) - { - deselect(); - } - - BOOL start_select = TRUE; - if( start_select ) - { - // If we're not scrolling (handled by child), then we're selecting - if (mask & MASK_SHIFT) - { - S32 old_cursor_pos = mCursorPos; - setCursorAtLocalPos( x, y, true ); - - if (hasSelection()) - { - mSelectionEnd = mCursorPos; - } - else - { - mSelectionStart = old_cursor_pos; - mSelectionEnd = mCursorPos; - } - // assume we're starting a drag select - mIsSelecting = TRUE; - } - else - { - setCursorAtLocalPos( x, y, true ); - startSelection(); - } - } - - handled = TRUE; - } - - // Delay cursor flashing - resetCursorBlink(); - - if (handled && !gFocusMgr.getMouseCapture()) - { - gFocusMgr.setMouseCapture( this ); - } - return handled; + BOOL handled = FALSE; + + // set focus first, in case click callbacks want to change it + // RN: do we really need to have a tab stop? + if (hasTabStop()) + { + setFocus( TRUE ); + } + + // Let scrollbar have first dibs + handled = LLTextBase::handleMouseDown(x, y, mask); + + if( !handled ) + { + if (!(mask & MASK_SHIFT)) + { + deselect(); + } + + BOOL start_select = TRUE; + if( start_select ) + { + // If we're not scrolling (handled by child), then we're selecting + if (mask & MASK_SHIFT) + { + S32 old_cursor_pos = mCursorPos; + setCursorAtLocalPos( x, y, true ); + + if (hasSelection()) + { + mSelectionEnd = mCursorPos; + } + else + { + mSelectionStart = old_cursor_pos; + mSelectionEnd = mCursorPos; + } + // assume we're starting a drag select + mIsSelecting = TRUE; + } + else + { + setCursorAtLocalPos( x, y, true ); + startSelection(); + } + } + + handled = TRUE; + } + + // Delay cursor flashing + resetCursorBlink(); + + if (handled && !gFocusMgr.getMouseCapture()) + { + gFocusMgr.setMouseCapture( this ); + } + return handled; } BOOL LLTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) { - if (hasTabStop()) - { - setFocus(TRUE); - } + if (hasTabStop()) + { + setFocus(TRUE); + } - bool show_menu = false; + bool show_menu = false; - // Prefer editor menu if it has selection. See EXT-6806. - if (hasSelection()) - { - S32 click_pos = getDocIndexFromLocalCoord(x, y, FALSE); - if (click_pos > mSelectionStart && click_pos < mSelectionEnd) - { - show_menu = true; - } - } + // Prefer editor menu if it has selection. See EXT-6806. + if (hasSelection()) + { + S32 click_pos = getDocIndexFromLocalCoord(x, y, FALSE); + if (click_pos > mSelectionStart && click_pos < mSelectionEnd) + { + show_menu = true; + } + } - // Let segments handle the click, if nothing does, show editor menu - if (!show_menu && !LLTextBase::handleRightMouseDown(x, y, mask)) - { - show_menu = true; - } + // Let segments handle the click, if nothing does, show editor menu + if (!show_menu && !LLTextBase::handleRightMouseDown(x, y, mask)) + { + show_menu = true; + } - if (show_menu && getShowContextMenu()) - { - showContextMenu(x, y); - } + if (show_menu && getShowContextMenu()) + { + showContextMenu(x, y); + } - return TRUE; + return TRUE; } BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) { - if (hasTabStop()) - { - setFocus(TRUE); - } + if (hasTabStop()) + { + setFocus(TRUE); + } - if (!LLTextBase::handleMouseDown(x, y, mask)) - { - if( canPastePrimary() ) - { - setCursorAtLocalPos( x, y, true ); - // does not rely on focus being set - pastePrimary(); - } - } - return TRUE; + if (!LLTextBase::handleMouseDown(x, y, mask)) + { + if( canPastePrimary() ) + { + setCursorAtLocalPos( x, y, true ); + // does not rely on focus being set + pastePrimary(); + } + } + return TRUE; } BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - if(hasMouseCapture() ) - { - if( mIsSelecting ) - { - if(mScroller) - { - mScroller->autoScroll(x, y); - } - S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); - S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); - setCursorAtLocalPos( clamped_x, clamped_y, true ); - mSelectionEnd = mCursorPos; - } - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; - getWindow()->setCursor(UI_CURSOR_IBEAM); - handled = TRUE; - } - - if( !handled ) - { - // Pass to children - handled = LLTextBase::handleHover(x, y, mask); - } - - if( handled ) - { - // Delay cursor flashing - resetCursorBlink(); - } - - if( !handled ) - { - getWindow()->setCursor(UI_CURSOR_IBEAM); - handled = TRUE; - } - - return handled; + BOOL handled = FALSE; + + if(hasMouseCapture() ) + { + if( mIsSelecting ) + { + if(mScroller) + { + mScroller->autoScroll(x, y); + } + S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); + S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); + setCursorAtLocalPos( clamped_x, clamped_y, true ); + mSelectionEnd = mCursorPos; + } + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; + getWindow()->setCursor(UI_CURSOR_IBEAM); + handled = TRUE; + } + + if( !handled ) + { + // Pass to children + handled = LLTextBase::handleHover(x, y, mask); + } + + if( handled ) + { + // Delay cursor flashing + resetCursorBlink(); + } + + if( !handled ) + { + getWindow()->setCursor(UI_CURSOR_IBEAM); + handled = TRUE; + } + + return handled; } BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - // if I'm not currently selecting text - if (!(mIsSelecting && hasMouseCapture())) - { - // let text segments handle mouse event - handled = LLTextBase::handleMouseUp(x, y, mask); - } - - if( !handled ) - { - if( mIsSelecting ) - { - if(mScroller) - { - mScroller->autoScroll(x, y); - } - S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); - S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); - setCursorAtLocalPos( clamped_x, clamped_y, true ); - endSelection(); - } - - // take selection to 'primary' clipboard - updatePrimary(); - - handled = TRUE; - } - - // Delay cursor flashing - resetCursorBlink(); - - if( hasMouseCapture() ) - { - gFocusMgr.setMouseCapture( NULL ); - - handled = TRUE; - } - - return handled; + BOOL handled = FALSE; + + // if I'm not currently selecting text + if (!(mIsSelecting && hasMouseCapture())) + { + // let text segments handle mouse event + handled = LLTextBase::handleMouseUp(x, y, mask); + } + + if( !handled ) + { + if( mIsSelecting ) + { + if(mScroller) + { + mScroller->autoScroll(x, y); + } + S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); + S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); + setCursorAtLocalPos( clamped_x, clamped_y, true ); + endSelection(); + } + + // take selection to 'primary' clipboard + updatePrimary(); + + handled = TRUE; + } + + // Delay cursor flashing + resetCursorBlink(); + + if( hasMouseCapture() ) + { + gFocusMgr.setMouseCapture( NULL ); + + handled = TRUE; + } + + return handled; } BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; + BOOL handled = FALSE; - // let scrollbar and text segments have first dibs - handled = LLTextBase::handleDoubleClick(x, y, mask); + // let scrollbar and text segments have first dibs + handled = LLTextBase::handleDoubleClick(x, y, mask); - if( !handled ) - { - setCursorAtLocalPos( x, y, false ); - deselect(); + if( !handled ) + { + setCursorAtLocalPos( x, y, false ); + deselect(); - LLWString text = getWText(); - - if( LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) - { - // Select word the cursor is over - while ((mCursorPos > 0) && LLWStringUtil::isPartOfWord(text[mCursorPos-1])) - { - if (!setCursorPos(mCursorPos - 1)) break; - } - startSelection(); + LLWString text = getWText(); - while ((mCursorPos < (S32)text.length()) && LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) - { - if (!setCursorPos(mCursorPos + 1)) break; - } - - mSelectionEnd = mCursorPos; - } - else if ((mCursorPos < (S32)text.length()) && !iswspace( text[mCursorPos]) ) - { - // Select the character the cursor is over - startSelection(); - setCursorPos(mCursorPos + 1); - mSelectionEnd = mCursorPos; - } + if( LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) + { + // Select word the cursor is over + while ((mCursorPos > 0) && LLWStringUtil::isPartOfWord(text[mCursorPos-1])) + { + if (!setCursorPos(mCursorPos - 1)) break; + } + startSelection(); + + while ((mCursorPos < (S32)text.length()) && LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) + { + if (!setCursorPos(mCursorPos + 1)) break; + } + + mSelectionEnd = mCursorPos; + } + else if ((mCursorPos < (S32)text.length()) && !iswspace( text[mCursorPos]) ) + { + // Select the character the cursor is over + startSelection(); + setCursorPos(mCursorPos + 1); + mSelectionEnd = mCursorPos; + } - // We don't want handleMouseUp() to "finish" the selection (and thereby - // set mSelectionEnd to where the mouse is), so we finish the selection here. - mIsSelecting = FALSE; + // We don't want handleMouseUp() to "finish" the selection (and thereby + // set mSelectionEnd to where the mouse is), so we finish the selection here. + mIsSelecting = FALSE; - // delay cursor flashing - resetCursorBlink(); + // delay cursor flashing + resetCursorBlink(); - // take selection to 'primary' clipboard - updatePrimary(); + // take selection to 'primary' clipboard + updatePrimary(); - handled = TRUE; - } + handled = TRUE; + } - return handled; + return handled; } @@ -969,228 +969,228 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) S32 LLTextEditor::execute( TextCmd* cmd ) { - if (!mReadOnly && mShowEmojiHelper) - { - // Any change to our contents should always hide the helper - LLEmojiHelper::instance().hideHelper(this); - } - - S32 delta = 0; - if( cmd->execute(this, &delta) ) - { - // Delete top of undo stack - undo_stack_t::iterator enditer = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); - std::for_each(mUndoStack.begin(), enditer, DeletePointer()); - mUndoStack.erase(mUndoStack.begin(), enditer); - // Push the new command is now on the top (front) of the undo stack. - mUndoStack.push_front(cmd); - mLastCmd = cmd; - - bool need_to_rollback = mPrevalidateFunc - && !mPrevalidateFunc(getViewModel()->getDisplay()); - if (need_to_rollback) - { - // get rid of this last command and clean up undo stack - undo(); - - // remove any evidence of this command from redo history - mUndoStack.pop_front(); - delete cmd; - - // failure, nothing changed - delta = 0; - } - } - else - { - // Operation failed, so don't put it on the undo stack. - delete cmd; - } - - return delta; + if (!mReadOnly && mShowEmojiHelper) + { + // Any change to our contents should always hide the helper + LLEmojiHelper::instance().hideHelper(this); + } + + S32 delta = 0; + if( cmd->execute(this, &delta) ) + { + // Delete top of undo stack + undo_stack_t::iterator enditer = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); + std::for_each(mUndoStack.begin(), enditer, DeletePointer()); + mUndoStack.erase(mUndoStack.begin(), enditer); + // Push the new command is now on the top (front) of the undo stack. + mUndoStack.push_front(cmd); + mLastCmd = cmd; + + bool need_to_rollback = mPrevalidateFunc + && !mPrevalidateFunc(getViewModel()->getDisplay()); + if (need_to_rollback) + { + // get rid of this last command and clean up undo stack + undo(); + + // remove any evidence of this command from redo history + mUndoStack.pop_front(); + delete cmd; + + // failure, nothing changed + delta = 0; + } + } + else + { + // Operation failed, so don't put it on the undo stack. + delete cmd; + } + + return delta; } S32 LLTextEditor::insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment) { - return execute( new TextCmdInsert( pos, group_with_next_op, wstr, segment ) ); + return execute( new TextCmdInsert( pos, group_with_next_op, wstr, segment ) ); } S32 LLTextEditor::remove(S32 pos, S32 length, bool group_with_next_op) { - S32 end_pos = getEditableIndex(pos + length, true); - BOOL removedChar = FALSE; + S32 end_pos = getEditableIndex(pos + length, true); + BOOL removedChar = FALSE; + + segment_vec_t segments_to_remove; + // store text segments + getSegmentsInRange(segments_to_remove, pos, pos + length, false); - segment_vec_t segments_to_remove; - // store text segments - getSegmentsInRange(segments_to_remove, pos, pos + length, false); - - if (pos <= end_pos) - { - removedChar = execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) ); - } + if (pos <= end_pos) + { + removedChar = execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) ); + } - return removedChar; + return removedChar; } S32 LLTextEditor::overwriteChar(S32 pos, llwchar wc) { - if ((S32)getLength() == pos) - { - return addChar(pos, wc); - } - else - { - return execute(new TextCmdOverwriteChar(pos, FALSE, wc)); - } + if ((S32)getLength() == pos) + { + return addChar(pos, wc); + } + else + { + return execute(new TextCmdOverwriteChar(pos, FALSE, wc)); + } } // Remove a single character from the text. Tries to remove // a pseudo-tab (up to for spaces in a row) void LLTextEditor::removeCharOrTab() { - if (!getEnabled()) - { - return; - } - - if (mCursorPos > 0) - { - S32 chars_to_remove = 1; - - LLWString text = getWText(); - if (text[mCursorPos - 1] == ' ') - { - // Try to remove a "tab" - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - if (offset > 0) - { - chars_to_remove = offset % SPACES_PER_TAB; - if (chars_to_remove == 0) - { - chars_to_remove = SPACES_PER_TAB; - } - - for (S32 i = 0; i < chars_to_remove; i++) - { - if (text[mCursorPos - i - 1] != ' ') - { - // Fewer than a full tab's worth of spaces, so - // just delete a single character. - chars_to_remove = 1; - break; - } - } - } - } - - for (S32 i = 0; i < chars_to_remove; i++) - { - setCursorPos(mCursorPos - 1); - remove(mCursorPos, 1, false); - } - - tryToShowEmojiHelper(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } -} + if (!getEnabled()) + { + return; + } -// Remove a single character from the text -S32 LLTextEditor::removeChar(S32 pos) -{ - return remove(pos, 1, false); + if (mCursorPos > 0) + { + S32 chars_to_remove = 1; + + LLWString text = getWText(); + if (text[mCursorPos - 1] == ' ') + { + // Try to remove a "tab" + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + if (offset > 0) + { + chars_to_remove = offset % SPACES_PER_TAB; + if (chars_to_remove == 0) + { + chars_to_remove = SPACES_PER_TAB; + } + + for (S32 i = 0; i < chars_to_remove; i++) + { + if (text[mCursorPos - i - 1] != ' ') + { + // Fewer than a full tab's worth of spaces, so + // just delete a single character. + chars_to_remove = 1; + break; + } + } + } + } + + for (S32 i = 0; i < chars_to_remove; i++) + { + setCursorPos(mCursorPos - 1); + remove(mCursorPos, 1, false); + } + + tryToShowEmojiHelper(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } +} + +// Remove a single character from the text +S32 LLTextEditor::removeChar(S32 pos) +{ + return remove(pos, 1, false); } void LLTextEditor::removeChar() { - if (!getEnabled()) - { - return; - } + if (!getEnabled()) + { + return; + } - if (mCursorPos > 0) - { - setCursorPos(mCursorPos - 1); - removeChar(mCursorPos); - tryToShowEmojiHelper(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } + if (mCursorPos > 0) + { + setCursorPos(mCursorPos - 1); + removeChar(mCursorPos); + tryToShowEmojiHelper(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } } // Add a single character to the text S32 LLTextEditor::addChar(S32 pos, llwchar wc) { - if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) > mMaxTextByteLength) - { - make_ui_sound("UISndBadKeystroke"); - return 0; - } - - if (mLastCmd && mLastCmd->canExtend(pos)) - { - S32 delta = 0; - if (mPrevalidateFunc) - { - // get a copy of current text contents - LLWString test_string(getViewModel()->getDisplay()); - - // modify text contents as if this addChar succeeded - llassert(pos <= (S32)test_string.size()); - test_string.insert(pos, 1, wc); - if (!mPrevalidateFunc( test_string)) - { - return 0; - } - } - mLastCmd->extendAndExecute(this, pos, wc, &delta); - - return delta; - } - else - { - return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr())); - } + if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) > mMaxTextByteLength) + { + make_ui_sound("UISndBadKeystroke"); + return 0; + } + + if (mLastCmd && mLastCmd->canExtend(pos)) + { + S32 delta = 0; + if (mPrevalidateFunc) + { + // get a copy of current text contents + LLWString test_string(getViewModel()->getDisplay()); + + // modify text contents as if this addChar succeeded + llassert(pos <= (S32)test_string.size()); + test_string.insert(pos, 1, wc); + if (!mPrevalidateFunc( test_string)) + { + return 0; + } + } + mLastCmd->extendAndExecute(this, pos, wc, &delta); + + return delta; + } + else + { + return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr())); + } } void LLTextEditor::addChar(llwchar wc) { - if( !getEnabled() ) - { - return; - } - if( hasSelection() ) - { - deleteSelection(TRUE); - } - else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - removeChar(mCursorPos); - } - - setCursorPos(mCursorPos + addChar( mCursorPos, wc )); - tryToShowEmojiHelper(); - - if (!mReadOnly && mAutoreplaceCallback != NULL) - { - // autoreplace the text, if necessary - S32 replacement_start; - S32 replacement_length; - LLWString replacement_string; - S32 new_cursor_pos = mCursorPos; - mAutoreplaceCallback(replacement_start, replacement_length, replacement_string, new_cursor_pos, getWText()); - - if (replacement_length > 0 || !replacement_string.empty()) - { - remove(replacement_start, replacement_length, true); - insert(replacement_start, replacement_string, false, LLTextSegmentPtr()); - setCursorPos(new_cursor_pos); - } - } + if( !getEnabled() ) + { + return; + } + if( hasSelection() ) + { + deleteSelection(TRUE); + } + else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + removeChar(mCursorPos); + } + + setCursorPos(mCursorPos + addChar( mCursorPos, wc )); + tryToShowEmojiHelper(); + + if (!mReadOnly && mAutoreplaceCallback != NULL) + { + // autoreplace the text, if necessary + S32 replacement_start; + S32 replacement_length; + LLWString replacement_string; + S32 new_cursor_pos = mCursorPos; + mAutoreplaceCallback(replacement_start, replacement_length, replacement_string, new_cursor_pos, getWText()); + + if (replacement_length > 0 || !replacement_string.empty()) + { + remove(replacement_start, replacement_length, true); + insert(replacement_start, replacement_string, false, LLTextSegmentPtr()); + setCursorPos(new_cursor_pos); + } + } } void LLTextEditor::showEmojiHelper() @@ -1226,792 +1226,792 @@ void LLTextEditor::tryToShowEmojiHelper() void LLTextEditor::addLineBreakChar(BOOL group_together) { - if( !getEnabled() ) - { - return; - } - if( hasSelection() ) - { - deleteSelection(TRUE); - } - else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - removeChar(mCursorPos); - } + if( !getEnabled() ) + { + return; + } + if( hasSelection() ) + { + deleteSelection(TRUE); + } + else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + removeChar(mCursorPos); + } + + LLStyleConstSP sp(new LLStyle(LLStyle::Params())); + LLTextSegmentPtr segment = new LLLineBreakTextSegment(sp, mCursorPos); - LLStyleConstSP sp(new LLStyle(LLStyle::Params())); - LLTextSegmentPtr segment = new LLLineBreakTextSegment(sp, mCursorPos); + S32 pos = execute(new TextCmdAddChar(mCursorPos, group_together, '\n', segment)); - S32 pos = execute(new TextCmdAddChar(mCursorPos, group_together, '\n', segment)); - - setCursorPos(mCursorPos + pos); + setCursorPos(mCursorPos + pos); } BOOL LLTextEditor::handleSelectionKey(const KEY key, const MASK mask) { - BOOL handled = FALSE; - - if( mask & MASK_SHIFT ) - { - handled = TRUE; - - switch( key ) - { - case KEY_LEFT: - if( 0 < mCursorPos ) - { - startSelection(); - setCursorPos(mCursorPos - 1); - if( mask & MASK_CONTROL ) - { - setCursorPos(prevWordPos(mCursorPos)); - } - mSelectionEnd = mCursorPos; - } - break; - - case KEY_RIGHT: - if( mCursorPos < getLength() ) - { - startSelection(); - setCursorPos(mCursorPos + 1); - if( mask & MASK_CONTROL ) - { - setCursorPos(nextWordPos(mCursorPos)); - } - mSelectionEnd = mCursorPos; - } - break; - - case KEY_UP: - startSelection(); - changeLine( -1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_PAGE_UP: - startSelection(); - changePage( -1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_HOME: - startSelection(); - if( mask & MASK_CONTROL ) - { - setCursorPos(0); - } - else - { - startOfLine(); - } - mSelectionEnd = mCursorPos; - break; - - case KEY_DOWN: - startSelection(); - changeLine( 1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_PAGE_DOWN: - startSelection(); - changePage( 1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_END: - startSelection(); - if( mask & MASK_CONTROL ) - { - setCursorPos(getLength()); - } - else - { - endOfLine(); - } - mSelectionEnd = mCursorPos; - break; - - default: - handled = FALSE; - break; - } - } - - if( handled ) - { - // take selection to 'primary' clipboard - updatePrimary(); - } - - return handled; + BOOL handled = FALSE; + + if( mask & MASK_SHIFT ) + { + handled = TRUE; + + switch( key ) + { + case KEY_LEFT: + if( 0 < mCursorPos ) + { + startSelection(); + setCursorPos(mCursorPos - 1); + if( mask & MASK_CONTROL ) + { + setCursorPos(prevWordPos(mCursorPos)); + } + mSelectionEnd = mCursorPos; + } + break; + + case KEY_RIGHT: + if( mCursorPos < getLength() ) + { + startSelection(); + setCursorPos(mCursorPos + 1); + if( mask & MASK_CONTROL ) + { + setCursorPos(nextWordPos(mCursorPos)); + } + mSelectionEnd = mCursorPos; + } + break; + + case KEY_UP: + startSelection(); + changeLine( -1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_PAGE_UP: + startSelection(); + changePage( -1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_HOME: + startSelection(); + if( mask & MASK_CONTROL ) + { + setCursorPos(0); + } + else + { + startOfLine(); + } + mSelectionEnd = mCursorPos; + break; + + case KEY_DOWN: + startSelection(); + changeLine( 1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_PAGE_DOWN: + startSelection(); + changePage( 1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_END: + startSelection(); + if( mask & MASK_CONTROL ) + { + setCursorPos(getLength()); + } + else + { + endOfLine(); + } + mSelectionEnd = mCursorPos; + break; + + default: + handled = FALSE; + break; + } + } + + if( handled ) + { + // take selection to 'primary' clipboard + updatePrimary(); + } + + return handled; } BOOL LLTextEditor::handleNavigationKey(const KEY key, const MASK mask) { - BOOL handled = FALSE; - - // Ignore capslock key - if( MASK_NONE == mask ) - { - handled = TRUE; - switch( key ) - { - case KEY_UP: - changeLine( -1 ); - break; - - case KEY_PAGE_UP: - changePage( -1 ); - break; - - case KEY_HOME: - startOfLine(); - break; - - case KEY_DOWN: - changeLine( 1 ); - deselect(); - break; - - case KEY_PAGE_DOWN: - changePage( 1 ); - break; - - case KEY_END: - endOfLine(); - break; - - case KEY_LEFT: - if( hasSelection() ) - { - setCursorPos(llmin( mSelectionStart, mSelectionEnd )); - } - else - { - if( 0 < mCursorPos ) - { - setCursorPos(mCursorPos - 1); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - } - break; - - case KEY_RIGHT: - if( hasSelection() ) - { - setCursorPos(llmax( mSelectionStart, mSelectionEnd )); - } - else - { - if( mCursorPos < getLength() ) - { - setCursorPos(mCursorPos + 1); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - } - break; - - default: - handled = FALSE; - break; - } - } - - if (handled) - { - deselect(); - } - - return handled; + BOOL handled = FALSE; + + // Ignore capslock key + if( MASK_NONE == mask ) + { + handled = TRUE; + switch( key ) + { + case KEY_UP: + changeLine( -1 ); + break; + + case KEY_PAGE_UP: + changePage( -1 ); + break; + + case KEY_HOME: + startOfLine(); + break; + + case KEY_DOWN: + changeLine( 1 ); + deselect(); + break; + + case KEY_PAGE_DOWN: + changePage( 1 ); + break; + + case KEY_END: + endOfLine(); + break; + + case KEY_LEFT: + if( hasSelection() ) + { + setCursorPos(llmin( mSelectionStart, mSelectionEnd )); + } + else + { + if( 0 < mCursorPos ) + { + setCursorPos(mCursorPos - 1); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + } + break; + + case KEY_RIGHT: + if( hasSelection() ) + { + setCursorPos(llmax( mSelectionStart, mSelectionEnd )); + } + else + { + if( mCursorPos < getLength() ) + { + setCursorPos(mCursorPos + 1); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + } + break; + + default: + handled = FALSE; + break; + } + } + + if (handled) + { + deselect(); + } + + return handled; } void LLTextEditor::deleteSelection(BOOL group_with_next_op ) { - if( getEnabled() && hasSelection() ) - { - S32 pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - - remove( pos, length, group_with_next_op ); + if( getEnabled() && hasSelection() ) + { + S32 pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); - deselect(); - setCursorPos(pos); - } + remove( pos, length, group_with_next_op ); + + deselect(); + setCursorPos(pos); + } } // virtual BOOL LLTextEditor::canCut() const { - return !mReadOnly && hasSelection(); + return !mReadOnly && hasSelection(); } // cut selection to clipboard void LLTextEditor::cut() { - if( !canCut() ) - { - return; - } - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard( getWText(), left_pos, length); - deleteSelection( FALSE ); + if( !canCut() ) + { + return; + } + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard( getWText(), left_pos, length); + deleteSelection( FALSE ); - onKeyStroke(); + onKeyStroke(); } BOOL LLTextEditor::canCopy() const { - return hasSelection(); + return hasSelection(); } // copy selection to clipboard void LLTextEditor::copy() { - if( !canCopy() ) - { - return; - } - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard(getWText(), left_pos, length); + if( !canCopy() ) + { + return; + } + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard(getWText(), left_pos, length); } BOOL LLTextEditor::canPaste() const { - return !mReadOnly && LLClipboard::instance().isTextAvailable(); + return !mReadOnly && LLClipboard::instance().isTextAvailable(); } // paste from clipboard void LLTextEditor::paste() { - bool is_primary = false; - pasteHelper(is_primary); + bool is_primary = false; + pasteHelper(is_primary); } // paste from primary void LLTextEditor::pastePrimary() { - bool is_primary = true; - pasteHelper(is_primary); + bool is_primary = true; + pasteHelper(is_primary); } // paste from primary (itsprimary==true) or clipboard (itsprimary==false) void LLTextEditor::pasteHelper(bool is_primary) { - mParseOnTheFly = FALSE; - bool can_paste_it; - if (is_primary) - { - can_paste_it = canPastePrimary(); - } - else - { - can_paste_it = canPaste(); - } + mParseOnTheFly = FALSE; + bool can_paste_it; + if (is_primary) + { + can_paste_it = canPastePrimary(); + } + else + { + can_paste_it = canPaste(); + } - if (!can_paste_it) - { - return; - } + if (!can_paste_it) + { + return; + } - LLWString paste; - LLClipboard::instance().pasteFromClipboard(paste, is_primary); + LLWString paste; + LLClipboard::instance().pasteFromClipboard(paste, is_primary); - if (paste.empty()) - { - return; - } + if (paste.empty()) + { + return; + } - // Delete any selected characters (the paste replaces them) - if( (!is_primary) && hasSelection() ) - { - deleteSelection(TRUE); - } + // Delete any selected characters (the paste replaces them) + if( (!is_primary) && hasSelection() ) + { + deleteSelection(TRUE); + } - // Clean up string (replace tabs and remove characters that our fonts don't support). - LLWString clean_string(paste); - cleanStringForPaste(clean_string); + // Clean up string (replace tabs and remove characters that our fonts don't support). + LLWString clean_string(paste); + cleanStringForPaste(clean_string); - // Insert the new text into the existing text. + // Insert the new text into the existing text. - //paste text with linebreaks. - pasteTextWithLinebreaks(clean_string); + //paste text with linebreaks. + pasteTextWithLinebreaks(clean_string); - deselect(); + deselect(); - onKeyStroke(); - mParseOnTheFly = TRUE; + onKeyStroke(); + mParseOnTheFly = TRUE; } // Clean up string (replace tabs and remove characters that our fonts don't support). void LLTextEditor::cleanStringForPaste(LLWString & clean_string) { - std::string clean_string_utf = wstring_to_utf8str(clean_string); - std::replace( clean_string_utf.begin(), clean_string_utf.end(), '\r', '\n'); - clean_string = utf8str_to_wstring(clean_string_utf); - - LLWStringUtil::replaceTabsWithSpaces(clean_string, SPACES_PER_TAB); - if( mAllowEmbeddedItems ) - { - const llwchar LF = 10; - S32 len = clean_string.length(); - for( S32 i = 0; i < len; i++ ) - { - llwchar wc = clean_string[i]; - if( (wc < LLFontFreetype::FIRST_CHAR) && (wc != LF) ) - { - clean_string[i] = LL_UNKNOWN_CHAR; - } - else if (wc >= FIRST_EMBEDDED_CHAR && wc <= LAST_EMBEDDED_CHAR) - { - clean_string[i] = pasteEmbeddedItem(wc); - } - } - } + std::string clean_string_utf = wstring_to_utf8str(clean_string); + std::replace( clean_string_utf.begin(), clean_string_utf.end(), '\r', '\n'); + clean_string = utf8str_to_wstring(clean_string_utf); + + LLWStringUtil::replaceTabsWithSpaces(clean_string, SPACES_PER_TAB); + if( mAllowEmbeddedItems ) + { + const llwchar LF = 10; + S32 len = clean_string.length(); + for( S32 i = 0; i < len; i++ ) + { + llwchar wc = clean_string[i]; + if( (wc < LLFontFreetype::FIRST_CHAR) && (wc != LF) ) + { + clean_string[i] = LL_UNKNOWN_CHAR; + } + else if (wc >= FIRST_EMBEDDED_CHAR && wc <= LAST_EMBEDDED_CHAR) + { + clean_string[i] = pasteEmbeddedItem(wc); + } + } + } } template <> void LLTextEditor::pasteTextWithLinebreaks(const LLWString & clean_string) { - std::basic_string::size_type start = 0; - std::basic_string::size_type pos = clean_string.find('\n',start); - - while((pos != -1) && (pos != clean_string.length() -1)) - { - if(pos!=start) - { - std::basic_string str = std::basic_string(clean_string,start,pos-start); - setCursorPos(mCursorPos + insert(mCursorPos, str, TRUE, LLTextSegmentPtr())); - } - addLineBreakChar(TRUE); // Add a line break and group with the next addition. - - start = pos+1; - pos = clean_string.find('\n',start); - } - - if (pos != start) - { - std::basic_string str = std::basic_string(clean_string,start,clean_string.length()-start); - setCursorPos(mCursorPos + insert(mCursorPos, str, FALSE, LLTextSegmentPtr())); - } - else - { - addLineBreakChar(FALSE); // Add a line break and end the grouping. - } + std::basic_string::size_type start = 0; + std::basic_string::size_type pos = clean_string.find('\n',start); + + while((pos != -1) && (pos != clean_string.length() -1)) + { + if(pos!=start) + { + std::basic_string str = std::basic_string(clean_string,start,pos-start); + setCursorPos(mCursorPos + insert(mCursorPos, str, TRUE, LLTextSegmentPtr())); + } + addLineBreakChar(TRUE); // Add a line break and group with the next addition. + + start = pos+1; + pos = clean_string.find('\n',start); + } + + if (pos != start) + { + std::basic_string str = std::basic_string(clean_string,start,clean_string.length()-start); + setCursorPos(mCursorPos + insert(mCursorPos, str, FALSE, LLTextSegmentPtr())); + } + else + { + addLineBreakChar(FALSE); // Add a line break and end the grouping. + } } // copy selection to primary void LLTextEditor::copyPrimary() { - if( !canCopy() ) - { - return; - } - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard(getWText(), left_pos, length, true); + if( !canCopy() ) + { + return; + } + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard(getWText(), left_pos, length, true); } BOOL LLTextEditor::canPastePrimary() const { - return !mReadOnly && LLClipboard::instance().isTextAvailable(true); + return !mReadOnly && LLClipboard::instance().isTextAvailable(true); } void LLTextEditor::updatePrimary() { - if (canCopy()) - { - copyPrimary(); - } -} - -BOOL LLTextEditor::handleControlKey(const KEY key, const MASK mask) -{ - BOOL handled = FALSE; - - if( mask & MASK_CONTROL ) - { - handled = TRUE; - - switch( key ) - { - case KEY_HOME: - if( mask & MASK_SHIFT ) - { - startSelection(); - setCursorPos(0); - mSelectionEnd = mCursorPos; - } - else - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - startOfDoc(); - } - break; - - case KEY_END: - { - if( mask & MASK_SHIFT ) - { - startSelection(); - } - else - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - } - endOfDoc(); - if( mask & MASK_SHIFT ) - { - mSelectionEnd = mCursorPos; - } - break; - } - - case KEY_RIGHT: - if( mCursorPos < getLength() ) - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - - setCursorPos(nextWordPos(mCursorPos + 1)); - } - break; - - - case KEY_LEFT: - if( mCursorPos > 0 ) - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - - setCursorPos(prevWordPos(mCursorPos - 1)); - } - break; - - default: - handled = FALSE; - break; - } - } - - if (handled && !gFocusMgr.getMouseCapture()) - { - updatePrimary(); - } - - return handled; -} - - -BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask) - { - BOOL handled = TRUE; - - if (mReadOnly) return FALSE; - - switch( key ) - { - case KEY_INSERT: - if (mask == MASK_NONE) - { - gKeyboard->toggleInsertMode(); - } - break; - - case KEY_BACKSPACE: - if( hasSelection() ) - { - deleteSelection(FALSE); - } - else - if( 0 < mCursorPos ) - { - removeCharOrTab(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - break; - - - case KEY_RETURN: - if (mask == MASK_NONE) - { - if( hasSelection() && !mKeepSelectionOnReturn ) - { - deleteSelection(FALSE); - } - if (mAutoIndent) - { - autoIndent(); - } - } - else - { - handled = FALSE; - break; - } - break; - - case KEY_TAB: - if (mask & MASK_CONTROL) - { - handled = FALSE; - break; - } - if( hasSelection() && selectionContainsLineBreaks() ) - { - indentSelectedLines( (mask & MASK_SHIFT) ? -SPACES_PER_TAB : SPACES_PER_TAB ); - } - else - { - if( hasSelection() ) - { - deleteSelection(FALSE); - } - - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - - S32 spaces_needed = SPACES_PER_TAB - (offset % SPACES_PER_TAB); - for( S32 i=0; i < spaces_needed; i++ ) - { - addChar( ' ' ); - } - } - break; - - default: - handled = FALSE; - break; - } - - if (handled) - { - onKeyStroke(); - } - return handled; + if (canCopy()) + { + copyPrimary(); + } } - -void LLTextEditor::unindentLineBeforeCloseBrace() +BOOL LLTextEditor::handleControlKey(const KEY key, const MASK mask) { - if( mCursorPos >= 1 ) - { - LLWString text = getWText(); - if( ' ' == text[ mCursorPos - 1 ] ) - { - S32 line = getLineNumFromDocIndex(mCursorPos, false); - S32 line_start = getLineStart(line); + BOOL handled = FALSE; + + if( mask & MASK_CONTROL ) + { + handled = TRUE; + + switch( key ) + { + case KEY_HOME: + if( mask & MASK_SHIFT ) + { + startSelection(); + setCursorPos(0); + mSelectionEnd = mCursorPos; + } + else + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + startOfDoc(); + } + break; + + case KEY_END: + { + if( mask & MASK_SHIFT ) + { + startSelection(); + } + else + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + } + endOfDoc(); + if( mask & MASK_SHIFT ) + { + mSelectionEnd = mCursorPos; + } + break; + } + + case KEY_RIGHT: + if( mCursorPos < getLength() ) + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + + setCursorPos(nextWordPos(mCursorPos + 1)); + } + break; + + + case KEY_LEFT: + if( mCursorPos > 0 ) + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + + setCursorPos(prevWordPos(mCursorPos - 1)); + } + break; + + default: + handled = FALSE; + break; + } + } + + if (handled && !gFocusMgr.getMouseCapture()) + { + updatePrimary(); + } + + return handled; +} + + +BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask) + { + BOOL handled = TRUE; + + if (mReadOnly) return FALSE; + + switch( key ) + { + case KEY_INSERT: + if (mask == MASK_NONE) + { + gKeyboard->toggleInsertMode(); + } + break; + + case KEY_BACKSPACE: + if( hasSelection() ) + { + deleteSelection(FALSE); + } + else + if( 0 < mCursorPos ) + { + removeCharOrTab(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + break; + + + case KEY_RETURN: + if (mask == MASK_NONE) + { + if( hasSelection() && !mKeepSelectionOnReturn ) + { + deleteSelection(FALSE); + } + if (mAutoIndent) + { + autoIndent(); + } + } + else + { + handled = FALSE; + break; + } + break; + + case KEY_TAB: + if (mask & MASK_CONTROL) + { + handled = FALSE; + break; + } + if( hasSelection() && selectionContainsLineBreaks() ) + { + indentSelectedLines( (mask & MASK_SHIFT) ? -SPACES_PER_TAB : SPACES_PER_TAB ); + } + else + { + if( hasSelection() ) + { + deleteSelection(FALSE); + } + + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + + S32 spaces_needed = SPACES_PER_TAB - (offset % SPACES_PER_TAB); + for( S32 i=0; i < spaces_needed; i++ ) + { + addChar( ' ' ); + } + } + break; - // Jump over spaces in the current line - while ((' ' == text[line_start]) && (line_start < mCursorPos)) - { - line_start++; - } + default: + handled = FALSE; + break; + } - // Make sure there is nothing but ' ' before the Brace we are unindenting - if (line_start == mCursorPos) - { - removeCharOrTab(); - } - } - } + if (handled) + { + onKeyStroke(); + } + return handled; +} + + +void LLTextEditor::unindentLineBeforeCloseBrace() +{ + if( mCursorPos >= 1 ) + { + LLWString text = getWText(); + if( ' ' == text[ mCursorPos - 1 ] ) + { + S32 line = getLineNumFromDocIndex(mCursorPos, false); + S32 line_start = getLineStart(line); + + // Jump over spaces in the current line + while ((' ' == text[line_start]) && (line_start < mCursorPos)) + { + line_start++; + } + + // Make sure there is nothing but ' ' before the Brace we are unindenting + if (line_start == mCursorPos) + { + removeCharOrTab(); + } + } + } } BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask ) { - BOOL handled = FALSE; - - // Special case for TAB. If want to move to next field, report - // not handled and let the parent take care of field movement. - if (KEY_TAB == key && mTabsToNextField) - { - return FALSE; - } - - if (mReadOnly && mScroller) - { - handled = (mScroller && mScroller->handleKeyHere( key, mask )) - || handleSelectionKey(key, mask) - || handleControlKey(key, mask); - } - else - { - if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) - { - return TRUE; - } - - if (mEnableTooltipPaste && - LLToolTipMgr::instance().toolTipVisible() && + BOOL handled = FALSE; + + // Special case for TAB. If want to move to next field, report + // not handled and let the parent take care of field movement. + if (KEY_TAB == key && mTabsToNextField) + { + return FALSE; + } + + if (mReadOnly && mScroller) + { + handled = (mScroller && mScroller->handleKeyHere( key, mask )) + || handleSelectionKey(key, mask) + || handleControlKey(key, mask); + } + else + { + if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) + { + return TRUE; + } + + if (mEnableTooltipPaste && + LLToolTipMgr::instance().toolTipVisible() && LLToolTipMgr::instance().isTooltipPastable() && - KEY_TAB == key) - { // Paste the first line of a tooltip into the editor - std::string message; - LLToolTipMgr::instance().getToolTipMessage(message); - LLWString tool_tip_text(utf8str_to_wstring(message)); - - if (tool_tip_text.size() > 0) - { - // Delete any selected characters (the tooltip text replaces them) - if(hasSelection()) - { - deleteSelection(TRUE); - } - - std::basic_string::size_type pos = tool_tip_text.find('\n',0); - if (pos != -1) - { // Extract the first line of the tooltip - tool_tip_text = std::basic_string(tool_tip_text, 0, pos); - } - - // Add the text - cleanStringForPaste(tool_tip_text); - pasteTextWithLinebreaks(tool_tip_text); - handled = TRUE; - } - } - else - { // Normal key handling - handled = handleNavigationKey( key, mask ) - || handleSelectionKey(key, mask) - || handleControlKey(key, mask) - || handleSpecialKey(key, mask); - } - } - - if( handled ) - { - resetCursorBlink(); - needsScroll(); - - if (mShowEmojiHelper) - { - // Dismiss the helper whenever we handled a key that it didn't - LLEmojiHelper::instance().hideHelper(this); - } - } - - return handled; + KEY_TAB == key) + { // Paste the first line of a tooltip into the editor + std::string message; + LLToolTipMgr::instance().getToolTipMessage(message); + LLWString tool_tip_text(utf8str_to_wstring(message)); + + if (tool_tip_text.size() > 0) + { + // Delete any selected characters (the tooltip text replaces them) + if(hasSelection()) + { + deleteSelection(TRUE); + } + + std::basic_string::size_type pos = tool_tip_text.find('\n',0); + if (pos != -1) + { // Extract the first line of the tooltip + tool_tip_text = std::basic_string(tool_tip_text, 0, pos); + } + + // Add the text + cleanStringForPaste(tool_tip_text); + pasteTextWithLinebreaks(tool_tip_text); + handled = TRUE; + } + } + else + { // Normal key handling + handled = handleNavigationKey( key, mask ) + || handleSelectionKey(key, mask) + || handleControlKey(key, mask) + || handleSpecialKey(key, mask); + } + } + + if( handled ) + { + resetCursorBlink(); + needsScroll(); + + if (mShowEmojiHelper) + { + // Dismiss the helper whenever we handled a key that it didn't + LLEmojiHelper::instance().hideHelper(this); + } + } + + return handled; } BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char) { - if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL - { - return FALSE; - } + if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL + { + return FALSE; + } - BOOL handled = FALSE; + BOOL handled = FALSE; - // Handle most keys only if the text editor is writeable. - if( !mReadOnly ) - { + // Handle most keys only if the text editor is writeable. + if( !mReadOnly ) + { if (mShowEmojiHelper && uni_char < 0x80 && LLEmojiHelper::instance().handleKey(this, (KEY)uni_char, MASK_NONE)) { return TRUE; } if( mAutoIndent && '}' == uni_char ) - { - unindentLineBeforeCloseBrace(); - } + { + unindentLineBeforeCloseBrace(); + } - // TODO: KLW Add auto show of tool tip on ( - addChar( uni_char ); + // TODO: KLW Add auto show of tool tip on ( + addChar( uni_char ); - // Keys that add characters temporarily hide the cursor - getWindow()->hideCursorUntilMouseMove(); + // Keys that add characters temporarily hide the cursor + getWindow()->hideCursorUntilMouseMove(); - handled = TRUE; - } + handled = TRUE; + } - if( handled ) - { - resetCursorBlink(); + if( handled ) + { + resetCursorBlink(); - // Most keystrokes will make the selection box go away, but not all will. - deselect(); + // Most keystrokes will make the selection box go away, but not all will. + deselect(); - onKeyStroke(); - } + onKeyStroke(); + } - return handled; + return handled; } // virtual BOOL LLTextEditor::canDoDelete() const { - return !mReadOnly && ( !mPassDelete || ( hasSelection() || (mCursorPos < getLength())) ); + return !mReadOnly && ( !mPassDelete || ( hasSelection() || (mCursorPos < getLength())) ); } void LLTextEditor::doDelete() { - if( !canDoDelete() ) - { - return; - } - if( hasSelection() ) - { - deleteSelection(FALSE); - } - else - if( mCursorPos < getLength() ) - { - S32 i; - S32 chars_to_remove = 1; - LLWString text = getWText(); - if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) ) - { - // Try to remove a full tab's worth of spaces - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - chars_to_remove = SPACES_PER_TAB - (offset % SPACES_PER_TAB); - if( chars_to_remove == 0 ) - { - chars_to_remove = SPACES_PER_TAB; - } - - for( i = 0; i < chars_to_remove; i++ ) - { - if( text[mCursorPos + i] != ' ' ) - { - chars_to_remove = 1; - break; - } - } - } - - for( i = 0; i < chars_to_remove; i++ ) - { - setCursorPos(mCursorPos + 1); - removeChar(); - } - - } - - onKeyStroke(); + if( !canDoDelete() ) + { + return; + } + if( hasSelection() ) + { + deleteSelection(FALSE); + } + else + if( mCursorPos < getLength() ) + { + S32 i; + S32 chars_to_remove = 1; + LLWString text = getWText(); + if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) ) + { + // Try to remove a full tab's worth of spaces + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + chars_to_remove = SPACES_PER_TAB - (offset % SPACES_PER_TAB); + if( chars_to_remove == 0 ) + { + chars_to_remove = SPACES_PER_TAB; + } + + for( i = 0; i < chars_to_remove; i++ ) + { + if( text[mCursorPos + i] != ' ' ) + { + chars_to_remove = 1; + break; + } + } + } + + for( i = 0; i < chars_to_remove; i++ ) + { + setCursorPos(mCursorPos + 1); + removeChar(); + } + + } + + onKeyStroke(); } //---------------------------------------------------------------------------- @@ -2019,624 +2019,624 @@ void LLTextEditor::doDelete() void LLTextEditor::blockUndo() { - mBaseDocIsPristine = FALSE; - mLastCmd = NULL; - std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); - mUndoStack.clear(); + mBaseDocIsPristine = FALSE; + mLastCmd = NULL; + std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); + mUndoStack.clear(); } // virtual BOOL LLTextEditor::canUndo() const { - return !mReadOnly && mLastCmd != NULL; + return !mReadOnly && mLastCmd != NULL; } void LLTextEditor::undo() { - if( !canUndo() ) - { - return; - } - deselect(); - S32 pos = 0; - do - { - pos = mLastCmd->undo(this); - undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); - if (iter != mUndoStack.end()) - ++iter; - if (iter != mUndoStack.end()) - mLastCmd = *iter; - else - mLastCmd = NULL; + if( !canUndo() ) + { + return; + } + deselect(); + S32 pos = 0; + do + { + pos = mLastCmd->undo(this); + undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); + if (iter != mUndoStack.end()) + ++iter; + if (iter != mUndoStack.end()) + mLastCmd = *iter; + else + mLastCmd = NULL; - } while( mLastCmd && mLastCmd->groupWithNext() ); + } while( mLastCmd && mLastCmd->groupWithNext() ); - setCursorPos(pos); + setCursorPos(pos); - onKeyStroke(); + onKeyStroke(); } BOOL LLTextEditor::canRedo() const { - return !mReadOnly && (mUndoStack.size() > 0) && (mLastCmd != mUndoStack.front()); + return !mReadOnly && (mUndoStack.size() > 0) && (mLastCmd != mUndoStack.front()); } void LLTextEditor::redo() { - if( !canRedo() ) - { - return; - } - deselect(); - S32 pos = 0; - do - { - if( !mLastCmd ) - { - mLastCmd = mUndoStack.back(); - } - else - { - undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); - if (iter != mUndoStack.begin()) - mLastCmd = *(--iter); - else - mLastCmd = NULL; - } - - if( mLastCmd ) - { - pos = mLastCmd->redo(this); - } - } while( - mLastCmd && - mLastCmd->groupWithNext() && - (mLastCmd != mUndoStack.front()) ); - - setCursorPos(pos); - - onKeyStroke(); + if( !canRedo() ) + { + return; + } + deselect(); + S32 pos = 0; + do + { + if( !mLastCmd ) + { + mLastCmd = mUndoStack.back(); + } + else + { + undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); + if (iter != mUndoStack.begin()) + mLastCmd = *(--iter); + else + mLastCmd = NULL; + } + + if( mLastCmd ) + { + pos = mLastCmd->redo(this); + } + } while( + mLastCmd && + mLastCmd->groupWithNext() && + (mLastCmd != mUndoStack.front()) ); + + setCursorPos(pos); + + onKeyStroke(); } void LLTextEditor::onFocusReceived() { - LLTextBase::onFocusReceived(); - updateAllowingLanguageInput(); + LLTextBase::onFocusReceived(); + updateAllowingLanguageInput(); } void LLTextEditor::focusLostHelper() { - updateAllowingLanguageInput(); + updateAllowingLanguageInput(); - // Route menu back to the default - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } + // Route menu back to the default + if( gEditMenuHandler == this ) + { + gEditMenuHandler = NULL; + } - if (mCommitOnFocusLost) - { - onCommit(); - } + if (mCommitOnFocusLost) + { + onCommit(); + } - // Make sure cursor is shown again - getWindow()->showCursorFromMouseMove(); + // Make sure cursor is shown again + getWindow()->showCursorFromMouseMove(); } void LLTextEditor::onFocusLost() { - focusLostHelper(); - LLTextBase::onFocusLost(); + focusLostHelper(); + LLTextBase::onFocusLost(); } void LLTextEditor::onCommit() { - setControlValue(getValue()); - LLTextBase::onCommit(); + setControlValue(getValue()); + LLTextBase::onCommit(); } void LLTextEditor::setEnabled(BOOL enabled) { - // just treat enabled as read-only flag - bool read_only = !enabled; - if (read_only != mReadOnly) - { - //mReadOnly = read_only; - LLTextBase::setReadOnly(read_only); - updateSegments(); - updateAllowingLanguageInput(); - } + // just treat enabled as read-only flag + bool read_only = !enabled; + if (read_only != mReadOnly) + { + //mReadOnly = read_only; + LLTextBase::setReadOnly(read_only); + updateSegments(); + updateAllowingLanguageInput(); + } } void LLTextEditor::showContextMenu(S32 x, S32 y) { - LLContextMenu* menu = static_cast(mContextMenuHandle.get()); - if (!menu) - { - llassert(LLMenuGL::sMenuContainer != NULL); - menu = LLUICtrlFactory::createFromFile("menu_text_editor.xml", - LLMenuGL::sMenuContainer, - LLMenuHolderGL::child_registry_t::instance()); + LLContextMenu* menu = static_cast(mContextMenuHandle.get()); + if (!menu) + { + llassert(LLMenuGL::sMenuContainer != NULL); + menu = LLUICtrlFactory::createFromFile("menu_text_editor.xml", + LLMenuGL::sMenuContainer, + LLMenuHolderGL::child_registry_t::instance()); if(!menu) { LL_WARNS() << "Failed to create menu for LLTextEditor: " << getName() << LL_ENDL; return; } - mContextMenuHandle = menu->getHandle(); - } - - // Route menu to this class - // previously this was done in ::handleRightMoseDown: - //if(hasTabStop()) - // setFocus(TRUE) - why? weird... - // and then inside setFocus - // .... - // gEditMenuHandler = this; - // .... - // but this didn't work in all cases and just weird... - //why not here? - // (all this was done for EXT-4443) - - gEditMenuHandler = this; - - S32 screen_x, screen_y; - localPointToScreen(x, y, &screen_x, &screen_y); - - setCursorAtLocalPos(x, y, false); - if (hasSelection()) - { - if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) - { - deselect(); - } - else - { - setCursorPos(llmax(mSelectionStart, mSelectionEnd)); - } - } - - bool use_spellcheck = getSpellCheck(), is_misspelled = false; - if (use_spellcheck) - { - mSuggestionList.clear(); - - // If the cursor is on a misspelled word, retrieve suggestions for it - std::string misspelled_word = getMisspelledWord(mCursorPos); - if ((is_misspelled = !misspelled_word.empty()) == true) - { - LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); - } - } - - menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); - menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); - menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); - menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); - menu->show(screen_x, screen_y, this); + mContextMenuHandle = menu->getHandle(); + } + + // Route menu to this class + // previously this was done in ::handleRightMoseDown: + //if(hasTabStop()) + // setFocus(TRUE) - why? weird... + // and then inside setFocus + // .... + // gEditMenuHandler = this; + // .... + // but this didn't work in all cases and just weird... + //why not here? + // (all this was done for EXT-4443) + + gEditMenuHandler = this; + + S32 screen_x, screen_y; + localPointToScreen(x, y, &screen_x, &screen_y); + + setCursorAtLocalPos(x, y, false); + if (hasSelection()) + { + if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) + { + deselect(); + } + else + { + setCursorPos(llmax(mSelectionStart, mSelectionEnd)); + } + } + + bool use_spellcheck = getSpellCheck(), is_misspelled = false; + if (use_spellcheck) + { + mSuggestionList.clear(); + + // If the cursor is on a misspelled word, retrieve suggestions for it + std::string misspelled_word = getMisspelledWord(mCursorPos); + if ((is_misspelled = !misspelled_word.empty()) == true) + { + LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); + } + } + + menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); + menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); + menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); + menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); + menu->show(screen_x, screen_y, this); } void LLTextEditor::drawPreeditMarker() { - static LLUICachedControl preedit_marker_brightness ("UIPreeditMarkerBrightness", 0); - static LLUICachedControl preedit_marker_gap ("UIPreeditMarkerGap", 0); - static LLUICachedControl preedit_marker_position ("UIPreeditMarkerPosition", 0); - static LLUICachedControl preedit_marker_thickness ("UIPreeditMarkerThickness", 0); - static LLUICachedControl preedit_standout_brightness ("UIPreeditStandoutBrightness", 0); - static LLUICachedControl preedit_standout_gap ("UIPreeditStandoutGap", 0); - static LLUICachedControl preedit_standout_position ("UIPreeditStandoutPosition", 0); - static LLUICachedControl preedit_standout_thickness ("UIPreeditStandoutThickness", 0); + static LLUICachedControl preedit_marker_brightness ("UIPreeditMarkerBrightness", 0); + static LLUICachedControl preedit_marker_gap ("UIPreeditMarkerGap", 0); + static LLUICachedControl preedit_marker_position ("UIPreeditMarkerPosition", 0); + static LLUICachedControl preedit_marker_thickness ("UIPreeditMarkerThickness", 0); + static LLUICachedControl preedit_standout_brightness ("UIPreeditStandoutBrightness", 0); + static LLUICachedControl preedit_standout_gap ("UIPreeditStandoutGap", 0); + static LLUICachedControl preedit_standout_position ("UIPreeditStandoutPosition", 0); + static LLUICachedControl preedit_standout_thickness ("UIPreeditStandoutThickness", 0); - if (!hasPreeditString()) - { - return; - } + if (!hasPreeditString()) + { + return; + } const LLWString textString(getWText()); - const llwchar *text = textString.c_str(); - const S32 text_len = getLength(); - const S32 num_lines = getLineCount(); - - S32 cur_line = getFirstVisibleLine(); - if (cur_line >= num_lines) - { - return; - } - - const S32 line_height = mFont->getLineHeight(); - - S32 line_start = getLineStart(cur_line); - S32 line_y = mVisibleTextRect.mTop - line_height; - while((mVisibleTextRect.mBottom <= line_y) && (num_lines > cur_line)) - { - S32 next_start = -1; - S32 line_end = text_len; - - if ((cur_line + 1) < num_lines) - { - next_start = getLineStart(cur_line + 1); - line_end = next_start; - } - if ( text[line_end-1] == '\n' ) - { - --line_end; - } - - // Does this line contain preedits? - if (line_start >= mPreeditPositions.back()) - { - // We have passed the preedits. - break; - } - if (line_end > mPreeditPositions.front()) - { - for (U32 i = 0; i < mPreeditStandouts.size(); i++) - { - S32 left = mPreeditPositions[i]; - S32 right = mPreeditPositions[i + 1]; - if (right <= line_start || left >= line_end) - { - continue; - } - - line_info& line = mLineInfoList[cur_line]; - LLRect text_rect(line.mRect); - text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents - text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position - - S32 preedit_left = text_rect.mLeft; - if (left > line_start) - { - preedit_left += mFont->getWidth(text, line_start, left - line_start); - } - S32 preedit_right = text_rect.mLeft; - if (right < line_end) - { - preedit_right += mFont->getWidth(text, line_start, right - line_start); - } - else - { - preedit_right += mFont->getWidth(text, line_start, line_end - line_start); - } - - if (mPreeditStandouts[i]) - { - gl_rect_2d(preedit_left + preedit_standout_gap, - text_rect.mBottom + mFont->getDescenderHeight() - 1, - preedit_right - preedit_standout_gap - 1, - text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_standout_thickness, - (mCursorColor.get() * preedit_standout_brightness + mWriteableBgColor.get() * (1 - preedit_standout_brightness)).setAlpha(1.0f)); - } - else - { - gl_rect_2d(preedit_left + preedit_marker_gap, - text_rect.mBottom + mFont->getDescenderHeight() - 1, - preedit_right - preedit_marker_gap - 1, - text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_marker_thickness, - (mCursorColor.get() * preedit_marker_brightness + mWriteableBgColor.get() * (1 - preedit_marker_brightness)).setAlpha(1.0f)); - } - } - } - - // move down one line - line_y -= line_height; - line_start = next_start; - cur_line++; - } + const llwchar *text = textString.c_str(); + const S32 text_len = getLength(); + const S32 num_lines = getLineCount(); + + S32 cur_line = getFirstVisibleLine(); + if (cur_line >= num_lines) + { + return; + } + + const S32 line_height = mFont->getLineHeight(); + + S32 line_start = getLineStart(cur_line); + S32 line_y = mVisibleTextRect.mTop - line_height; + while((mVisibleTextRect.mBottom <= line_y) && (num_lines > cur_line)) + { + S32 next_start = -1; + S32 line_end = text_len; + + if ((cur_line + 1) < num_lines) + { + next_start = getLineStart(cur_line + 1); + line_end = next_start; + } + if ( text[line_end-1] == '\n' ) + { + --line_end; + } + + // Does this line contain preedits? + if (line_start >= mPreeditPositions.back()) + { + // We have passed the preedits. + break; + } + if (line_end > mPreeditPositions.front()) + { + for (U32 i = 0; i < mPreeditStandouts.size(); i++) + { + S32 left = mPreeditPositions[i]; + S32 right = mPreeditPositions[i + 1]; + if (right <= line_start || left >= line_end) + { + continue; + } + + line_info& line = mLineInfoList[cur_line]; + LLRect text_rect(line.mRect); + text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents + text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position + + S32 preedit_left = text_rect.mLeft; + if (left > line_start) + { + preedit_left += mFont->getWidth(text, line_start, left - line_start); + } + S32 preedit_right = text_rect.mLeft; + if (right < line_end) + { + preedit_right += mFont->getWidth(text, line_start, right - line_start); + } + else + { + preedit_right += mFont->getWidth(text, line_start, line_end - line_start); + } + + if (mPreeditStandouts[i]) + { + gl_rect_2d(preedit_left + preedit_standout_gap, + text_rect.mBottom + mFont->getDescenderHeight() - 1, + preedit_right - preedit_standout_gap - 1, + text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_standout_thickness, + (mCursorColor.get() * preedit_standout_brightness + mWriteableBgColor.get() * (1 - preedit_standout_brightness)).setAlpha(1.0f)); + } + else + { + gl_rect_2d(preedit_left + preedit_marker_gap, + text_rect.mBottom + mFont->getDescenderHeight() - 1, + preedit_right - preedit_marker_gap - 1, + text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_marker_thickness, + (mCursorColor.get() * preedit_marker_brightness + mWriteableBgColor.get() * (1 - preedit_marker_brightness)).setAlpha(1.0f)); + } + } + } + + // move down one line + line_y -= line_height; + line_start = next_start; + cur_line++; + } } void LLTextEditor::draw() { - { - // pad clipping rectangle so that cursor can draw at full width - // when at left edge of mVisibleTextRect - LLRect clip_rect(mVisibleTextRect); - clip_rect.stretch(1); - LLLocalClipRect clip(clip_rect); - } + { + // pad clipping rectangle so that cursor can draw at full width + // when at left edge of mVisibleTextRect + LLRect clip_rect(mVisibleTextRect); + clip_rect.stretch(1); + LLLocalClipRect clip(clip_rect); + } - LLTextBase::draw(); + LLTextBase::draw(); drawPreeditMarker(); - //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret - // when in readonly mode - mBorder->setKeyboardFocusHighlight( hasFocus() );// && !mReadOnly); + //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret + // when in readonly mode + mBorder->setKeyboardFocusHighlight( hasFocus() );// && !mReadOnly); } // Start or stop the editor from accepting text-editing keystrokes // see also LLLineEditor void LLTextEditor::setFocus( BOOL new_state ) { - BOOL old_state = hasFocus(); + BOOL old_state = hasFocus(); - // Don't change anything if the focus state didn't change - if (new_state == old_state) return; + // Don't change anything if the focus state didn't change + if (new_state == old_state) return; - // Notify early if we are losing focus. - if (!new_state) - { - getWindow()->allowLanguageTextInput(this, FALSE); - } + // Notify early if we are losing focus. + if (!new_state) + { + getWindow()->allowLanguageTextInput(this, FALSE); + } - LLTextBase::setFocus( new_state ); + LLTextBase::setFocus( new_state ); - if( new_state ) - { - // Route menu to this class - gEditMenuHandler = this; + if( new_state ) + { + // Route menu to this class + gEditMenuHandler = this; - // Don't start the cursor flashing right away - resetCursorBlink(); - } - else - { - // Route menu back to the default - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } + // Don't start the cursor flashing right away + resetCursorBlink(); + } + else + { + // Route menu back to the default + if( gEditMenuHandler == this ) + { + gEditMenuHandler = NULL; + } - endSelection(); - } + endSelection(); + } } // public void LLTextEditor::setCursorAndScrollToEnd() { - deselect(); - endOfDoc(); + deselect(); + endOfDoc(); } -void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ) -{ - *line = getLineNumFromDocIndex(mCursorPos, include_wordwrap); - *col = getLineOffsetFromDocIndex(mCursorPos, include_wordwrap); +void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ) +{ + *line = getLineNumFromDocIndex(mCursorPos, include_wordwrap); + *col = getLineOffsetFromDocIndex(mCursorPos, include_wordwrap); } void LLTextEditor::autoIndent() { - // Count the number of spaces in the current line - S32 line = getLineNumFromDocIndex(mCursorPos, false); - S32 line_start = getLineStart(line); - S32 space_count = 0; - S32 i; + // Count the number of spaces in the current line + S32 line = getLineNumFromDocIndex(mCursorPos, false); + S32 line_start = getLineStart(line); + S32 space_count = 0; + S32 i; - LLWString text = getWText(); - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - while(( ' ' == text[line_start] ) && (space_count < offset)) - { - space_count++; - line_start++; - } + LLWString text = getWText(); + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + while(( ' ' == text[line_start] ) && (space_count < offset)) + { + space_count++; + line_start++; + } - // If we're starting a braced section, indent one level. - if( (mCursorPos > 0) && (text[mCursorPos -1] == '{') ) - { - space_count += SPACES_PER_TAB; - } + // If we're starting a braced section, indent one level. + if( (mCursorPos > 0) && (text[mCursorPos -1] == '{') ) + { + space_count += SPACES_PER_TAB; + } - // Insert that number of spaces on the new line + // Insert that number of spaces on the new line - //appendLineBreakSegment(LLStyle::Params());//addChar( '\n' ); - addLineBreakChar(); + //appendLineBreakSegment(LLStyle::Params());//addChar( '\n' ); + addLineBreakChar(); - for( i = 0; i < space_count; i++ ) - { - addChar( ' ' ); - } + for( i = 0; i < space_count; i++ ) + { + addChar( ' ' ); + } } // Inserts new text at the cursor position void LLTextEditor::insertText(const std::string &new_text) { - BOOL enabled = getEnabled(); - setEnabled( TRUE ); + BOOL enabled = getEnabled(); + setEnabled( TRUE ); + + // Delete any selected characters (the insertion replaces them) + if( hasSelection() ) + { + deleteSelection(TRUE); + } - // Delete any selected characters (the insertion replaces them) - if( hasSelection() ) - { - deleteSelection(TRUE); - } + setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE, LLTextSegmentPtr() )); - setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE, LLTextSegmentPtr() )); - - setEnabled( enabled ); + setEnabled( enabled ); } void LLTextEditor::insertText(LLWString &new_text) { - BOOL enabled = getEnabled(); - setEnabled( TRUE ); + BOOL enabled = getEnabled(); + setEnabled( TRUE ); - // Delete any selected characters (the insertion replaces them) - if( hasSelection() ) - { - deleteSelection(TRUE); - } + // Delete any selected characters (the insertion replaces them) + if( hasSelection() ) + { + deleteSelection(TRUE); + } - setCursorPos(mCursorPos + insert( mCursorPos, new_text, FALSE, LLTextSegmentPtr() )); + setCursorPos(mCursorPos + insert( mCursorPos, new_text, FALSE, LLTextSegmentPtr() )); - setEnabled( enabled ); + setEnabled( enabled ); } void LLTextEditor::appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo) { - // Save old state - S32 selection_start = mSelectionStart; - S32 selection_end = mSelectionEnd; - BOOL was_selecting = mIsSelecting; - S32 cursor_pos = mCursorPos; - S32 old_length = getLength(); - BOOL cursor_was_at_end = (mCursorPos == old_length); + // Save old state + S32 selection_start = mSelectionStart; + S32 selection_end = mSelectionEnd; + BOOL was_selecting = mIsSelecting; + S32 cursor_pos = mCursorPos; + S32 old_length = getLength(); + BOOL cursor_was_at_end = (mCursorPos == old_length); - deselect(); + deselect(); - setCursorPos(old_length); + setCursorPos(old_length); - LLWString widget_wide_text = utf8str_to_wstring(text); + LLWString widget_wide_text = utf8str_to_wstring(text); - LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size()); - insert(getLength(), widget_wide_text, FALSE, segment); + LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size()); + insert(getLength(), widget_wide_text, FALSE, segment); - // Set the cursor and scroll position - if( selection_start != selection_end ) - { - mSelectionStart = selection_start; - mSelectionEnd = selection_end; + // Set the cursor and scroll position + if( selection_start != selection_end ) + { + mSelectionStart = selection_start; + mSelectionEnd = selection_end; - mIsSelecting = was_selecting; - setCursorPos(cursor_pos); - } - else if( cursor_was_at_end ) - { - setCursorPos(getLength()); - } - else - { - setCursorPos(cursor_pos); - } + mIsSelecting = was_selecting; + setCursorPos(cursor_pos); + } + else if( cursor_was_at_end ) + { + setCursorPos(getLength()); + } + else + { + setCursorPos(cursor_pos); + } - if (!allow_undo) - { - blockUndo(); - } + if (!allow_undo) + { + blockUndo(); + } } void LLTextEditor::removeTextFromEnd(S32 num_chars) { - if (num_chars <= 0) return; + if (num_chars <= 0) return; - remove(getLength() - num_chars, num_chars, FALSE); + remove(getLength() - num_chars, num_chars, FALSE); - S32 len = getLength(); - setCursorPos (llclamp(mCursorPos, 0, len)); - mSelectionStart = llclamp(mSelectionStart, 0, len); - mSelectionEnd = llclamp(mSelectionEnd, 0, len); + S32 len = getLength(); + setCursorPos (llclamp(mCursorPos, 0, len)); + mSelectionStart = llclamp(mSelectionStart, 0, len); + mSelectionEnd = llclamp(mSelectionEnd, 0, len); - needsScroll(); + needsScroll(); } //---------------------------------------------------------------------------- void LLTextEditor::onSpellCheckPerformed() { - if (isPristine()) - { - mBaseDocIsPristine = FALSE; - } + if (isPristine()) + { + mBaseDocIsPristine = FALSE; + } } void LLTextEditor::makePristine() { - mPristineCmd = mLastCmd; - mBaseDocIsPristine = !mLastCmd; + mPristineCmd = mLastCmd; + mBaseDocIsPristine = !mLastCmd; - // Create a clean partition in the undo stack. We don't want a single command to extend from - // the "pre-pristine" state to the "post-pristine" state. - if( mLastCmd ) - { - mLastCmd->blockExtensions(); - } + // Create a clean partition in the undo stack. We don't want a single command to extend from + // the "pre-pristine" state to the "post-pristine" state. + if( mLastCmd ) + { + mLastCmd->blockExtensions(); + } } BOOL LLTextEditor::isPristine() const { - if( mPristineCmd ) - { - return (mPristineCmd == mLastCmd); - } - else - { - // No undo stack, so check if the version before and commands were done was the original version - return !mLastCmd && mBaseDocIsPristine; - } + if( mPristineCmd ) + { + return (mPristineCmd == mLastCmd); + } + else + { + // No undo stack, so check if the version before and commands were done was the original version + return !mLastCmd && mBaseDocIsPristine; + } } BOOL LLTextEditor::tryToRevertToPristineState() { - if( !isPristine() ) - { - deselect(); - S32 i = 0; - while( !isPristine() && canUndo() ) - { - undo(); - i--; - } - - while( !isPristine() && canRedo() ) - { - redo(); - i++; - } - - if( !isPristine() ) - { - // failed, so go back to where we started - while( i > 0 ) - { - undo(); - i--; - } - } - } - - return isPristine(); // TRUE => success + if( !isPristine() ) + { + deselect(); + S32 i = 0; + while( !isPristine() && canUndo() ) + { + undo(); + i--; + } + + while( !isPristine() && canRedo() ) + { + redo(); + i++; + } + + if( !isPristine() ) + { + // failed, so go back to where we started + while( i > 0 ) + { + undo(); + i--; + } + } + } + + return isPristine(); // TRUE => success } void LLTextEditor::updateLinkSegments() { - LLWString wtext = getWText(); - - // update any segments that contain a link - for (segment_set_t::iterator it = mSegments.begin(); it != mSegments.end(); ++it) - { - LLTextSegment *segment = *it; - if (segment && segment->getStyle() && segment->getStyle()->isLink()) - { - LLStyleConstSP style = segment->getStyle(); - LLStyleSP new_style(new LLStyle(*style)); - LLWString url_label = wtext.substr(segment->getStart(), segment->getEnd()-segment->getStart()); - - segment_set_t::const_iterator next_it = mSegments.upper_bound(segment); - LLTextSegment *next_segment = *next_it; - if (next_segment) - { - LLWString next_url_label = wtext.substr(next_segment->getStart(), next_segment->getEnd()-next_segment->getStart()); - std::string link_check = wstring_to_utf8str(url_label) + wstring_to_utf8str(next_url_label); - LLUrlMatch match; - - if ( LLUrlRegistry::instance().findUrl(link_check, match)) - { - if(match.getQuery() == wstring_to_utf8str(next_url_label)) - { - continue; - } - } - } - - // if the link's label (what the user can edit) is a valid Url, - // then update the link's HREF to be the same as the label text. - // This lets users edit Urls in-place. - if (acceptsTextInput() && LLUrlRegistry::instance().hasUrl(url_label)) - { - std::string new_url = wstring_to_utf8str(url_label); - LLStringUtil::trim(new_url); - new_style->setLinkHREF(new_url); - LLStyleConstSP sp(new_style); - segment->setStyle(sp); - } - } - } + LLWString wtext = getWText(); + + // update any segments that contain a link + for (segment_set_t::iterator it = mSegments.begin(); it != mSegments.end(); ++it) + { + LLTextSegment *segment = *it; + if (segment && segment->getStyle() && segment->getStyle()->isLink()) + { + LLStyleConstSP style = segment->getStyle(); + LLStyleSP new_style(new LLStyle(*style)); + LLWString url_label = wtext.substr(segment->getStart(), segment->getEnd()-segment->getStart()); + + segment_set_t::const_iterator next_it = mSegments.upper_bound(segment); + LLTextSegment *next_segment = *next_it; + if (next_segment) + { + LLWString next_url_label = wtext.substr(next_segment->getStart(), next_segment->getEnd()-next_segment->getStart()); + std::string link_check = wstring_to_utf8str(url_label) + wstring_to_utf8str(next_url_label); + LLUrlMatch match; + + if ( LLUrlRegistry::instance().findUrl(link_check, match)) + { + if(match.getQuery() == wstring_to_utf8str(next_url_label)) + { + continue; + } + } + } + + // if the link's label (what the user can edit) is a valid Url, + // then update the link's HREF to be the same as the label text. + // This lets users edit Urls in-place. + if (acceptsTextInput() && LLUrlRegistry::instance().hasUrl(url_label)) + { + std::string new_url = wstring_to_utf8str(url_label); + LLStringUtil::trim(new_url); + new_style->setLinkHREF(new_url); + LLStyleConstSP sp(new_style); + segment->setStyle(sp); + } + } + } } void LLTextEditor::onMouseCaptureLost() { - endSelection(); + endSelection(); } /////////////////////////////////////////////////////////////////// @@ -2644,135 +2644,135 @@ void LLTextEditor::onMouseCaptureLost() BOOL LLTextEditor::importBuffer(const char* buffer, S32 length ) { - std::istringstream instream(buffer); - - // Version 1 format: - // Linden text version 1\n - // {\n - // - // Text length \n - // (text may contain ext_char_values) - // }\n - - char tbuf[MAX_STRING]; /* Flawfinder: ignore */ - - S32 version = 0; - instream.getline(tbuf, MAX_STRING); - if( 1 != sscanf(tbuf, "Linden text version %d", &version) ) - { - LL_WARNS() << "Invalid Linden text file header " << LL_ENDL; - return FALSE; - } - - if( 1 != version ) - { - LL_WARNS() << "Invalid Linden text file version: " << version << LL_ENDL; - return FALSE; - } - - instream.getline(tbuf, MAX_STRING); - if( 0 != sscanf(tbuf, "{") ) - { - LL_WARNS() << "Invalid Linden text file format" << LL_ENDL; - return FALSE; - } - - S32 text_len = 0; - instream.getline(tbuf, MAX_STRING); - if( 1 != sscanf(tbuf, "Text length %d", &text_len) ) - { - LL_WARNS() << "Invalid Linden text length field" << LL_ENDL; - return FALSE; - } - - if( text_len > mMaxTextByteLength ) - { - LL_WARNS() << "Invalid Linden text length: " << text_len << LL_ENDL; - return FALSE; - } - - BOOL success = TRUE; - - char* text = new char[ text_len + 1]; - if (text == NULL) - { + std::istringstream instream(buffer); + + // Version 1 format: + // Linden text version 1\n + // {\n + // + // Text length \n + // (text may contain ext_char_values) + // }\n + + char tbuf[MAX_STRING]; /* Flawfinder: ignore */ + + S32 version = 0; + instream.getline(tbuf, MAX_STRING); + if( 1 != sscanf(tbuf, "Linden text version %d", &version) ) + { + LL_WARNS() << "Invalid Linden text file header " << LL_ENDL; + return FALSE; + } + + if( 1 != version ) + { + LL_WARNS() << "Invalid Linden text file version: " << version << LL_ENDL; + return FALSE; + } + + instream.getline(tbuf, MAX_STRING); + if( 0 != sscanf(tbuf, "{") ) + { + LL_WARNS() << "Invalid Linden text file format" << LL_ENDL; + return FALSE; + } + + S32 text_len = 0; + instream.getline(tbuf, MAX_STRING); + if( 1 != sscanf(tbuf, "Text length %d", &text_len) ) + { + LL_WARNS() << "Invalid Linden text length field" << LL_ENDL; + return FALSE; + } + + if( text_len > mMaxTextByteLength ) + { + LL_WARNS() << "Invalid Linden text length: " << text_len << LL_ENDL; + return FALSE; + } + + BOOL success = TRUE; + + char* text = new char[ text_len + 1]; + if (text == NULL) + { LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS() << "Memory allocation failure." << LL_ENDL; - return FALSE; - } - instream.get(text, text_len + 1, '\0'); - text[text_len] = '\0'; - if( text_len != (S32)strlen(text) )/* Flawfinder: ignore */ - { - LL_WARNS() << llformat("Invalid text length: %d != %d ",strlen(text),text_len) << LL_ENDL;/* Flawfinder: ignore */ - success = FALSE; - } - - instream.getline(tbuf, MAX_STRING); - if( success && (0 != sscanf(tbuf, "}")) ) - { - LL_WARNS() << "Invalid Linden text file format: missing terminal }" << LL_ENDL; - success = FALSE; - } - - if( success ) - { - // Actually set the text - setText( LLStringExplicit(text) ); - } - - delete[] text; - - startOfDoc(); - deselect(); - - return success; + LL_ERRS() << "Memory allocation failure." << LL_ENDL; + return FALSE; + } + instream.get(text, text_len + 1, '\0'); + text[text_len] = '\0'; + if( text_len != (S32)strlen(text) )/* Flawfinder: ignore */ + { + LL_WARNS() << llformat("Invalid text length: %d != %d ",strlen(text),text_len) << LL_ENDL;/* Flawfinder: ignore */ + success = FALSE; + } + + instream.getline(tbuf, MAX_STRING); + if( success && (0 != sscanf(tbuf, "}")) ) + { + LL_WARNS() << "Invalid Linden text file format: missing terminal }" << LL_ENDL; + success = FALSE; + } + + if( success ) + { + // Actually set the text + setText( LLStringExplicit(text) ); + } + + delete[] text; + + startOfDoc(); + deselect(); + + return success; } BOOL LLTextEditor::exportBuffer(std::string &buffer ) { - std::ostringstream outstream(buffer); - - outstream << "Linden text version 1\n"; - outstream << "{\n"; + std::ostringstream outstream(buffer); - outstream << llformat("Text length %d\n", getLength() ); - outstream << getText(); - outstream << "}\n"; + outstream << "Linden text version 1\n"; + outstream << "{\n"; - return TRUE; + outstream << llformat("Text length %d\n", getLength() ); + outstream << getText(); + outstream << "}\n"; + + return TRUE; } void LLTextEditor::updateAllowingLanguageInput() { - LLWindow* window = getWindow(); - if (!window) - { - // test app, no window available - return; - } - if (hasFocus() && !mReadOnly) - { - window->allowLanguageTextInput(this, TRUE); - } - else - { - window->allowLanguageTextInput(this, FALSE); - } + LLWindow* window = getWindow(); + if (!window) + { + // test app, no window available + return; + } + if (hasFocus() && !mReadOnly) + { + window->allowLanguageTextInput(this, TRUE); + } + else + { + window->allowLanguageTextInput(this, FALSE); + } } // Preedit is managed off the undo/redo command stack. BOOL LLTextEditor::hasPreeditString() const { - return (mPreeditPositions.size() > 1); + return (mPreeditPositions.size() > 1); } void LLTextEditor::resetPreedit() { if (hasSelection()) { - if (hasPreeditString()) + if (hasPreeditString()) { LL_WARNS() << "Preedit and selection!" << LL_ENDL; deselect(); @@ -2782,277 +2782,277 @@ void LLTextEditor::resetPreedit() deleteSelection(TRUE); } } - if (hasPreeditString()) - { - if (hasSelection()) - { - LL_WARNS() << "Preedit and selection!" << LL_ENDL; - deselect(); - } + if (hasPreeditString()) + { + if (hasSelection()) + { + LL_WARNS() << "Preedit and selection!" << LL_ENDL; + deselect(); + } - setCursorPos(mPreeditPositions.front()); - removeStringNoUndo(mCursorPos, mPreeditPositions.back() - mCursorPos); - insertStringNoUndo(mCursorPos, mPreeditOverwrittenWString); + setCursorPos(mPreeditPositions.front()); + removeStringNoUndo(mCursorPos, mPreeditPositions.back() - mCursorPos); + insertStringNoUndo(mCursorPos, mPreeditOverwrittenWString); - mPreeditWString.clear(); - mPreeditOverwrittenWString.clear(); - mPreeditPositions.clear(); + mPreeditWString.clear(); + mPreeditOverwrittenWString.clear(); + mPreeditPositions.clear(); - // A call to updatePreedit should soon follow under a - // normal course of operation, so we don't need to - // maintain internal variables such as line start - // positions now. - } + // A call to updatePreedit should soon follow under a + // normal course of operation, so we don't need to + // maintain internal variables such as line start + // positions now. + } } void LLTextEditor::updatePreedit(const LLWString &preedit_string, - const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) + const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) { - // Just in case. - if (mReadOnly) - { - return; - } + // Just in case. + if (mReadOnly) + { + return; + } + + getWindow()->hideCursorUntilMouseMove(); - getWindow()->hideCursorUntilMouseMove(); + S32 insert_preedit_at = mCursorPos; - S32 insert_preedit_at = mCursorPos; + mPreeditWString = preedit_string; + mPreeditPositions.resize(preedit_segment_lengths.size() + 1); + S32 position = insert_preedit_at; + for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++) + { + mPreeditPositions[i] = position; + position += preedit_segment_lengths[i]; + } + mPreeditPositions.back() = position; - mPreeditWString = preedit_string; - mPreeditPositions.resize(preedit_segment_lengths.size() + 1); - S32 position = insert_preedit_at; - for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++) - { - mPreeditPositions[i] = position; - position += preedit_segment_lengths[i]; - } - mPreeditPositions.back() = position; + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + mPreeditOverwrittenWString = getWText().substr(insert_preedit_at, mPreeditWString.length()); + removeStringNoUndo(insert_preedit_at, mPreeditWString.length()); + } + else + { + mPreeditOverwrittenWString.clear(); + } - if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - mPreeditOverwrittenWString = getWText().substr(insert_preedit_at, mPreeditWString.length()); - removeStringNoUndo(insert_preedit_at, mPreeditWString.length()); - } - else - { - mPreeditOverwrittenWString.clear(); - } - - segment_vec_t segments; - //pass empty segments to let "insertStringNoUndo" make new LLNormalTextSegment and insert it, if needed. - insertStringNoUndo(insert_preedit_at, mPreeditWString, &segments); + segment_vec_t segments; + //pass empty segments to let "insertStringNoUndo" make new LLNormalTextSegment and insert it, if needed. + insertStringNoUndo(insert_preedit_at, mPreeditWString, &segments); - mPreeditStandouts = preedit_standouts; + mPreeditStandouts = preedit_standouts; - setCursorPos(insert_preedit_at + caret_position); + setCursorPos(insert_preedit_at + caret_position); - // Update of the preedit should be caused by some key strokes. - resetCursorBlink(); + // Update of the preedit should be caused by some key strokes. + resetCursorBlink(); - onKeyStroke(); + onKeyStroke(); } BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const { - if (control) - { - LLRect control_rect_screen; - localRectToScreen(mVisibleTextRect, &control_rect_screen); - LLUI::getInstance()->screenRectToGL(control_rect_screen, control); - } - - S32 preedit_left_position, preedit_right_position; - if (hasPreeditString()) - { - preedit_left_position = mPreeditPositions.front(); - preedit_right_position = mPreeditPositions.back(); - } - else - { - preedit_left_position = preedit_right_position = mCursorPos; - } - - const S32 query = (query_offset >= 0 ? preedit_left_position + query_offset : mCursorPos); - if (query < preedit_left_position || query > preedit_right_position) - { - return FALSE; - } - - const S32 first_visible_line = getFirstVisibleLine(); - if (query < getLineStart(first_visible_line)) - { - return FALSE; - } - - S32 current_line = first_visible_line; - S32 current_line_start, current_line_end; - for (;;) - { - current_line_start = getLineStart(current_line); - current_line_end = getLineStart(current_line + 1); - if (query >= current_line_start && query < current_line_end) - { - break; - } - if (current_line_start == current_line_end) - { - // We have reached on the last line. The query position must be here. - break; - } - current_line++; - } + if (control) + { + LLRect control_rect_screen; + localRectToScreen(mVisibleTextRect, &control_rect_screen); + LLUI::getInstance()->screenRectToGL(control_rect_screen, control); + } + + S32 preedit_left_position, preedit_right_position; + if (hasPreeditString()) + { + preedit_left_position = mPreeditPositions.front(); + preedit_right_position = mPreeditPositions.back(); + } + else + { + preedit_left_position = preedit_right_position = mCursorPos; + } + + const S32 query = (query_offset >= 0 ? preedit_left_position + query_offset : mCursorPos); + if (query < preedit_left_position || query > preedit_right_position) + { + return FALSE; + } + + const S32 first_visible_line = getFirstVisibleLine(); + if (query < getLineStart(first_visible_line)) + { + return FALSE; + } + + S32 current_line = first_visible_line; + S32 current_line_start, current_line_end; + for (;;) + { + current_line_start = getLineStart(current_line); + current_line_end = getLineStart(current_line + 1); + if (query >= current_line_start && query < current_line_end) + { + break; + } + if (current_line_start == current_line_end) + { + // We have reached on the last line. The query position must be here. + break; + } + current_line++; + } const LLWString textString(getWText()); - const llwchar * const text = textString.c_str(); - const S32 line_height = mFont->getLineHeight(); - - if (coord) - { - const S32 query_x = mVisibleTextRect.mLeft + mFont->getWidth(text, current_line_start, query - current_line_start); - const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2; - S32 query_screen_x, query_screen_y; - localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y); - LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); - } - - if (bounds) - { - S32 preedit_left = mVisibleTextRect.mLeft; - if (preedit_left_position > current_line_start) - { - preedit_left += mFont->getWidth(text, current_line_start, preedit_left_position - current_line_start); - } - - S32 preedit_right = mVisibleTextRect.mLeft; - if (preedit_right_position < current_line_end) - { - preedit_right += mFont->getWidth(text, current_line_start, preedit_right_position - current_line_start); - } - else - { - preedit_right += mFont->getWidth(text, current_line_start, current_line_end - current_line_start); - } - - const S32 preedit_top = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height; - const S32 preedit_bottom = preedit_top - line_height; - - const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom); - LLRect preedit_rect_screen; - localRectToScreen(preedit_rect_local, &preedit_rect_screen); - LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds); - } - - return TRUE; + const llwchar * const text = textString.c_str(); + const S32 line_height = mFont->getLineHeight(); + + if (coord) + { + const S32 query_x = mVisibleTextRect.mLeft + mFont->getWidth(text, current_line_start, query - current_line_start); + const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2; + S32 query_screen_x, query_screen_y; + localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y); + LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); + } + + if (bounds) + { + S32 preedit_left = mVisibleTextRect.mLeft; + if (preedit_left_position > current_line_start) + { + preedit_left += mFont->getWidth(text, current_line_start, preedit_left_position - current_line_start); + } + + S32 preedit_right = mVisibleTextRect.mLeft; + if (preedit_right_position < current_line_end) + { + preedit_right += mFont->getWidth(text, current_line_start, preedit_right_position - current_line_start); + } + else + { + preedit_right += mFont->getWidth(text, current_line_start, current_line_end - current_line_start); + } + + const S32 preedit_top = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height; + const S32 preedit_bottom = preedit_top - line_height; + + const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom); + LLRect preedit_rect_screen; + localRectToScreen(preedit_rect_local, &preedit_rect_screen); + LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds); + } + + return TRUE; } void LLTextEditor::getSelectionRange(S32 *position, S32 *length) const { - if (hasSelection()) - { - *position = llmin(mSelectionStart, mSelectionEnd); - *length = llabs(mSelectionStart - mSelectionEnd); - } - else - { - *position = mCursorPos; - *length = 0; - } + if (hasSelection()) + { + *position = llmin(mSelectionStart, mSelectionEnd); + *length = llabs(mSelectionStart - mSelectionEnd); + } + else + { + *position = mCursorPos; + *length = 0; + } } void LLTextEditor::getPreeditRange(S32 *position, S32 *length) const { - if (hasPreeditString()) - { - *position = mPreeditPositions.front(); - *length = mPreeditPositions.back() - mPreeditPositions.front(); - } - else - { - *position = mCursorPos; - *length = 0; - } + if (hasPreeditString()) + { + *position = mPreeditPositions.front(); + *length = mPreeditPositions.back() - mPreeditPositions.front(); + } + else + { + *position = mCursorPos; + *length = 0; + } } void LLTextEditor::markAsPreedit(S32 position, S32 length) { - deselect(); - setCursorPos(position); - if (hasPreeditString()) - { - LL_WARNS() << "markAsPreedit invoked when hasPreeditString is true." << LL_ENDL; - } - mPreeditWString = LLWString( getWText(), position, length ); - if (length > 0) - { - mPreeditPositions.resize(2); - mPreeditPositions[0] = position; - mPreeditPositions[1] = position + length; - mPreeditStandouts.resize(1); - mPreeditStandouts[0] = FALSE; - } - else - { - mPreeditPositions.clear(); - mPreeditStandouts.clear(); - } - if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - mPreeditOverwrittenWString = mPreeditWString; - } - else - { - mPreeditOverwrittenWString.clear(); - } + deselect(); + setCursorPos(position); + if (hasPreeditString()) + { + LL_WARNS() << "markAsPreedit invoked when hasPreeditString is true." << LL_ENDL; + } + mPreeditWString = LLWString( getWText(), position, length ); + if (length > 0) + { + mPreeditPositions.resize(2); + mPreeditPositions[0] = position; + mPreeditPositions[1] = position + length; + mPreeditStandouts.resize(1); + mPreeditStandouts[0] = FALSE; + } + else + { + mPreeditPositions.clear(); + mPreeditStandouts.clear(); + } + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + mPreeditOverwrittenWString = mPreeditWString; + } + else + { + mPreeditOverwrittenWString.clear(); + } } S32 LLTextEditor::getPreeditFontSize() const { - return ll_round((F32)mFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); + return ll_round((F32)mFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); } BOOL LLTextEditor::isDirty() const { - if(mReadOnly) - { - return FALSE; - } + if(mReadOnly) + { + return FALSE; + } - if( mPristineCmd ) - { - return ( mPristineCmd == mLastCmd ); - } - else - { - return ( NULL != mLastCmd ); - } + if( mPristineCmd ) + { + return ( mPristineCmd == mLastCmd ); + } + else + { + return ( NULL != mLastCmd ); + } } void LLTextEditor::setKeystrokeCallback(const keystroke_signal_t::slot_type& callback) { - mKeystrokeSignal.connect(callback); + mKeystrokeSignal.connect(callback); } void LLTextEditor::onKeyStroke() { - mKeystrokeSignal(this); + mKeystrokeSignal(this); - mSpellCheckStart = mSpellCheckEnd = -1; - mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); + mSpellCheckStart = mSpellCheckEnd = -1; + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } //virtual void LLTextEditor::clear() { - getViewModel()->setDisplay(LLWStringUtil::null); - clearSegments(); + getViewModel()->setDisplay(LLWStringUtil::null); + clearSegments(); } bool LLTextEditor::canLoadOrSaveToFile() { - return !mReadOnly; + return !mReadOnly; } S32 LLTextEditor::spacesPerTab() { - return SPACES_PER_TAB; + return SPACES_PER_TAB; } diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 658bfb9295..2bc4184ca8 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -48,316 +48,316 @@ class LLUICtrlFactory; class LLScrollContainer; class LLTextEditor : - public LLTextBase, - protected LLPreeditor + public LLTextBase, + protected LLPreeditor { public: - struct Params : public LLInitParam::Block - { - Optional default_text; - Optional prevalidate_callback; - - Optional embedded_items, - ignore_tab, - commit_on_focus_lost, - show_context_menu, - show_emoji_helper, - enable_tooltip_paste, - auto_indent; - - //colors - Optional default_color; - - Params(); - }; - - void initFromParams(const Params&); + struct Params : public LLInitParam::Block + { + Optional default_text; + Optional prevalidate_callback; + + Optional embedded_items, + ignore_tab, + commit_on_focus_lost, + show_context_menu, + show_emoji_helper, + enable_tooltip_paste, + auto_indent; + + //colors + Optional default_color; + + Params(); + }; + + void initFromParams(const Params&); protected: - LLTextEditor(const Params&); - friend class LLUICtrlFactory; + LLTextEditor(const Params&); + friend class LLUICtrlFactory; public: - // - // Constants - // - static const llwchar FIRST_EMBEDDED_CHAR = 0x100000; - static const llwchar LAST_EMBEDDED_CHAR = 0x10ffff; - static const S32 MAX_EMBEDDED_ITEMS = LAST_EMBEDDED_CHAR - FIRST_EMBEDDED_CHAR + 1; + // + // Constants + // + static const llwchar FIRST_EMBEDDED_CHAR = 0x100000; + static const llwchar LAST_EMBEDDED_CHAR = 0x10ffff; + static const S32 MAX_EMBEDDED_ITEMS = LAST_EMBEDDED_CHAR - FIRST_EMBEDDED_CHAR + 1; - virtual ~LLTextEditor(); + virtual ~LLTextEditor(); - typedef boost::signals2::signal keystroke_signal_t; + typedef boost::signals2::signal keystroke_signal_t; - void setKeystrokeCallback(const keystroke_signal_t::slot_type& callback); + void setKeystrokeCallback(const keystroke_signal_t::slot_type& callback); - void setParseHighlights(BOOL parsing) {mParseHighlights=parsing;} + void setParseHighlights(BOOL parsing) {mParseHighlights=parsing;} - static S32 spacesPerTab(); + static S32 spacesPerTab(); - void insertEmoji(llwchar emoji); - void handleEmojiCommit(llwchar emoji); + void insertEmoji(llwchar emoji); + void handleEmojiCommit(llwchar emoji); - // mousehandler overrides - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask ); - virtual BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask); + // mousehandler overrides + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask ); + virtual BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask); - virtual BOOL handleKeyHere(KEY key, MASK mask ); - virtual BOOL handleUnicodeCharHere(llwchar uni_char); + virtual BOOL handleKeyHere(KEY key, MASK mask ); + virtual BOOL handleUnicodeCharHere(llwchar uni_char); - virtual void onMouseCaptureLost(); + virtual void onMouseCaptureLost(); - // view overrides - virtual void draw(); - virtual void onFocusReceived(); - virtual void onFocusLost(); - virtual void onCommit(); - virtual void setEnabled(BOOL enabled); + // view overrides + virtual void draw(); + virtual void onFocusReceived(); + virtual void onFocusLost(); + virtual void onCommit(); + virtual void setEnabled(BOOL enabled); - // uictrl overrides - virtual void clear(); - virtual void setFocus( BOOL b ); - virtual BOOL isDirty() const; + // uictrl overrides + virtual void clear(); + virtual void setFocus( BOOL b ); + virtual BOOL isDirty() const; - // LLEditMenuHandler interface - virtual void undo(); - virtual BOOL canUndo() const; - virtual void redo(); - virtual BOOL canRedo() const; + // LLEditMenuHandler interface + virtual void undo(); + virtual BOOL canUndo() const; + virtual void redo(); + virtual BOOL canRedo() const; - virtual void cut(); - virtual BOOL canCut() const; - virtual void copy(); - virtual BOOL canCopy() const; - virtual void paste(); - virtual BOOL canPaste() const; + virtual void cut(); + virtual BOOL canCut() const; + virtual void copy(); + virtual BOOL canCopy() const; + virtual void paste(); + virtual BOOL canPaste() const; - virtual void updatePrimary(); - virtual void copyPrimary(); - virtual void pastePrimary(); - virtual BOOL canPastePrimary() const; + virtual void updatePrimary(); + virtual void copyPrimary(); + virtual void pastePrimary(); + virtual BOOL canPastePrimary() const; - virtual void doDelete(); - virtual BOOL canDoDelete() const; - virtual void selectAll(); - virtual BOOL canSelectAll() const; + virtual void doDelete(); + virtual BOOL canDoDelete() const; + virtual void selectAll(); + virtual BOOL canSelectAll() const; - void selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos); + void selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos); - virtual bool canLoadOrSaveToFile(); + virtual bool canLoadOrSaveToFile(); - void selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap = TRUE); - BOOL replaceText(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive, BOOL wrap = TRUE); - void replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive); + void selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap = TRUE); + BOOL replaceText(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive, BOOL wrap = TRUE); + void replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive); - // Undo/redo stack - void blockUndo(); + // Undo/redo stack + void blockUndo(); - // Text editing - virtual void makePristine(); - BOOL isPristine() const; - BOOL allowsEmbeddedItems() const { return mAllowEmbeddedItems; } + // Text editing + virtual void makePristine(); + BOOL isPristine() const; + BOOL allowsEmbeddedItems() const { return mAllowEmbeddedItems; } - // Autoreplace (formerly part of LLLineEditor) - typedef boost::function autoreplace_callback_t; - autoreplace_callback_t mAutoreplaceCallback; - void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; } + // Autoreplace (formerly part of LLLineEditor) + typedef boost::function autoreplace_callback_t; + autoreplace_callback_t mAutoreplaceCallback; + void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; } - /*virtual*/ void onSpellCheckPerformed(); + /*virtual*/ void onSpellCheckPerformed(); - // - // Text manipulation - // + // + // Text manipulation + // - // inserts text at cursor - void insertText(const std::string &text); - void insertText(LLWString &text); + // inserts text at cursor + void insertText(const std::string &text); + void insertText(LLWString &text); - void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo); - // Non-undoable - void setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params = LLStyle::Params()); + void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo); + // Non-undoable + void setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params = LLStyle::Params()); - // Removes text from the end of document - // Does not change highlight or cursor position. - void removeTextFromEnd(S32 num_chars); + // Removes text from the end of document + // Does not change highlight or cursor position. + void removeTextFromEnd(S32 num_chars); - BOOL tryToRevertToPristineState(); + BOOL tryToRevertToPristineState(); - void setCursorAndScrollToEnd(); + void setCursorAndScrollToEnd(); - void getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ); + void getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ); - // Hacky methods to make it into a word-wrapping, potentially scrolling, - // read-only text box. - void setCommitOnFocusLost(BOOL b) { mCommitOnFocusLost = b; } + // Hacky methods to make it into a word-wrapping, potentially scrolling, + // read-only text box. + void setCommitOnFocusLost(BOOL b) { mCommitOnFocusLost = b; } - // Hack to handle Notecards - virtual BOOL importBuffer(const char* buffer, S32 length ); - virtual BOOL exportBuffer(std::string& buffer ); + // Hack to handle Notecards + virtual BOOL importBuffer(const char* buffer, S32 length ); + virtual BOOL exportBuffer(std::string& buffer ); - const LLUUID& getSourceID() const { return mSourceID; } + const LLUUID& getSourceID() const { return mSourceID; } - const LLTextSegmentPtr getPreviousSegment() const; - const LLTextSegmentPtr getLastSegment() const; - void getSelectedSegments(segment_vec_t& segments) const; + const LLTextSegmentPtr getPreviousSegment() const; + const LLTextSegmentPtr getLastSegment() const; + void getSelectedSegments(segment_vec_t& segments) const; - void setShowContextMenu(bool show) { mShowContextMenu = show; } - bool getShowContextMenu() const { return mShowContextMenu; } + void setShowContextMenu(bool show) { mShowContextMenu = show; } + bool getShowContextMenu() const { return mShowContextMenu; } - void showEmojiHelper(); - void setShowEmojiHelper(bool show); - bool getShowEmojiHelper() const { return mShowEmojiHelper; } + void showEmojiHelper(); + void setShowEmojiHelper(bool show); + bool getShowEmojiHelper() const { return mShowEmojiHelper; } - void setPassDelete(BOOL b) { mPassDelete = b; } + void setPassDelete(BOOL b) { mPassDelete = b; } protected: - void showContextMenu(S32 x, S32 y); - void drawPreeditMarker(); + void showContextMenu(S32 x, S32 y); + void drawPreeditMarker(); - void assignEmbedded(const std::string &s); + void assignEmbedded(const std::string &s); - void removeCharOrTab(); + void removeCharOrTab(); - void indentSelectedLines( S32 spaces ); - S32 indentLine( S32 pos, S32 spaces ); - void unindentLineBeforeCloseBrace(); + void indentSelectedLines( S32 spaces ); + S32 indentLine( S32 pos, S32 spaces ); + void unindentLineBeforeCloseBrace(); - virtual BOOL handleSpecialKey(const KEY key, const MASK mask); - BOOL handleNavigationKey(const KEY key, const MASK mask); - BOOL handleSelectionKey(const KEY key, const MASK mask); - BOOL handleControlKey(const KEY key, const MASK mask); + virtual BOOL handleSpecialKey(const KEY key, const MASK mask); + BOOL handleNavigationKey(const KEY key, const MASK mask); + BOOL handleSelectionKey(const KEY key, const MASK mask); + BOOL handleControlKey(const KEY key, const MASK mask); - BOOL selectionContainsLineBreaks(); - void deleteSelection(BOOL transient_operation); + BOOL selectionContainsLineBreaks(); + void deleteSelection(BOOL transient_operation); - S32 prevWordPos(S32 cursorPos) const; - S32 nextWordPos(S32 cursorPos) const; + S32 prevWordPos(S32 cursorPos) const; + S32 nextWordPos(S32 cursorPos) const; - void autoIndent(); + void autoIndent(); - void findEmbeddedItemSegments(S32 start, S32 end); - void getSegmentsInRange(segment_vec_t& segments, S32 start, S32 end, bool include_partial) const; + void findEmbeddedItemSegments(S32 start, S32 end); + void getSegmentsInRange(segment_vec_t& segments, S32 start, S32 end, bool include_partial) const; - virtual llwchar pasteEmbeddedItem(llwchar ext_char) { return ext_char; } + virtual llwchar pasteEmbeddedItem(llwchar ext_char) { return ext_char; } - // Here's the method that takes and applies text commands. - S32 execute(TextCmd* cmd); + // Here's the method that takes and applies text commands. + S32 execute(TextCmd* cmd); - // Undoable operations - void addChar(llwchar c); // at mCursorPos - S32 addChar(S32 pos, llwchar wc); + // Undoable operations + void addChar(llwchar c); // at mCursorPos + S32 addChar(S32 pos, llwchar wc); public: - void addLineBreakChar(BOOL group_together = FALSE); + void addLineBreakChar(BOOL group_together = FALSE); protected: - S32 overwriteChar(S32 pos, llwchar wc); - void removeChar(); - S32 removeChar(S32 pos); - S32 insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment); - S32 remove(S32 pos, S32 length, bool group_with_next_op); - - void tryToShowEmojiHelper(); - void focusLostHelper(); - void updateAllowingLanguageInput(); - BOOL hasPreeditString() const; - - // Overrides LLPreeditor - virtual void resetPreedit(); - virtual void updatePreedit(const LLWString &preedit_string, - const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position); - virtual void markAsPreedit(S32 position, S32 length); - virtual void getPreeditRange(S32 *position, S32 *length) const; - virtual void getSelectionRange(S32 *position, S32 *length) const; - virtual BOOL getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const; - virtual S32 getPreeditFontSize() const; - virtual LLWString getPreeditString() const { return getWText(); } - // - // Protected data - // - // Probably deserves serious thought to hiding as many of these - // as possible behind protected accessor methods. - // - - // Use these to determine if a click on an embedded item is a drag or not. - S32 mMouseDownX; - S32 mMouseDownY; - - LLWString mPreeditWString; - LLWString mPreeditOverwrittenWString; - std::vector mPreeditPositions; - std::vector mPreeditStandouts; + S32 overwriteChar(S32 pos, llwchar wc); + void removeChar(); + S32 removeChar(S32 pos); + S32 insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment); + S32 remove(S32 pos, S32 length, bool group_with_next_op); + + void tryToShowEmojiHelper(); + void focusLostHelper(); + void updateAllowingLanguageInput(); + BOOL hasPreeditString() const; + + // Overrides LLPreeditor + virtual void resetPreedit(); + virtual void updatePreedit(const LLWString &preedit_string, + const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position); + virtual void markAsPreedit(S32 position, S32 length); + virtual void getPreeditRange(S32 *position, S32 *length) const; + virtual void getSelectionRange(S32 *position, S32 *length) const; + virtual BOOL getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const; + virtual S32 getPreeditFontSize() const; + virtual LLWString getPreeditString() const { return getWText(); } + // + // Protected data + // + // Probably deserves serious thought to hiding as many of these + // as possible behind protected accessor methods. + // + + // Use these to determine if a click on an embedded item is a drag or not. + S32 mMouseDownX; + S32 mMouseDownY; + + LLWString mPreeditWString; + LLWString mPreeditOverwrittenWString; + std::vector mPreeditPositions; + std::vector mPreeditStandouts; protected: - LLUIColor mDefaultColor; + LLUIColor mDefaultColor; - bool mAutoIndent; - bool mParseOnTheFly; + bool mAutoIndent; + bool mParseOnTheFly; - void updateLinkSegments(); - void keepSelectionOnReturn(bool keep) { mKeepSelectionOnReturn = keep; } - class LLViewBorder* mBorder; + void updateLinkSegments(); + void keepSelectionOnReturn(bool keep) { mKeepSelectionOnReturn = keep; } + class LLViewBorder* mBorder; private: - // - // Methods - // - void pasteHelper(bool is_primary); - void cleanStringForPaste(LLWString & clean_string); + // + // Methods + // + void pasteHelper(bool is_primary); + void cleanStringForPaste(LLWString & clean_string); public: - template - void pasteTextWithLinebreaks(const STRINGTYPE& clean_string) - { - pasteTextWithLinebreaks(ll_convert(clean_string)); - } - template <> - void pasteTextWithLinebreaks(const LLWString & clean_string); + template + void pasteTextWithLinebreaks(const STRINGTYPE& clean_string) + { + pasteTextWithLinebreaks(ll_convert(clean_string)); + } + template <> + void pasteTextWithLinebreaks(const LLWString & clean_string); private: - void onKeyStroke(); + void onKeyStroke(); - // Concrete TextCmd sub-classes used by the LLTextEditor base class - class TextCmdInsert; - class TextCmdAddChar; - class TextCmdOverwriteChar; - class TextCmdRemove; + // Concrete TextCmd sub-classes used by the LLTextEditor base class + class TextCmdInsert; + class TextCmdAddChar; + class TextCmdOverwriteChar; + class TextCmdRemove; - BOOL mBaseDocIsPristine; - TextCmd* mPristineCmd; + BOOL mBaseDocIsPristine; + TextCmd* mPristineCmd; - TextCmd* mLastCmd; + TextCmd* mLastCmd; - typedef std::deque undo_stack_t; - undo_stack_t mUndoStack; + typedef std::deque undo_stack_t; + undo_stack_t mUndoStack; - BOOL mTabsToNextField; // if true, tab moves focus to next field, else inserts spaces - BOOL mCommitOnFocusLost; - BOOL mTakesFocus; + BOOL mTabsToNextField; // if true, tab moves focus to next field, else inserts spaces + BOOL mCommitOnFocusLost; + BOOL mTakesFocus; - BOOL mAllowEmbeddedItems; - bool mShowContextMenu; - bool mShowEmojiHelper; - bool mEnableTooltipPaste; - bool mPassDelete; - bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter + BOOL mAllowEmbeddedItems; + bool mShowContextMenu; + bool mShowEmojiHelper; + bool mEnableTooltipPaste; + bool mPassDelete; + bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter - LLUUID mSourceID; + LLUUID mSourceID; - LLCoordGL mLastIMEPosition; // Last position of the IME editor + LLCoordGL mLastIMEPosition; // Last position of the IME editor - keystroke_signal_t mKeystrokeSignal; - LLTextValidate::validate_func_t mPrevalidateFunc; + keystroke_signal_t mKeystrokeSignal; + LLTextValidate::validate_func_t mPrevalidateFunc; - LLHandle mContextMenuHandle; + LLHandle mContextMenuHandle; }; // end class LLTextEditor // Build time optimization, generate once in .cpp file #ifndef LLTEXTEDITOR_CPP extern template class LLTextEditor* LLView::getChild( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; #endif #endif // LL_TEXTEDITOR_H -- cgit v1.2.3 From 9f540f10e687bb3889de191afbae3b52cc21f415 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Wed, 15 May 2024 18:50:51 +0300 Subject: Add trusted flag to UI callbacks, so not everything is accessible from the script --- indra/llui/llmenugl.h | 9 +++++---- indra/llui/lluictrl.cpp | 8 ++++++++ indra/llui/lluictrl.h | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index fdbfb38474..1dcf79d02c 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -950,16 +950,17 @@ 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) + static void addCommit(view_listener_t* listener, const std::string& name, bool allow_untrusted = false) { - LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); + LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(name, + LLUICtrl::LLCommitCallbackInfo(boost::bind(&view_listener_t::handleEvent, listener, _2), allow_untrusted)); } - static void addMenu(view_listener_t* listener, const std::string& name) + static void addMenu(view_listener_t* listener, const std::string& name, bool allow_untrusted = true) { // For now, add to both click and enable registries addEnable(listener, name); - addCommit(listener, name); + addCommit(listener, name, allow_untrusted); } static void cleanup() diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 7eb9ae69fb..ee41d20d7a 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -284,6 +284,7 @@ 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)); + LLUICtrl::LLCommitCallbackInfo* info = LLUICtrl::SharedCommitCallbackRegistry::getValue(function_name); if (func) { if (cb.parameter.isProvided()) @@ -291,6 +292,13 @@ LLUICtrl::commit_signal_t::slot_type LLUICtrl::initCommitCallback(const CommitCa else return commit_signal_t::slot_type(*func); } + else if (info && info->callback_func) + { + if (cb.parameter.isProvided()) + return boost::bind((info->callback_func), _1, cb.parameter); + else + return commit_signal_t::slot_type(info->callback_func); + } else if (!function_name.empty()) { LL_WARNS() << "No callback found for: '" << function_name << "' in control: " << getName() << LL_ENDL; diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index cffb9933d4..5039d3e22c 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -282,6 +282,22 @@ public: { LLSINGLETON_EMPTY_CTOR(EnableCallbackRegistry); }; + + struct LLCommitCallbackInfo + { + LLCommitCallbackInfo(commit_callback_t func = NULL, bool allow_untrusted = false) + : callback_func(func), mAllowUntrusted(allow_untrusted) + {} + + public: + bool mAllowUntrusted; + commit_callback_t callback_func; + }; + + class SharedCommitCallbackRegistry : public CallbackRegistry + { + LLSINGLETON_EMPTY_CTOR(SharedCommitCallbackRegistry); + }; protected: -- cgit v1.2.3 From 7137647e90d8c11197513f542f04fb39b483d663 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 15 May 2024 12:19:54 -0400 Subject: Manual whitespace cleanup (fix_whitespace.py). --- indra/llui/llflashtimer.cpp | 72 +- indra/llui/llflashtimer.h | 58 +- indra/llui/llmenugl.h | 1248 ++++++------ indra/llui/lltexteditor.cpp | 4634 +++++++++++++++++++++---------------------- indra/llui/lltexteditor.h | 456 ++--- 5 files changed, 3234 insertions(+), 3234 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llflashtimer.cpp b/indra/llui/llflashtimer.cpp index 4a5b220008..2711e8088d 100644 --- a/indra/llui/llflashtimer.cpp +++ b/indra/llui/llflashtimer.cpp @@ -28,71 +28,71 @@ #include "llui.h" LLFlashTimer::LLFlashTimer(callback_t cb, S32 count, F32 period) -: LLEventTimer(period), - mCallback(cb), - mCurrentTickCount(0), - mIsFlashingInProgress(false), - mIsCurrentlyHighlighted(false), - mUnset(false) +: LLEventTimer(period), + mCallback(cb), + mCurrentTickCount(0), + mIsFlashingInProgress(false), + mIsCurrentlyHighlighted(false), + mUnset(false) { - 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 - // in runtime. So, both settings are made as required restart. - mFlashCount = 2 * ((count > 0) ? count : LLUI::getInstance()->mSettingGroups["config"]->getS32("FlashCount")); - if (mPeriod <= 0) - { - mPeriod = LLUI::getInstance()->mSettingGroups["config"]->getF32("FlashPeriod"); - } + // 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 + // in runtime. So, both settings are made as required restart. + mFlashCount = 2 * ((count > 0) ? count : LLUI::getInstance()->mSettingGroups["config"]->getS32("FlashCount")); + if (mPeriod <= 0) + { + mPeriod = LLUI::getInstance()->mSettingGroups["config"]->getF32("FlashPeriod"); + } } void LLFlashTimer::unset() { - mUnset = true; - mCallback = NULL; + mUnset = true; + mCallback = NULL; } bool LLFlashTimer::tick() { - mIsCurrentlyHighlighted = !mIsCurrentlyHighlighted; + mIsCurrentlyHighlighted = !mIsCurrentlyHighlighted; - if (mCallback) - { - mCallback(mIsCurrentlyHighlighted); - } + if (mCallback) + { + mCallback(mIsCurrentlyHighlighted); + } - if (++mCurrentTickCount >= mFlashCount) - { - stopFlashing(); - } + if (++mCurrentTickCount >= mFlashCount) + { + stopFlashing(); + } - return mUnset; + return mUnset; } void LLFlashTimer::startFlashing() { - mIsFlashingInProgress = true; - mIsCurrentlyHighlighted = true; - start(); + mIsFlashingInProgress = true; + mIsCurrentlyHighlighted = true; + start(); } void LLFlashTimer::stopFlashing() { - stop(); - mIsFlashingInProgress = false; - mIsCurrentlyHighlighted = false; - mCurrentTickCount = 0; + stop(); + mIsFlashingInProgress = false; + mIsCurrentlyHighlighted = false; + mCurrentTickCount = 0; } bool LLFlashTimer::isFlashingInProgress() { - return mIsFlashingInProgress; + return mIsFlashingInProgress; } bool LLFlashTimer::isCurrentlyHighlighted() { - return mIsCurrentlyHighlighted; + return mIsCurrentlyHighlighted; } diff --git a/indra/llui/llflashtimer.h b/indra/llui/llflashtimer.h index 4a2088734d..988b577ed2 100644 --- a/indra/llui/llflashtimer.h +++ b/indra/llui/llflashtimer.h @@ -34,41 +34,41 @@ class LLFlashTimer : public LLEventTimer { public: - typedef boost::function callback_t; + typedef boost::function callback_t; - /** - * Constructor. - * - * @param count - how many times callback should be called (twice to not change original state) - * @param period - how frequently callback should be called - * @param cb - callback to be called each tick - */ - LLFlashTimer(callback_t cb = NULL, S32 count = 0, F32 period = 0.0); - ~LLFlashTimer() {}; + /** + * Constructor. + * + * @param count - how many times callback should be called (twice to not change original state) + * @param period - how frequently callback should be called + * @param cb - callback to be called each tick + */ + LLFlashTimer(callback_t cb = NULL, S32 count = 0, F32 period = 0.0); + ~LLFlashTimer() {}; - bool tick() override; + bool tick() override; - void startFlashing(); - void stopFlashing(); + void startFlashing(); + void stopFlashing(); - bool isFlashingInProgress(); - bool isCurrentlyHighlighted(); - /* - * Use this instead of deleting this object. - * The next call to tick() will return true and that will destroy this object. - */ - void unset(); + bool isFlashingInProgress(); + bool isCurrentlyHighlighted(); + /* + * Use this instead of deleting this object. + * The next call to tick() will return true and that will destroy this object. + */ + void unset(); private: - callback_t mCallback; - /** - * How many times parent will blink. - */ - S32 mFlashCount; - S32 mCurrentTickCount; - bool mIsCurrentlyHighlighted; - bool mIsFlashingInProgress; - bool mUnset; + callback_t mCallback; + /** + * How many times parent will blink. + */ + S32 mFlashCount; + S32 mCurrentTickCount; + bool mIsCurrentlyHighlighted; + bool mIsFlashingInProgress; + bool mUnset; }; #endif /* LL_FLASHTIMER_H */ diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index fdbfb38474..e8d6043e54 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -1,25 +1,25 @@ -/** +/** * @file llmenugl.h * @brief Declaration of the opengl based menu system. * * $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$ */ @@ -45,183 +45,183 @@ extern S32 MENU_BAR_WIDTH; class LLMenuKeyboardBinding { public: - KEY mKey; - MASK mMask; + KEY mKey; + MASK mMask; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLMenuItemGL // -// The LLMenuItemGL represents a single menu item in a menu. +// The LLMenuItemGL represents a single menu item in a menu. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLMenuItemGL: public LLUICtrl, public ll::ui::SearchableControl { public: - struct Params : public LLInitParam::Block - { - Optional shortcut; - Optional jump_key; - Optional use_mac_ctrl, - allow_key_repeat; - - Ignored rect, - left, - top, - right, - bottom, - width, - height, - bottom_delta, - left_delta; - - Optional enabled_color, - disabled_color, - highlight_bg_color, - highlight_fg_color; - - - Params(); - }; + struct Params : public LLInitParam::Block + { + Optional shortcut; + Optional jump_key; + Optional use_mac_ctrl, + allow_key_repeat; + + Ignored rect, + left, + top, + right, + bottom, + width, + height, + bottom_delta, + left_delta; + + Optional enabled_color, + disabled_color, + highlight_bg_color, + highlight_fg_color; + + + Params(); + }; protected: - LLMenuItemGL(const Params&); - friend class LLUICtrlFactory; + LLMenuItemGL(const Params&); + friend class LLUICtrlFactory; public: - // LLView overrides - /*virtual*/ void onVisibilityChange(BOOL new_visibility); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); - - // LLUICtrl overrides - /*virtual*/ void setValue(const LLSD& value); - /*virtual*/ LLSD getValue() const; - - virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - - LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); } - - void setJumpKey(KEY key); - KEY getJumpKey() const { return mJumpKey; } - - // set the font used by this item. - void setFont(const LLFontGL* font) { mFont = font; } - const LLFontGL* getFont() const { return mFont; } - - // returns the height in pixels for the current font. - virtual U32 getNominalHeight( void ) const; - - // Marks item as not needing space for check marks or accelerator keys - virtual void setBriefItem(BOOL brief); - virtual BOOL isBriefItem() const; - - virtual BOOL addToAcceleratorList(std::list *listp); - void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; } - BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; } - - // change the label - void setLabel( const LLStringExplicit& label ) { mLabel = label; } - std::string getLabel( void ) const { return mLabel.getString(); } - virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); - - // Get the parent menu for this item - virtual class LLMenuGL* getMenu() const; - - // returns the normal width of this control in pixels - this is - // used for calculating the widest item, as well as for horizontal - // arrangement. - virtual U32 getNominalWidth( void ) const; - - // buildDrawLabel() - constructs the string used during the draw() - // function. This reduces the overall string manipulation, but can - // lead to visual errors if the state of the object changes - // without the knowledge of the menu item. For example, if a - // boolean being watched is changed outside of the menu item's - // onCommit() function, the draw buffer will not be updated and will - // reflect the wrong value. If this ever becomes an issue, there - // are ways to fix this. - // Returns the enabled state of the item. - virtual void buildDrawLabel( void ); - - // for branching menu items, bring sub menus up to root level of menu hierarchy - virtual void updateBranchParent( LLView* parentp ){}; - - virtual void onCommit( void ); - - virtual void setHighlight( BOOL highlight ); - virtual BOOL getHighlight() const { return mHighlight; } - - // determine if this represents an active sub-menu - virtual BOOL isActive( void ) const { return FALSE; } - - // determine if this represents an open sub-menu - virtual BOOL isOpen( void ) const { return FALSE; } - - virtual void setEnabledSubMenus(BOOL enable){}; - - // LLView Functionality - virtual BOOL handleKeyHere( KEY key, MASK mask ); - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); - virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); - - virtual void onMouseEnter(S32 x, S32 y, MASK mask); - virtual void onMouseLeave(S32 x, S32 y, MASK mask); - - virtual void draw( void ); - - BOOL getHover() const { return mGotHover; } - - void setDrawTextDisabled(BOOL disabled) { mDrawTextDisabled = disabled; } - BOOL getDrawTextDisabled() const { return mDrawTextDisabled; } + // LLView overrides + /*virtual*/ void onVisibilityChange(BOOL new_visibility); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); + + // LLUICtrl overrides + /*virtual*/ void setValue(const LLSD& value); + /*virtual*/ LLSD getValue() const; + + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + + LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); } + + void setJumpKey(KEY key); + KEY getJumpKey() const { return mJumpKey; } + + // set the font used by this item. + void setFont(const LLFontGL* font) { mFont = font; } + const LLFontGL* getFont() const { return mFont; } + + // returns the height in pixels for the current font. + virtual U32 getNominalHeight( void ) const; + + // Marks item as not needing space for check marks or accelerator keys + virtual void setBriefItem(BOOL brief); + virtual BOOL isBriefItem() const; + + virtual BOOL addToAcceleratorList(std::list *listp); + void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; } + BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; } + + // change the label + void setLabel( const LLStringExplicit& label ) { mLabel = label; } + std::string getLabel( void ) const { return mLabel.getString(); } + virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); + + // Get the parent menu for this item + virtual class LLMenuGL* getMenu() const; + + // returns the normal width of this control in pixels - this is + // used for calculating the widest item, as well as for horizontal + // arrangement. + virtual U32 getNominalWidth( void ) const; + + // buildDrawLabel() - constructs the string used during the draw() + // function. This reduces the overall string manipulation, but can + // lead to visual errors if the state of the object changes + // without the knowledge of the menu item. For example, if a + // boolean being watched is changed outside of the menu item's + // onCommit() function, the draw buffer will not be updated and will + // reflect the wrong value. If this ever becomes an issue, there + // are ways to fix this. + // Returns the enabled state of the item. + virtual void buildDrawLabel( void ); + + // for branching menu items, bring sub menus up to root level of menu hierarchy + virtual void updateBranchParent( LLView* parentp ){}; + + virtual void onCommit( void ); + + virtual void setHighlight( BOOL highlight ); + virtual BOOL getHighlight() const { return mHighlight; } + + // determine if this represents an active sub-menu + virtual BOOL isActive( void ) const { return FALSE; } + + // determine if this represents an open sub-menu + virtual BOOL isOpen( void ) const { return FALSE; } + + virtual void setEnabledSubMenus(BOOL enable){}; + + // LLView Functionality + virtual BOOL handleKeyHere( KEY key, MASK mask ); + virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); + virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + + virtual void onMouseEnter(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); + + virtual void draw( void ); + + BOOL getHover() const { return mGotHover; } + + void setDrawTextDisabled(BOOL disabled) { mDrawTextDisabled = disabled; } + BOOL getDrawTextDisabled() const { return mDrawTextDisabled; } protected: - void setHover(BOOL hover) { mGotHover = hover; } + void setHover(BOOL hover) { mGotHover = hover; } - // This function appends the character string representation of - // the current accelerator key and mask to the provided string. - void appendAcceleratorString( std::string& st ) const; + // This function appends the character string representation of + // the current accelerator key and mask to the provided string. + void appendAcceleratorString( std::string& st ) const; - virtual std::string _getSearchText() const - { - return mLabel.getString(); - } + virtual std::string _getSearchText() const + { + return mLabel.getString(); + } protected: - KEY mAcceleratorKey; - MASK mAcceleratorMask; - // mLabel contains the actual label specified by the user. - LLUIString mLabel; - - // The draw labels contain some of the labels that we draw during - // the draw() routine. This optimizes away some of the string - // manipulation. - LLUIString mDrawBoolLabel; - LLUIString mDrawAccelLabel; - LLUIString mDrawBranchLabel; - - LLUIColor mEnabledColor; - LLUIColor mDisabledColor; - LLUIColor mHighlightBackground; - LLUIColor mHighlightForeground; - - BOOL mHighlight; + KEY mAcceleratorKey; + MASK mAcceleratorMask; + // mLabel contains the actual label specified by the user. + LLUIString mLabel; + + // The draw labels contain some of the labels that we draw during + // the draw() routine. This optimizes away some of the string + // manipulation. + LLUIString mDrawBoolLabel; + LLUIString mDrawAccelLabel; + LLUIString mDrawBranchLabel; + + LLUIColor mEnabledColor; + LLUIColor mDisabledColor; + LLUIColor mHighlightBackground; + LLUIColor mHighlightForeground; + + BOOL mHighlight; private: - // Keyboard and mouse variables - BOOL mAllowKeyRepeat; - BOOL mGotHover; + // Keyboard and mouse variables + BOOL mAllowKeyRepeat; + BOOL mGotHover; - // If true, suppress normal space for check marks on the left and accelerator - // keys on the right. - BOOL mBriefItem; + // If true, suppress normal space for check marks on the left and accelerator + // keys on the right. + BOOL mBriefItem; - // Font for this item - const LLFontGL* mFont; - BOOL mDrawTextDisabled; + // Font for this item + const LLFontGL* mFont; + BOOL mDrawTextDisabled; - KEY mJumpKey; + KEY mJumpKey; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -232,22 +232,22 @@ private: class LLMenuItemSeparatorGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block - { + struct Params : public LLInitParam::Block + { Optional on_visible; Params(); - }; + }; LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p = LLMenuItemSeparatorGL::Params()); - /*virtual*/ void draw( void ); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ void draw( void ); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); virtual void buildDrawLabel(); - /*virtual*/ U32 getNominalHeight( void ) const; + /*virtual*/ U32 getNominalHeight( void ) const; private: enable_signal_t mVisibleSignal; @@ -263,49 +263,49 @@ private: class LLMenuItemCallGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block - { - Optional on_enable; - Optional on_click; - Optional on_visible; - Params() - : on_enable("on_enable"), - on_click("on_click"), - on_visible("on_visible") - {} - }; + struct Params : public LLInitParam::Block + { + Optional on_enable; + Optional on_click; + Optional on_visible; + Params() + : on_enable("on_enable"), + on_click("on_click"), + on_visible("on_visible") + {} + }; protected: - LLMenuItemCallGL(const Params&); - friend class LLUICtrlFactory; - void updateEnabled( void ); - void updateVisible( void ); + LLMenuItemCallGL(const Params&); + friend class LLUICtrlFactory; + void updateEnabled( void ); + void updateVisible( void ); public: - void initFromParams(const Params& p); - - // called to rebuild the draw label - virtual void buildDrawLabel( void ); - - virtual void onCommit( void ); - - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - virtual BOOL handleKeyHere(KEY key, MASK mask); - - //virtual void draw(); - - boost::signals2::connection setClickCallback( const commit_signal_t::slot_type& cb ) - { - return setCommitCallback(cb); - } - - boost::signals2::connection setEnableCallback( const enable_signal_t::slot_type& cb ) - { - return mEnableSignal.connect(cb); - } - + void initFromParams(const Params& p); + + // called to rebuild the draw label + virtual void buildDrawLabel( void ); + + virtual void onCommit( void ); + + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + virtual BOOL handleKeyHere(KEY key, MASK mask); + + //virtual void draw(); + + boost::signals2::connection setClickCallback( const commit_signal_t::slot_type& cb ) + { + return setCommitCallback(cb); + } + + boost::signals2::connection setEnableCallback( const enable_signal_t::slot_type& cb ) + { + return mEnableSignal.connect(cb); + } + private: - enable_signal_t mEnableSignal; - enable_signal_t mVisibleSignal; + enable_signal_t mEnableSignal; + enable_signal_t mVisibleSignal; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -318,40 +318,40 @@ private: // EFFICIENT because it may need to be checked a lot. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLMenuItemCheckGL -: public LLMenuItemCallGL +class LLMenuItemCheckGL +: public LLMenuItemCallGL { public: - struct Params : public LLInitParam::Block - { - Optional on_check; - Params() - : on_check("on_check") - {} - }; + struct Params : public LLInitParam::Block + { + Optional on_check; + Params() + : on_check("on_check") + {} + }; protected: - LLMenuItemCheckGL(const Params&); - friend class LLUICtrlFactory; + LLMenuItemCheckGL(const Params&); + friend class LLUICtrlFactory; public: - - void initFromParams(const Params& p); - - virtual void onCommit( void ); - - virtual void setValue(const LLSD& value); - virtual LLSD getValue() const; - - // called to rebuild the draw label - virtual void buildDrawLabel( void ); - - boost::signals2::connection setCheckCallback( const enable_signal_t::slot_type& cb ) - { - return mCheckSignal.connect(cb); - } - + + void initFromParams(const Params& p); + + virtual void onCommit( void ); + + virtual void setValue(const LLSD& value); + virtual LLSD getValue() const; + + // called to rebuild the draw label + virtual void buildDrawLabel( void ); + + boost::signals2::connection setCheckCallback( const enable_signal_t::slot_type& cb ) + { + return mCheckSignal.connect(cb); + } + private: - enable_signal_t mCheckSignal; + enable_signal_t mCheckSignal; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -368,199 +368,199 @@ private: // child widget registry struct MenuRegistry : public LLChildRegistry { - LLSINGLETON_EMPTY_CTOR(MenuRegistry); + LLSINGLETON_EMPTY_CTOR(MenuRegistry); }; -class LLMenuGL -: public LLUICtrl +class LLMenuGL +: public LLUICtrl { public: - struct Params : public LLInitParam::Block - { - Optional jump_key; - Optional horizontal_layout, - can_tear_off, - drop_shadow, - bg_visible, - create_jump_keys, - keep_fixed_size, - scrollable; - Optional max_scrollable_items; - Optional preferred_width; - Optional bg_color; - Optional shortcut_pad; - - Params() - : jump_key("jump_key", KEY_NONE), - horizontal_layout("horizontal_layout"), - can_tear_off("tear_off", false), - drop_shadow("drop_shadow", true), - bg_visible("bg_visible", true), - create_jump_keys("create_jump_keys", false), - keep_fixed_size("keep_fixed_size", false), - bg_color("bg_color", LLUIColorTable::instance().getColor( "MenuDefaultBgColor" )), - scrollable("scrollable", false), - max_scrollable_items("max_scrollable_items", U32_MAX), - preferred_width("preferred_width", U32_MAX), - shortcut_pad("shortcut_pad") - { - addSynonym(bg_visible, "opaque"); - addSynonym(bg_color, "color"); - addSynonym(can_tear_off, "can_tear_off"); - } - }; - - // my valid children are contained in MenuRegistry - typedef MenuRegistry child_registry_t; - - void initFromParams(const Params&); - - // textual artwork which menugl-imitators may want to match - static const std::string BOOLEAN_TRUE_PREFIX; - static const std::string BRANCH_SUFFIX; - static const std::string ARROW_UP; - static const std::string ARROW_DOWN; - - // for scrollable menus - typedef enum e_scrolling_direction - { - SD_UP = 0, - SD_DOWN = 1, - SD_BEGIN = 2, - SD_END = 3 - } EScrollingDirection; + struct Params : public LLInitParam::Block + { + Optional jump_key; + Optional horizontal_layout, + can_tear_off, + drop_shadow, + bg_visible, + create_jump_keys, + keep_fixed_size, + scrollable; + Optional max_scrollable_items; + Optional preferred_width; + Optional bg_color; + Optional shortcut_pad; + + Params() + : jump_key("jump_key", KEY_NONE), + horizontal_layout("horizontal_layout"), + can_tear_off("tear_off", false), + drop_shadow("drop_shadow", true), + bg_visible("bg_visible", true), + create_jump_keys("create_jump_keys", false), + keep_fixed_size("keep_fixed_size", false), + bg_color("bg_color", LLUIColorTable::instance().getColor( "MenuDefaultBgColor" )), + scrollable("scrollable", false), + max_scrollable_items("max_scrollable_items", U32_MAX), + preferred_width("preferred_width", U32_MAX), + shortcut_pad("shortcut_pad") + { + addSynonym(bg_visible, "opaque"); + addSynonym(bg_color, "color"); + addSynonym(can_tear_off, "can_tear_off"); + } + }; + + // my valid children are contained in MenuRegistry + typedef MenuRegistry child_registry_t; + + void initFromParams(const Params&); + + // textual artwork which menugl-imitators may want to match + static const std::string BOOLEAN_TRUE_PREFIX; + static const std::string BRANCH_SUFFIX; + static const std::string ARROW_UP; + static const std::string ARROW_DOWN; + + // for scrollable menus + typedef enum e_scrolling_direction + { + SD_UP = 0, + SD_DOWN = 1, + SD_BEGIN = 2, + SD_END = 3 + } EScrollingDirection; protected: - LLMenuGL(const LLMenuGL::Params& p); - friend class LLUICtrlFactory; - // let branching menu items use my protected traversal methods - friend class LLMenuItemBranchGL; + LLMenuGL(const LLMenuGL::Params& p); + friend class LLUICtrlFactory; + // let branching menu items use my protected traversal methods + friend class LLMenuItemBranchGL; public: - virtual ~LLMenuGL( void ); - - void parseChildXML(LLXMLNodePtr child, LLView* parent); - - // LLView Functionality - /*virtual*/ BOOL handleUnicodeCharHere( llwchar uni_char ); - /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); - /*virtual*/ BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); - /*virtual*/ void draw( void ); - /*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha); - /*virtual*/ void setVisible(BOOL visible); - /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); + virtual ~LLMenuGL( void ); + + void parseChildXML(LLXMLNodePtr child, LLView* parent); + + // LLView Functionality + /*virtual*/ BOOL handleUnicodeCharHere( llwchar uni_char ); + /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + /*virtual*/ void draw( void ); + /*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha); + /*virtual*/ void setVisible(BOOL visible); + /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); /*virtual*/ void deleteAllChildren(); - /*virtual*/ void removeChild( LLView* ctrl); - /*virtual*/ BOOL postBuild(); - - virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - - LLMenuGL* findChildMenuByName(const std::string& name, BOOL recurse) const; - - BOOL clearHoverItem(); - - // return the name label - const std::string& getLabel( void ) const { return mLabel.getString(); } - void setLabel(const LLStringExplicit& label) { mLabel = label; } - - // background colors - void setBackgroundColor( const LLUIColor& color ) { mBackgroundColor = color; } - const LLUIColor& getBackgroundColor() const { return mBackgroundColor; } - void setBackgroundVisible( BOOL b ) { mBgVisible = b; } - void setCanTearOff(BOOL tear_off); - - // add a separator to this menu - virtual BOOL addSeparator(); - - // for branching menu items, bring sub menus up to root level of menu hierarchy - virtual void updateParent( LLView* parentp ); - - // setItemEnabled() - pass the name and the enable flag for a - // menu item. TRUE will make sure it's enabled, FALSE will disable - // it. - void setItemEnabled( const std::string& name, BOOL enable ); - - // propagate message to submenus - void setEnabledSubMenus(BOOL enable); - - void setItemVisible( const std::string& name, BOOL visible); + /*virtual*/ void removeChild( LLView* ctrl); + /*virtual*/ BOOL postBuild(); + + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + + LLMenuGL* findChildMenuByName(const std::string& name, BOOL recurse) const; + + BOOL clearHoverItem(); + + // return the name label + const std::string& getLabel( void ) const { return mLabel.getString(); } + void setLabel(const LLStringExplicit& label) { mLabel = label; } + + // background colors + void setBackgroundColor( const LLUIColor& color ) { mBackgroundColor = color; } + const LLUIColor& getBackgroundColor() const { return mBackgroundColor; } + void setBackgroundVisible( BOOL b ) { mBgVisible = b; } + void setCanTearOff(BOOL tear_off); + + // add a separator to this menu + virtual BOOL addSeparator(); + + // for branching menu items, bring sub menus up to root level of menu hierarchy + virtual void updateParent( LLView* parentp ); + + // setItemEnabled() - pass the name and the enable flag for a + // menu item. TRUE will make sure it's enabled, FALSE will disable + // it. + void setItemEnabled( const std::string& name, BOOL enable ); + + // propagate message to submenus + void setEnabledSubMenus(BOOL enable); + + void setItemVisible( const std::string& name, BOOL visible); void setItemLabel(const std::string &name, const std::string &label); - - // sets the left,bottom corner of menu, useful for popups - void setLeftAndBottom(S32 left, S32 bottom); - virtual BOOL handleJumpKey(KEY key); + // sets the left,bottom corner of menu, useful for popups + void setLeftAndBottom(S32 left, S32 bottom); - virtual BOOL jumpKeysActive(); + virtual BOOL handleJumpKey(KEY key); - virtual BOOL isOpen(); + virtual BOOL jumpKeysActive(); - void needsArrange() { mNeedsArrange = TRUE; } - // Shape this menu to fit the current state of the children, and - // adjust the child rects to fit. This is called automatically - // when you add items. *FIX: We may need to deal with visibility - // arrangement. - virtual void arrange( void ); - void arrangeAndClear( void ); + virtual BOOL isOpen(); - // remove all items on the menu - void empty( void ); + void needsArrange() { mNeedsArrange = TRUE; } + // Shape this menu to fit the current state of the children, and + // adjust the child rects to fit. This is called automatically + // when you add items. *FIX: We may need to deal with visibility + // arrangement. + virtual void arrange( void ); + void arrangeAndClear( void ); - // erase group of items from menu - void erase( S32 begin, S32 end, bool arrange = true ); + // remove all items on the menu + void empty( void ); - // add new item at position - void insert( S32 begin, LLView * ctrl, bool arrange = true ); + // erase group of items from menu + void erase( S32 begin, S32 end, bool arrange = true ); - void setItemLastSelected(LLMenuItemGL* item); // must be in menu - U32 getItemCount(); // number of menu items - LLMenuItemGL* getItem(S32 number); // 0 = first item + // add new item at position + void insert( S32 begin, LLView * ctrl, bool arrange = true ); + + void setItemLastSelected(LLMenuItemGL* item); // must be in menu + U32 getItemCount(); // number of menu items + LLMenuItemGL* getItem(S32 number); // 0 = first item LLMenuItemGL* getItem(std::string name); - LLMenuItemGL* getHighlightedItem(); + LLMenuItemGL* getHighlightedItem(); + + LLMenuItemGL* highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); + LLMenuItemGL* highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); - LLMenuItemGL* highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); - LLMenuItemGL* highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); + void buildDrawLabels(); + void createJumpKeys(); - void buildDrawLabels(); - void createJumpKeys(); + // Show popup at a specific location, in the spawn_view's coordinate frame + static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x = 0, S32 mouse_y = 0); - // Show popup at a specific location, in the spawn_view's coordinate frame - static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x = 0, S32 mouse_y = 0); + // Whether to drop shadow menu bar + void setDropShadowed( const BOOL shadowed ); - // Whether to drop shadow menu bar - void setDropShadowed( const BOOL shadowed ); + void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item->getHandle(); } + LLMenuItemGL* getParentMenuItem() const { return dynamic_cast(mParentMenuItem.get()); } - void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item->getHandle(); } - LLMenuItemGL* getParentMenuItem() const { return dynamic_cast(mParentMenuItem.get()); } + void setTornOff(BOOL torn_off); + BOOL getTornOff() { return mTornOff; } - void setTornOff(BOOL torn_off); - BOOL getTornOff() { return mTornOff; } + BOOL getCanTearOff() { return mTearOffItem != NULL; } - BOOL getCanTearOff() { return mTearOffItem != NULL; } + KEY getJumpKey() const { return mJumpKey; } + void setJumpKey(KEY key) { mJumpKey = key; } - KEY getJumpKey() const { return mJumpKey; } - void setJumpKey(KEY key) { mJumpKey = key; } + static void setKeyboardMode(BOOL mode) { sKeyboardMode = mode; } + static BOOL getKeyboardMode() { return sKeyboardMode; } - static void setKeyboardMode(BOOL mode) { sKeyboardMode = mode; } - static BOOL getKeyboardMode() { return sKeyboardMode; } + S32 getShortcutPad() { return mShortcutPad; } - S32 getShortcutPad() { return mShortcutPad; } + bool scrollItems(EScrollingDirection direction); + BOOL isScrollable() const { return mScrollable; } - bool scrollItems(EScrollingDirection direction); - BOOL isScrollable() const { return mScrollable; } + static class LLMenuHolderGL* sMenuContainer; - static class LLMenuHolderGL* sMenuContainer; - - void resetScrollPositionOnShow(bool reset_scroll_pos) { mResetScrollPositionOnShow = reset_scroll_pos; } - bool isScrollPositionOnShowReset() { return mResetScrollPositionOnShow; } + void resetScrollPositionOnShow(bool reset_scroll_pos) { mResetScrollPositionOnShow = reset_scroll_pos; } + bool isScrollPositionOnShowReset() { return mResetScrollPositionOnShow; } - void setAlwaysShowMenu(BOOL show) { mAlwaysShowMenu = show; } - BOOL getAlwaysShowMenu() { return mAlwaysShowMenu; } + void setAlwaysShowMenu(BOOL show) { mAlwaysShowMenu = show; } + BOOL getAlwaysShowMenu() { return mAlwaysShowMenu; } - // add a context menu branch - BOOL appendContextSubMenu(LLMenuGL *menu); + // add a context menu branch + BOOL appendContextSubMenu(LLMenuGL *menu); // Add the menu item to this menu. virtual BOOL append( LLMenuItemGL* item ); @@ -571,31 +571,31 @@ public: const LLFontGL *getFont() const { return mFont; } protected: - void createSpilloverBranch(); - void cleanupSpilloverBranch(); - - // Used in LLContextMenu and in LLTogleableMenu - // to add an item of context menu branch - bool addContextChild(LLView* view, S32 tab_group); - - // TODO: create accessor methods for these? - typedef std::list< LLMenuItemGL* > item_list_t; - item_list_t mItems; - LLMenuItemGL*mFirstVisibleItem; - LLMenuItemGL *mArrowUpItem, *mArrowDownItem; - - typedef std::map navigation_key_map_t; - navigation_key_map_t mJumpKeys; - S32 mLastMouseX; - S32 mLastMouseY; - S32 mMouseVelX; - S32 mMouseVelY; - U32 mMaxScrollableItems; - U32 mPreferredWidth; - BOOL mHorizontalLayout; - BOOL mScrollable; - BOOL mKeepFixedSize; - BOOL mNeedsArrange; + void createSpilloverBranch(); + void cleanupSpilloverBranch(); + + // Used in LLContextMenu and in LLTogleableMenu + // to add an item of context menu branch + bool addContextChild(LLView* view, S32 tab_group); + + // TODO: create accessor methods for these? + typedef std::list< LLMenuItemGL* > item_list_t; + item_list_t mItems; + LLMenuItemGL*mFirstVisibleItem; + LLMenuItemGL *mArrowUpItem, *mArrowDownItem; + + typedef std::map navigation_key_map_t; + navigation_key_map_t mJumpKeys; + S32 mLastMouseX; + S32 mLastMouseY; + S32 mMouseVelX; + S32 mMouseVelY; + U32 mMaxScrollableItems; + U32 mPreferredWidth; + BOOL mHorizontalLayout; + BOOL mScrollable; + BOOL mKeepFixedSize; + BOOL mNeedsArrange; // Font for top menu items only const LLFontGL* mFont; @@ -603,27 +603,27 @@ protected: private: - static LLColor4 sDefaultBackgroundColor; - static BOOL sKeyboardMode; - - BOOL mAlwaysShowMenu; - - LLUIColor mBackgroundColor; - BOOL mBgVisible; - LLHandle mParentMenuItem; - LLUIString mLabel; - BOOL mDropShadowed; // Whether to drop shadow - bool mHasSelection; - LLFrameTimer mFadeTimer; - LLTimer mScrollItemsTimer; - BOOL mTornOff; - class LLMenuItemTearOffGL* mTearOffItem; - class LLMenuItemBranchGL* mSpilloverBranch; - LLMenuGL* mSpilloverMenu; - KEY mJumpKey; - BOOL mCreateJumpKeys; - S32 mShortcutPad; - bool mResetScrollPositionOnShow; + static LLColor4 sDefaultBackgroundColor; + static BOOL sKeyboardMode; + + BOOL mAlwaysShowMenu; + + LLUIColor mBackgroundColor; + BOOL mBgVisible; + LLHandle mParentMenuItem; + LLUIString mLabel; + BOOL mDropShadowed; // Whether to drop shadow + bool mHasSelection; + LLFrameTimer mFadeTimer; + LLTimer mScrollItemsTimer; + BOOL mTornOff; + class LLMenuItemTearOffGL* mTearOffItem; + class LLMenuItemBranchGL* mSpilloverBranch; + LLMenuGL* mSpilloverMenu; + KEY mJumpKey; + BOOL mCreateJumpKeys; + S32 mShortcutPad; + bool mResetScrollPositionOnShow; }; // end class LLMenuGL @@ -638,61 +638,61 @@ private: class LLMenuItemBranchGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block - { - Optional branch; - }; + struct Params : public LLInitParam::Block + { + Optional branch; + }; protected: - LLMenuItemBranchGL(const Params&); - friend class LLUICtrlFactory; + LLMenuItemBranchGL(const Params&); + friend class LLUICtrlFactory; public: - virtual ~LLMenuItemBranchGL(); - - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual ~LLMenuItemBranchGL(); - virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - // check if we've used these accelerators already - virtual BOOL addToAcceleratorList(std::list *listp); + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - // called to rebuild the draw label - virtual void buildDrawLabel( void ); + // check if we've used these accelerators already + virtual BOOL addToAcceleratorList(std::list *listp); - virtual void onCommit( void ); + // called to rebuild the draw label + virtual void buildDrawLabel( void ); - virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + virtual void onCommit( void ); - // set the hover status (called by it's menu) and if the object is - // active. This is used for behavior transfer. - virtual void setHighlight( BOOL highlight ); + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); - virtual BOOL handleKeyHere(KEY key, MASK mask); + // set the hover status (called by it's menu) and if the object is + // active. This is used for behavior transfer. + virtual void setHighlight( BOOL highlight ); - virtual BOOL isActive() const; + virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual BOOL isOpen() const; + virtual BOOL isActive() const; - LLMenuGL* getBranch() const { return (LLMenuGL*)mBranchHandle.get(); } + virtual BOOL isOpen() const; - virtual void updateBranchParent( LLView* parentp ); + LLMenuGL* getBranch() const { return (LLMenuGL*)mBranchHandle.get(); } - // LLView Functionality - virtual void onVisibilityChange( BOOL curVisibilityIn ); + virtual void updateBranchParent( LLView* parentp ); - virtual void draw(); + // LLView Functionality + virtual void onVisibilityChange( BOOL curVisibilityIn ); - virtual void setEnabledSubMenus(BOOL enabled) { if (getBranch()) getBranch()->setEnabledSubMenus(enabled); } + virtual void draw(); - virtual void openMenu(); + virtual void setEnabledSubMenus(BOOL enabled) { if (getBranch()) getBranch()->setEnabledSubMenus(enabled); } - virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE) const; - virtual LLView* findChildView(const std::string& name, BOOL recurse = TRUE) const; + virtual void openMenu(); + + virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE) const; + virtual LLView* findChildView(const std::string& name, BOOL recurse = TRUE) const; private: - LLHandle mBranchHandle; + LLHandle mBranchHandle; }; // end class LLMenuItemBranchGL @@ -705,44 +705,44 @@ class LLContextMenu : public LLMenuGL { public: - struct Params : public LLInitParam::Block - { - Params() - { - changeDefault(visible, false); - } - }; + struct Params : public LLInitParam::Block + { + Params() + { + changeDefault(visible, false); + } + }; protected: - LLContextMenu(const Params& p); - friend class LLUICtrlFactory; + LLContextMenu(const Params& p); + friend class LLUICtrlFactory; public: - virtual ~LLContextMenu() {} + virtual ~LLContextMenu() {} + + // LLView Functionality + // can't set visibility directly, must call show or hide + virtual void setVisible (BOOL visible); - // LLView Functionality - // can't set visibility directly, must call show or hide - virtual void setVisible (BOOL visible); - - virtual void show (S32 x, S32 y, LLView* spawning_view = NULL); - virtual void hide (); + virtual void show (S32 x, S32 y, LLView* spawning_view = NULL); + virtual void hide (); - virtual BOOL handleHover ( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseUp ( S32 x, S32 y, MASK mask ); + virtual BOOL handleHover ( S32 x, S32 y, MASK mask ); + virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleRightMouseUp ( S32 x, S32 y, MASK mask ); - virtual bool addChild (LLView* view, S32 tab_group = 0); + virtual bool addChild (LLView* view, S32 tab_group = 0); - LLHandle getHandle() { return getDerivedHandle(); } + LLHandle getHandle() { return getDerivedHandle(); } - LLView* getSpawningView() const { return mSpawningViewHandle.get(); } - void setSpawningView(LLHandle spawning_view) { mSpawningViewHandle = spawning_view; } + LLView* getSpawningView() const { return mSpawningViewHandle.get(); } + void setSpawningView(LLHandle spawning_view) { mSpawningViewHandle = spawning_view; } protected: - BOOL mHoveredAnyItem; - LLMenuItemGL* mHoverItem; - LLRootHandle mHandle; - LLHandle mSpawningViewHandle; + BOOL mHoveredAnyItem; + LLMenuItemGL* mHoverItem; + LLRootHandle mHandle; + LLHandle mSpawningViewHandle; }; //----------------------------------------------------------------------------- @@ -752,28 +752,28 @@ protected: class LLContextMenuBranch : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block - { - Mandatory branch; - }; + struct Params : public LLInitParam::Block + { + Mandatory branch; + }; - LLContextMenuBranch(const Params&); + LLContextMenuBranch(const Params&); - virtual ~LLContextMenuBranch(); + virtual ~LLContextMenuBranch(); - // called to rebuild the draw label - virtual void buildDrawLabel( void ); + // called to rebuild the draw label + virtual void buildDrawLabel( void ); - // onCommit() - do the primary funcationality of the menu item. - virtual void onCommit( void ); + // onCommit() - do the primary funcationality of the menu item. + virtual void onCommit( void ); - LLContextMenu* getBranch() { return mBranch.get(); } - void setHighlight( BOOL highlight ); + LLContextMenu* getBranch() { return mBranch.get(); } + void setHighlight( BOOL highlight ); protected: - void showSubMenu(); + void showSubMenu(); - LLHandle mBranch; + LLHandle mBranch; }; @@ -786,43 +786,43 @@ protected: class LLMenuBarGL : public LLMenuGL { public: - struct Params : public LLInitParam::Block - {}; - LLMenuBarGL( const Params& p ); - virtual ~LLMenuBarGL(); + struct Params : public LLInitParam::Block + {}; + LLMenuBarGL( const Params& p ); + virtual ~LLMenuBarGL(); - /*virtual*/ BOOL handleAcceleratorKey(KEY key, MASK mask); - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); - /*virtual*/ BOOL handleJumpKey(KEY key); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleAcceleratorKey(KEY key, MASK mask); + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); + /*virtual*/ BOOL handleJumpKey(KEY key); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - /*virtual*/ void draw(); - /*virtual*/ BOOL jumpKeysActive(); + /*virtual*/ void draw(); + /*virtual*/ BOOL jumpKeysActive(); - // add a vertical separator to this menu - virtual BOOL addSeparator(); + // add a vertical separator to this menu + virtual BOOL addSeparator(); - // LLView Functionality - virtual BOOL handleHover( S32 x, S32 y, MASK mask ); + // LLView Functionality + virtual BOOL handleHover( S32 x, S32 y, MASK mask ); - // Returns x position of rightmost child, usually Help menu - S32 getRightmostMenuEdge(); + // Returns x position of rightmost child, usually Help menu + S32 getRightmostMenuEdge(); - void resetMenuTrigger() { mAltKeyTrigger = FALSE; } + void resetMenuTrigger() { mAltKeyTrigger = FALSE; } // add a menu - this will create a drop down menu. virtual BOOL appendMenu(LLMenuGL *menu); private: - // rearrange the child rects so they fit the shape of the menu - // bar. - virtual void arrange( void ); + // rearrange the child rects so they fit the shape of the menu + // bar. + virtual void arrange( void ); - void checkMenuTrigger(); + void checkMenuTrigger(); - std::list mAccelerators; - BOOL mAltKeyTrigger; + std::list mAccelerators; + BOOL mAltKeyTrigger; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -833,39 +833,39 @@ private: class LLMenuHolderGL : public LLPanel { public: - struct Params : public LLInitParam::Block - {}; - LLMenuHolderGL(const Params& p); - virtual ~LLMenuHolderGL() {} + struct Params : public LLInitParam::Block + {}; + LLMenuHolderGL(const Params& p); + virtual ~LLMenuHolderGL() {} - virtual BOOL hideMenus(); - void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - void setCanHide(BOOL can_hide) { mCanHide = can_hide; } + virtual BOOL hideMenus(); + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + void setCanHide(BOOL can_hide) { mCanHide = can_hide; } - // LLView functionality - virtual void draw(); - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + // LLView functionality + virtual void draw(); + virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - // Close context menus on right mouse up not handled by menus. - /*virtual*/ BOOL handleRightMouseUp( S32 x, S32 y, MASK mask ); + // Close context menus on right mouse up not handled by menus. + /*virtual*/ BOOL handleRightMouseUp( S32 x, S32 y, MASK mask ); - virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - virtual const LLRect getMenuRect() const { return getLocalRect(); } - LLView*const getVisibleMenu() const; - virtual BOOL hasVisibleMenu() const {return getVisibleMenu() != NULL;} + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual const LLRect getMenuRect() const { return getLocalRect(); } + LLView*const getVisibleMenu() const; + virtual BOOL hasVisibleMenu() const {return getVisibleMenu() != NULL;} - static void setActivatedItem(LLMenuItemGL* item); + static void setActivatedItem(LLMenuItemGL* item); - // Need to detect if mouse-up after context menu spawn has moved. - // If not, need to keep the menu up. - static LLCoordGL sContextMenuSpawnPos; + // Need to detect if mouse-up after context menu spawn has moved. + // If not, need to keep the menu up. + static LLCoordGL sContextMenuSpawnPos; private: - static LLHandle sItemLastSelectedHandle; - static LLFrameTimer sItemActivationTimer; + static LLHandle sItemLastSelectedHandle; + static LLFrameTimer sItemActivationTimer; - BOOL mCanHide; + BOOL mCanHide; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -877,26 +877,26 @@ private: class LLTearOffMenu : public LLFloater { public: - static LLTearOffMenu* create(LLMenuGL* menup); - virtual ~LLTearOffMenu(); + static LLTearOffMenu* create(LLMenuGL* menup); + virtual ~LLTearOffMenu(); - virtual void draw(void); - virtual void onFocusReceived(); - virtual void onFocusLost(); - virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); - virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual void translate(S32 x, S32 y); + virtual void draw(void); + virtual void onFocusReceived(); + virtual void onFocusLost(); + virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual void translate(S32 x, S32 y); - void updateSize(); + void updateSize(); private: - LLTearOffMenu(LLMenuGL* menup); - - void closeTearOff(); - - LLView* mOldParent; - LLMenuGL* mMenu; - S32 mTargetHeight; + LLTearOffMenu(LLMenuGL* menup); + + void closeTearOff(); + + LLView* mOldParent; + LLMenuGL* mMenu; + S32 mTargetHeight; bool mQuitRequested; }; @@ -909,16 +909,16 @@ private: class LLMenuItemTearOffGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block - {}; + struct Params : public LLInitParam::Block + {}; + + LLMenuItemTearOffGL( const Params& ); - LLMenuItemTearOffGL( const Params& ); - - virtual void onCommit(void); - virtual void draw(void); - virtual U32 getNominalHeight() const; + virtual void onCommit(void); + virtual void draw(void); + virtual U32 getNominalHeight() const; - LLFloater* getParentFloater(); + LLFloater* getParentFloater(); }; @@ -926,13 +926,13 @@ public: class LLEditMenuHandlerMgr { public: - LLEditMenuHandlerMgr& getInstance() { - static LLEditMenuHandlerMgr instance; - return instance; - } - virtual ~LLEditMenuHandlerMgr() {} + LLEditMenuHandlerMgr& getInstance() { + static LLEditMenuHandlerMgr instance; + return instance; + } + virtual ~LLEditMenuHandlerMgr() {} private: - LLEditMenuHandlerMgr() {}; + LLEditMenuHandlerMgr() {}; }; @@ -941,40 +941,40 @@ private: class view_listener_t : public boost::signals2::trackable { public: - virtual bool handleEvent(const LLSD& userdata) = 0; - view_listener_t() { sListeners.insert(this); } - virtual ~view_listener_t() { sListeners.erase(this); } - - static void addEnable(view_listener_t* listener, const std::string& name) - { - LLUICtrl::EnableCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); - } - - static void addCommit(view_listener_t* listener, const std::string& name) - { - LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); - } - - static void addMenu(view_listener_t* listener, const std::string& name) - { - // For now, add to both click and enable registries - addEnable(listener, name); - addCommit(listener, name); - } - - static void cleanup() - { - listener_vector_t listeners(sListeners.begin(), sListeners.end()); - sListeners.clear(); - - std::for_each(listeners.begin(), listeners.end(), DeletePointer()); - listeners.clear(); - } + virtual bool handleEvent(const LLSD& userdata) = 0; + view_listener_t() { sListeners.insert(this); } + virtual ~view_listener_t() { sListeners.erase(this); } + + static void addEnable(view_listener_t* listener, const std::string& name) + { + LLUICtrl::EnableCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); + } + + static void addCommit(view_listener_t* listener, const std::string& name) + { + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); + } + + static void addMenu(view_listener_t* listener, const std::string& name) + { + // For now, add to both click and enable registries + addEnable(listener, name); + addCommit(listener, name); + } + + static void cleanup() + { + listener_vector_t listeners(sListeners.begin(), sListeners.end()); + sListeners.clear(); + + std::for_each(listeners.begin(), listeners.end(), DeletePointer()); + listeners.clear(); + } private: - typedef std::set listener_map_t; - typedef std::vector listener_vector_t; - static listener_map_t sListeners; + typedef std::set listener_map_t; + typedef std::vector listener_vector_t; + static listener_map_t sListeners; }; #endif // LL_LLMENUGL_H diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index d6fc7d5377..348a4603de 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1,24 +1,24 @@ -/** +/** * @file lltexteditor.cpp * * $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$ */ @@ -32,7 +32,7 @@ #include "llfontfreetype.h" // for LLFontFreetype::FIRST_CHAR #include "llfontgl.h" -#include "llgl.h" // LLGLSUIDefault() +#include "llgl.h" // LLGLSUIDefault() #include "lllocalcliprect.h" #include "llrender.h" #include "llui.h" @@ -64,105 +64,105 @@ #include #include "llcombobox.h" -// +// // Globals // static LLDefaultChildRegistry::Register r("simple_text_editor"); // Compiler optimization, generate extern template template class LLTextEditor* LLView::getChild( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; // // Constants // -const S32 SPACES_PER_TAB = 4; -const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on +const S32 SPACES_PER_TAB = 4; +const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on /////////////////////////////////////////////////////////////////// class LLTextEditor::TextCmdInsert : public LLTextBase::TextCmd { public: - TextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws, LLTextSegmentPtr segment) - : TextCmd(pos, group_with_next, segment), mWString(ws) - { - } - virtual ~TextCmdInsert() {} - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - *delta = insert(editor, getPosition(), mWString ); - LLWStringUtil::truncate(mWString, *delta); - //mWString = wstring_truncate(mWString, *delta); - return (*delta != 0); - } - virtual S32 undo( LLTextBase* editor ) - { - remove(editor, getPosition(), mWString.length() ); - return getPosition(); - } - virtual S32 redo( LLTextBase* editor ) - { - insert(editor, getPosition(), mWString ); - return getPosition() + mWString.length(); - } + TextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws, LLTextSegmentPtr segment) + : TextCmd(pos, group_with_next, segment), mWString(ws) + { + } + virtual ~TextCmdInsert() {} + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + *delta = insert(editor, getPosition(), mWString ); + LLWStringUtil::truncate(mWString, *delta); + //mWString = wstring_truncate(mWString, *delta); + return (*delta != 0); + } + virtual S32 undo( LLTextBase* editor ) + { + remove(editor, getPosition(), mWString.length() ); + return getPosition(); + } + virtual S32 redo( LLTextBase* editor ) + { + insert(editor, getPosition(), mWString ); + return getPosition() + mWString.length(); + } private: - LLWString mWString; + LLWString mWString; }; /////////////////////////////////////////////////////////////////// class LLTextEditor::TextCmdAddChar : public LLTextBase::TextCmd { public: - TextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc, LLTextSegmentPtr segment) - : TextCmd(pos, group_with_next, segment), mWString(1, wc), mBlockExtensions(FALSE) - { - } - virtual void blockExtensions() - { - mBlockExtensions = TRUE; - } - virtual BOOL canExtend(S32 pos) const - { - // cannot extend text with custom segments - if (!mSegments.empty()) return FALSE; - - return !mBlockExtensions && (pos == getPosition() + (S32)mWString.length()); - } - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - *delta = insert(editor, getPosition(), mWString); - LLWStringUtil::truncate(mWString, *delta); - //mWString = wstring_truncate(mWString, *delta); - return (*delta != 0); - } - virtual BOOL extendAndExecute( LLTextBase* editor, S32 pos, llwchar wc, S32* delta ) - { - LLWString ws; - ws += wc; - - *delta = insert(editor, pos, ws); - if( *delta > 0 ) - { - mWString += wc; - } - return (*delta != 0); - } - virtual S32 undo( LLTextBase* editor ) - { - remove(editor, getPosition(), mWString.length() ); - return getPosition(); - } - virtual S32 redo( LLTextBase* editor ) - { - insert(editor, getPosition(), mWString ); - return getPosition() + mWString.length(); - } + TextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc, LLTextSegmentPtr segment) + : TextCmd(pos, group_with_next, segment), mWString(1, wc), mBlockExtensions(FALSE) + { + } + virtual void blockExtensions() + { + mBlockExtensions = TRUE; + } + virtual BOOL canExtend(S32 pos) const + { + // cannot extend text with custom segments + if (!mSegments.empty()) return FALSE; + + return !mBlockExtensions && (pos == getPosition() + (S32)mWString.length()); + } + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + *delta = insert(editor, getPosition(), mWString); + LLWStringUtil::truncate(mWString, *delta); + //mWString = wstring_truncate(mWString, *delta); + return (*delta != 0); + } + virtual BOOL extendAndExecute( LLTextBase* editor, S32 pos, llwchar wc, S32* delta ) + { + LLWString ws; + ws += wc; + + *delta = insert(editor, pos, ws); + if( *delta > 0 ) + { + mWString += wc; + } + return (*delta != 0); + } + virtual S32 undo( LLTextBase* editor ) + { + remove(editor, getPosition(), mWString.length() ); + return getPosition(); + } + virtual S32 redo( LLTextBase* editor ) + { + insert(editor, getPosition(), mWString ); + return getPosition() + mWString.length(); + } private: - LLWString mWString; - BOOL mBlockExtensions; + LLWString mWString; + BOOL mBlockExtensions; }; @@ -171,30 +171,30 @@ private: class LLTextEditor::TextCmdOverwriteChar : public LLTextBase::TextCmd { public: - TextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc) - : TextCmd(pos, group_with_next), mChar(wc), mOldChar(0) {} - - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - mOldChar = editor->getWText()[getPosition()]; - overwrite(editor, getPosition(), mChar); - *delta = 0; - return TRUE; - } - virtual S32 undo( LLTextBase* editor ) - { - overwrite(editor, getPosition(), mOldChar); - return getPosition(); - } - virtual S32 redo( LLTextBase* editor ) - { - overwrite(editor, getPosition(), mChar); - return getPosition()+1; - } + TextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc) + : TextCmd(pos, group_with_next), mChar(wc), mOldChar(0) {} + + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + mOldChar = editor->getWText()[getPosition()]; + overwrite(editor, getPosition(), mChar); + *delta = 0; + return TRUE; + } + virtual S32 undo( LLTextBase* editor ) + { + overwrite(editor, getPosition(), mOldChar); + return getPosition(); + } + virtual S32 redo( LLTextBase* editor ) + { + overwrite(editor, getPosition(), mChar); + return getPosition()+1; + } private: - llwchar mChar; - llwchar mOldChar; + llwchar mChar; + llwchar mOldChar; }; /////////////////////////////////////////////////////////////////// @@ -202,114 +202,114 @@ private: class LLTextEditor::TextCmdRemove : public LLTextBase::TextCmd { public: - TextCmdRemove( S32 pos, BOOL group_with_next, S32 len, segment_vec_t& segments ) : - TextCmd(pos, group_with_next), mLen(len) - { - std::swap(mSegments, segments); - } - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - mWString = editor->getWText().substr(getPosition(), mLen); - *delta = remove(editor, getPosition(), mLen ); - return (*delta != 0); - } - virtual S32 undo( LLTextBase* editor ) - { - insert(editor, getPosition(), mWString); - return getPosition() + mWString.length(); - } - virtual S32 redo( LLTextBase* editor ) - { - remove(editor, getPosition(), mLen ); - return getPosition(); - } + TextCmdRemove( S32 pos, BOOL group_with_next, S32 len, segment_vec_t& segments ) : + TextCmd(pos, group_with_next), mLen(len) + { + std::swap(mSegments, segments); + } + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + mWString = editor->getWText().substr(getPosition(), mLen); + *delta = remove(editor, getPosition(), mLen ); + return (*delta != 0); + } + virtual S32 undo( LLTextBase* editor ) + { + insert(editor, getPosition(), mWString); + return getPosition() + mWString.length(); + } + virtual S32 redo( LLTextBase* editor ) + { + remove(editor, getPosition(), mLen ); + return getPosition(); + } private: - LLWString mWString; - S32 mLen; + LLWString mWString; + S32 mLen; }; /////////////////////////////////////////////////////////////////// LLTextEditor::Params::Params() -: default_text("default_text"), - prevalidate_callback("prevalidate_callback"), - embedded_items("embedded_items", false), - ignore_tab("ignore_tab", true), - auto_indent("auto_indent", true), - default_color("default_color"), +: default_text("default_text"), + prevalidate_callback("prevalidate_callback"), + embedded_items("embedded_items", false), + ignore_tab("ignore_tab", true), + auto_indent("auto_indent", true), + default_color("default_color"), commit_on_focus_lost("commit_on_focus_lost", false), - show_context_menu("show_context_menu"), - show_emoji_helper("show_emoji_helper"), - enable_tooltip_paste("enable_tooltip_paste") + show_context_menu("show_context_menu"), + show_emoji_helper("show_emoji_helper"), + enable_tooltip_paste("enable_tooltip_paste") { - addSynonym(prevalidate_callback, "text_type"); + addSynonym(prevalidate_callback, "text_type"); } LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : - LLTextBase(p), - mAutoreplaceCallback(), - mBaseDocIsPristine(TRUE), - mPristineCmd( NULL ), - mLastCmd( NULL ), - mDefaultColor( p.default_color() ), - mAutoIndent(p.auto_indent), - mCommitOnFocusLost( p.commit_on_focus_lost), - mAllowEmbeddedItems( p.embedded_items ), - mMouseDownX(0), - mMouseDownY(0), - mTabsToNextField(p.ignore_tab), - mPrevalidateFunc(p.prevalidate_callback()), - mShowContextMenu(p.show_context_menu), - mShowEmojiHelper(p.show_emoji_helper), - mEnableTooltipPaste(p.enable_tooltip_paste), - mPassDelete(FALSE), - mKeepSelectionOnReturn(false) -{ - mSourceID.generate(); - - //FIXME: use image? - LLViewBorder::Params params; - params.name = "text ed border"; - params.rect = getLocalRect(); - params.bevel_style = LLViewBorder::BEVEL_IN; - params.border_thickness = 1; - params.visible = p.border_visible; - mBorder = LLUICtrlFactory::create (params); - addChild( mBorder ); - setText(p.default_text()); - - mParseOnTheFly = TRUE; + LLTextBase(p), + mAutoreplaceCallback(), + mBaseDocIsPristine(TRUE), + mPristineCmd( NULL ), + mLastCmd( NULL ), + mDefaultColor( p.default_color() ), + mAutoIndent(p.auto_indent), + mCommitOnFocusLost( p.commit_on_focus_lost), + mAllowEmbeddedItems( p.embedded_items ), + mMouseDownX(0), + mMouseDownY(0), + mTabsToNextField(p.ignore_tab), + mPrevalidateFunc(p.prevalidate_callback()), + mShowContextMenu(p.show_context_menu), + mShowEmojiHelper(p.show_emoji_helper), + mEnableTooltipPaste(p.enable_tooltip_paste), + mPassDelete(FALSE), + mKeepSelectionOnReturn(false) +{ + mSourceID.generate(); + + //FIXME: use image? + LLViewBorder::Params params; + params.name = "text ed border"; + params.rect = getLocalRect(); + params.bevel_style = LLViewBorder::BEVEL_IN; + params.border_thickness = 1; + params.visible = p.border_visible; + mBorder = LLUICtrlFactory::create (params); + addChild( mBorder ); + setText(p.default_text()); + + mParseOnTheFly = TRUE; } void LLTextEditor::initFromParams( const LLTextEditor::Params& p) { - LLTextBase::initFromParams(p); + LLTextBase::initFromParams(p); - // HACK: text editors always need to be enabled so that we can scroll - LLView::setEnabled(true); + // HACK: text editors always need to be enabled so that we can scroll + LLView::setEnabled(true); + + if (p.commit_on_focus_lost.isProvided()) + { + mCommitOnFocusLost = p.commit_on_focus_lost; + } - if (p.commit_on_focus_lost.isProvided()) - { - mCommitOnFocusLost = p.commit_on_focus_lost; - } - - updateAllowingLanguageInput(); + updateAllowingLanguageInput(); } LLTextEditor::~LLTextEditor() { - gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() while LLTextEditor still valid + gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() while LLTextEditor still valid - // Scrollbar is deleted by LLView - std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); - mUndoStack.clear(); - // Mark the menu as dead or its retained in memory till shutdown. - LLContextMenu* menu = static_cast(mContextMenuHandle.get()); - if(menu) - { - menu->die(); - mContextMenuHandle.markDead(); - } + // Scrollbar is deleted by LLView + std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); + mUndoStack.clear(); + // Mark the menu as dead or its retained in memory till shutdown. + LLContextMenu* menu = static_cast(mContextMenuHandle.get()); + if(menu) + { + menu->die(); + mContextMenuHandle.markDead(); + } } //////////////////////////////////////////////////////////// @@ -318,649 +318,649 @@ LLTextEditor::~LLTextEditor() void LLTextEditor::setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params) { - // validate incoming text if necessary - if (mPrevalidateFunc) - { - LLWString test_text = utf8str_to_wstring(utf8str); - if (!mPrevalidateFunc(test_text)) - { - // not valid text, nothing to do - return; - } - } + // validate incoming text if necessary + if (mPrevalidateFunc) + { + LLWString test_text = utf8str_to_wstring(utf8str); + if (!mPrevalidateFunc(test_text)) + { + // not valid text, nothing to do + return; + } + } - blockUndo(); - deselect(); - - mParseOnTheFly = FALSE; - LLTextBase::setText(utf8str, input_params); - mParseOnTheFly = TRUE; + blockUndo(); + deselect(); - resetDirty(); + mParseOnTheFly = FALSE; + LLTextBase::setText(utf8str, input_params); + mParseOnTheFly = TRUE; + + resetDirty(); } void LLTextEditor::selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap) { - if (search_text_in.empty()) - { - return; - } - - LLWString text = getWText(); - LLWString search_text = utf8str_to_wstring(search_text_in); - if (case_insensitive) - { - LLWStringUtil::toLower(text); - LLWStringUtil::toLower(search_text); - } - - if (mIsSelecting) - { - LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); - - if (selected_text == search_text) - { - // We already have this word selected, we are searching for the next. - setCursorPos(mCursorPos + search_text.size()); - } - } - - S32 loc = text.find(search_text,mCursorPos); - - // If Maybe we wrapped, search again - if (wrap && (-1 == loc)) - { - loc = text.find(search_text); - } - - // If still -1, then search_text just isn't found. + if (search_text_in.empty()) + { + return; + } + + LLWString text = getWText(); + LLWString search_text = utf8str_to_wstring(search_text_in); + if (case_insensitive) + { + LLWStringUtil::toLower(text); + LLWStringUtil::toLower(search_text); + } + + if (mIsSelecting) + { + LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); + + if (selected_text == search_text) + { + // We already have this word selected, we are searching for the next. + setCursorPos(mCursorPos + search_text.size()); + } + } + + S32 loc = text.find(search_text,mCursorPos); + + // If Maybe we wrapped, search again + if (wrap && (-1 == loc)) + { + loc = text.find(search_text); + } + + // If still -1, then search_text just isn't found. if (-1 == loc) - { - mIsSelecting = FALSE; - mSelectionEnd = 0; - mSelectionStart = 0; - return; - } + { + mIsSelecting = FALSE; + mSelectionEnd = 0; + mSelectionStart = 0; + return; + } + + setCursorPos(loc); - setCursorPos(loc); - - mIsSelecting = TRUE; - mSelectionEnd = mCursorPos; - mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size())); + mIsSelecting = TRUE; + mSelectionEnd = mCursorPos; + mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size())); } BOOL LLTextEditor::replaceText(const std::string& search_text_in, const std::string& replace_text, - BOOL case_insensitive, BOOL wrap) + BOOL case_insensitive, BOOL wrap) { - BOOL replaced = FALSE; + BOOL replaced = FALSE; - if (search_text_in.empty()) - { - return replaced; - } + if (search_text_in.empty()) + { + return replaced; + } - LLWString search_text = utf8str_to_wstring(search_text_in); - if (mIsSelecting) - { - LLWString text = getWText(); - LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); + LLWString search_text = utf8str_to_wstring(search_text_in); + if (mIsSelecting) + { + LLWString text = getWText(); + LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); - if (case_insensitive) - { - LLWStringUtil::toLower(selected_text); - LLWStringUtil::toLower(search_text); - } + if (case_insensitive) + { + LLWStringUtil::toLower(selected_text); + LLWStringUtil::toLower(search_text); + } - if (selected_text == search_text) - { - insertText(replace_text); - replaced = TRUE; - } - } + if (selected_text == search_text) + { + insertText(replace_text); + replaced = TRUE; + } + } - selectNext(search_text_in, case_insensitive, wrap); - return replaced; + selectNext(search_text_in, case_insensitive, wrap); + return replaced; } void LLTextEditor::replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive) { - startOfDoc(); - selectNext(search_text, case_insensitive, FALSE); + startOfDoc(); + selectNext(search_text, case_insensitive, FALSE); - BOOL replaced = TRUE; - while ( replaced ) - { - replaced = replaceText(search_text,replace_text, case_insensitive, FALSE); - } + BOOL replaced = TRUE; + while ( replaced ) + { + replaced = replaceText(search_text,replace_text, case_insensitive, FALSE); + } } S32 LLTextEditor::prevWordPos(S32 cursorPos) const { - LLWString wtext(getWText()); - while( (cursorPos > 0) && (wtext[cursorPos-1] == ' ') ) - { - cursorPos--; - } - while( (cursorPos > 0) && LLWStringUtil::isPartOfWord( wtext[cursorPos-1] ) ) - { - cursorPos--; - } - return cursorPos; + LLWString wtext(getWText()); + while( (cursorPos > 0) && (wtext[cursorPos-1] == ' ') ) + { + cursorPos--; + } + while( (cursorPos > 0) && LLWStringUtil::isPartOfWord( wtext[cursorPos-1] ) ) + { + cursorPos--; + } + return cursorPos; } S32 LLTextEditor::nextWordPos(S32 cursorPos) const { - LLWString wtext(getWText()); - while( (cursorPos < getLength()) && LLWStringUtil::isPartOfWord( wtext[cursorPos] ) ) - { - cursorPos++; - } - while( (cursorPos < getLength()) && (wtext[cursorPos] == ' ') ) - { - cursorPos++; - } - return cursorPos; + LLWString wtext(getWText()); + while( (cursorPos < getLength()) && LLWStringUtil::isPartOfWord( wtext[cursorPos] ) ) + { + cursorPos++; + } + while( (cursorPos < getLength()) && (wtext[cursorPos] == ' ') ) + { + cursorPos++; + } + return cursorPos; } -const LLTextSegmentPtr LLTextEditor::getPreviousSegment() const +const LLTextSegmentPtr LLTextEditor::getPreviousSegment() const { - static LLPointer index_segment = new LLIndexSegment; + static LLPointer index_segment = new LLIndexSegment; - index_segment->setStart(mCursorPos); - index_segment->setEnd(mCursorPos); + index_segment->setStart(mCursorPos); + index_segment->setEnd(mCursorPos); - // find segment index at character to left of cursor (or rightmost edge of selection) - segment_set_t::const_iterator it = mSegments.lower_bound(index_segment); + // find segment index at character to left of cursor (or rightmost edge of selection) + segment_set_t::const_iterator it = mSegments.lower_bound(index_segment); - if (it != mSegments.end()) - { - return *it; - } - else - { - return LLTextSegmentPtr(); - } + if (it != mSegments.end()) + { + return *it; + } + else + { + return LLTextSegmentPtr(); + } } void LLTextEditor::getSelectedSegments(LLTextEditor::segment_vec_t& segments) const { - S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos; - S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos; + S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos; + S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos; - return getSegmentsInRange(segments, left, right, true); + return getSegmentsInRange(segments, left, right, true); } void LLTextEditor::getSegmentsInRange(LLTextEditor::segment_vec_t& segments_out, S32 start, S32 end, bool include_partial) const { - segment_set_t::const_iterator first_it = getSegIterContaining(start); - segment_set_t::const_iterator end_it = getSegIterContaining(end - 1); - if (end_it != mSegments.end()) ++end_it; + segment_set_t::const_iterator first_it = getSegIterContaining(start); + segment_set_t::const_iterator end_it = getSegIterContaining(end - 1); + if (end_it != mSegments.end()) ++end_it; - for (segment_set_t::const_iterator it = first_it; it != end_it; ++it) - { - LLTextSegmentPtr segment = *it; - if (include_partial - || (segment->getStart() >= start - && segment->getEnd() <= end)) - { - segments_out.push_back(segment); - } - } + for (segment_set_t::const_iterator it = first_it; it != end_it; ++it) + { + LLTextSegmentPtr segment = *it; + if (include_partial + || (segment->getStart() >= start + && segment->getEnd() <= end)) + { + segments_out.push_back(segment); + } + } } void LLTextEditor::setShowEmojiHelper(bool show) { - if (!mShowEmojiHelper) - { - LLEmojiHelper::instance().hideHelper(this); - } + if (!mShowEmojiHelper) + { + LLEmojiHelper::instance().hideHelper(this); + } - mShowEmojiHelper = show; + mShowEmojiHelper = show; } BOOL LLTextEditor::selectionContainsLineBreaks() { - if (hasSelection()) - { - S32 left = llmin(mSelectionStart, mSelectionEnd); - S32 right = left + llabs(mSelectionStart - mSelectionEnd); + if (hasSelection()) + { + S32 left = llmin(mSelectionStart, mSelectionEnd); + S32 right = left + llabs(mSelectionStart - mSelectionEnd); - LLWString wtext = getWText(); - for( S32 i = left; i < right; i++ ) - { - if (wtext[i] == '\n') - { - return TRUE; - } - } - } - return FALSE; + LLWString wtext = getWText(); + for( S32 i = left; i < right; i++ ) + { + if (wtext[i] == '\n') + { + return TRUE; + } + } + } + return FALSE; } S32 LLTextEditor::indentLine( S32 pos, S32 spaces ) { - // Assumes that pos is at the start of the line - // spaces may be positive (indent) or negative (unindent). - // Returns the actual number of characters added or removed. - - llassert(pos >= 0); - llassert(pos <= getLength() ); - - S32 delta_spaces = 0; - - if (spaces >= 0) - { - // Indent - for(S32 i=0; i < spaces; i++) - { - delta_spaces += addChar(pos, ' '); - } - } - else - { - // Unindent - for(S32 i=0; i < -spaces; i++) - { - LLWString wtext = getWText(); - if (wtext[pos] == ' ') - { - delta_spaces += remove( pos, 1, FALSE ); - } - } - } - - return delta_spaces; + // Assumes that pos is at the start of the line + // spaces may be positive (indent) or negative (unindent). + // Returns the actual number of characters added or removed. + + llassert(pos >= 0); + llassert(pos <= getLength() ); + + S32 delta_spaces = 0; + + if (spaces >= 0) + { + // Indent + for(S32 i=0; i < spaces; i++) + { + delta_spaces += addChar(pos, ' '); + } + } + else + { + // Unindent + for(S32 i=0; i < -spaces; i++) + { + LLWString wtext = getWText(); + if (wtext[pos] == ' ') + { + delta_spaces += remove( pos, 1, FALSE ); + } + } + } + + return delta_spaces; } void LLTextEditor::indentSelectedLines( S32 spaces ) { - if( hasSelection() ) - { - LLWString text = getWText(); - S32 left = llmin( mSelectionStart, mSelectionEnd ); - S32 right = left + llabs( mSelectionStart - mSelectionEnd ); - BOOL cursor_on_right = (mSelectionEnd > mSelectionStart); - S32 cur = left; - - // Expand left to start of line - while( (cur > 0) && (text[cur] != '\n') ) - { - cur--; - } - left = cur; - if( cur > 0 ) - { - left++; - } - - // Expand right to end of line - if( text[right - 1] == '\n' ) - { - right--; - } - else - { - while( (text[right] != '\n') && (right <= getLength() ) ) - { - right++; - } - } - - // Disabling parsing on the fly to avoid updating text segments - // until all indentation commands are executed. - mParseOnTheFly = FALSE; - - // Find each start-of-line and indent it - do - { - if( text[cur] == '\n' ) - { - cur++; - } - - S32 delta_spaces = indentLine( cur, spaces ); - if( delta_spaces > 0 ) - { - cur += delta_spaces; - } - right += delta_spaces; - - text = getWText(); - - // Find the next new line - while( (cur < right) && (text[cur] != '\n') ) - { - cur++; - } - } - while( cur < right ); - - mParseOnTheFly = TRUE; - - if( (right < getLength()) && (text[right] == '\n') ) - { - right++; - } - - // Set the selection and cursor - if( cursor_on_right ) - { - mSelectionStart = left; - mSelectionEnd = right; - } - else - { - mSelectionStart = right; - mSelectionEnd = left; - } - setCursorPos(mSelectionEnd); - } + if( hasSelection() ) + { + LLWString text = getWText(); + S32 left = llmin( mSelectionStart, mSelectionEnd ); + S32 right = left + llabs( mSelectionStart - mSelectionEnd ); + BOOL cursor_on_right = (mSelectionEnd > mSelectionStart); + S32 cur = left; + + // Expand left to start of line + while( (cur > 0) && (text[cur] != '\n') ) + { + cur--; + } + left = cur; + if( cur > 0 ) + { + left++; + } + + // Expand right to end of line + if( text[right - 1] == '\n' ) + { + right--; + } + else + { + while( (text[right] != '\n') && (right <= getLength() ) ) + { + right++; + } + } + + // Disabling parsing on the fly to avoid updating text segments + // until all indentation commands are executed. + mParseOnTheFly = FALSE; + + // Find each start-of-line and indent it + do + { + if( text[cur] == '\n' ) + { + cur++; + } + + S32 delta_spaces = indentLine( cur, spaces ); + if( delta_spaces > 0 ) + { + cur += delta_spaces; + } + right += delta_spaces; + + text = getWText(); + + // Find the next new line + while( (cur < right) && (text[cur] != '\n') ) + { + cur++; + } + } + while( cur < right ); + + mParseOnTheFly = TRUE; + + if( (right < getLength()) && (text[right] == '\n') ) + { + right++; + } + + // Set the selection and cursor + if( cursor_on_right ) + { + mSelectionStart = left; + mSelectionEnd = right; + } + else + { + mSelectionStart = right; + mSelectionEnd = left; + } + setCursorPos(mSelectionEnd); + } } //virtual BOOL LLTextEditor::canSelectAll() const { - return TRUE; + return TRUE; } // virtual void LLTextEditor::selectAll() { - mSelectionStart = getLength(); - mSelectionEnd = 0; - setCursorPos(mSelectionEnd); - updatePrimary(); + mSelectionStart = getLength(); + mSelectionEnd = 0; + setCursorPos(mSelectionEnd); + updatePrimary(); } void LLTextEditor::selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos) { - setCursorPos(prev_cursor_pos); - startSelection(); - setCursorPos(next_cursor_pos); - endSelection(); + setCursorPos(prev_cursor_pos); + startSelection(); + setCursorPos(next_cursor_pos); + endSelection(); } void LLTextEditor::insertEmoji(llwchar emoji) { - LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL; - auto styleParams = LLStyle::Params(); - styleParams.font = LLFontGL::getFontEmoji(); - auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this); - insert(mCursorPos, LLWString(1, emoji), false, segment); - setCursorPos(mCursorPos + 1); + LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL; + auto styleParams = LLStyle::Params(); + styleParams.font = LLFontGL::getFontEmoji(); + auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this); + insert(mCursorPos, LLWString(1, emoji), false, segment); + setCursorPos(mCursorPos + 1); } void LLTextEditor::handleEmojiCommit(llwchar emoji) { - S32 shortCodePos; - if (LLEmojiHelper::isCursorInEmojiCode(getWText(), mCursorPos, &shortCodePos)) - { - remove(shortCodePos, mCursorPos - shortCodePos, true); - setCursorPos(shortCodePos); + S32 shortCodePos; + if (LLEmojiHelper::isCursorInEmojiCode(getWText(), mCursorPos, &shortCodePos)) + { + remove(shortCodePos, mCursorPos - shortCodePos, true); + setCursorPos(shortCodePos); - insertEmoji(emoji); - } + insertEmoji(emoji); + } } BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - // set focus first, in case click callbacks want to change it - // RN: do we really need to have a tab stop? - if (hasTabStop()) - { - setFocus( TRUE ); - } - - // Let scrollbar have first dibs - handled = LLTextBase::handleMouseDown(x, y, mask); - - if( !handled ) - { - if (!(mask & MASK_SHIFT)) - { - deselect(); - } - - BOOL start_select = TRUE; - if( start_select ) - { - // If we're not scrolling (handled by child), then we're selecting - if (mask & MASK_SHIFT) - { - S32 old_cursor_pos = mCursorPos; - setCursorAtLocalPos( x, y, true ); - - if (hasSelection()) - { - mSelectionEnd = mCursorPos; - } - else - { - mSelectionStart = old_cursor_pos; - mSelectionEnd = mCursorPos; - } - // assume we're starting a drag select - mIsSelecting = TRUE; - } - else - { - setCursorAtLocalPos( x, y, true ); - startSelection(); - } - } - - handled = TRUE; - } - - // Delay cursor flashing - resetCursorBlink(); - - if (handled && !gFocusMgr.getMouseCapture()) - { - gFocusMgr.setMouseCapture( this ); - } - return handled; + BOOL handled = FALSE; + + // set focus first, in case click callbacks want to change it + // RN: do we really need to have a tab stop? + if (hasTabStop()) + { + setFocus( TRUE ); + } + + // Let scrollbar have first dibs + handled = LLTextBase::handleMouseDown(x, y, mask); + + if( !handled ) + { + if (!(mask & MASK_SHIFT)) + { + deselect(); + } + + BOOL start_select = TRUE; + if( start_select ) + { + // If we're not scrolling (handled by child), then we're selecting + if (mask & MASK_SHIFT) + { + S32 old_cursor_pos = mCursorPos; + setCursorAtLocalPos( x, y, true ); + + if (hasSelection()) + { + mSelectionEnd = mCursorPos; + } + else + { + mSelectionStart = old_cursor_pos; + mSelectionEnd = mCursorPos; + } + // assume we're starting a drag select + mIsSelecting = TRUE; + } + else + { + setCursorAtLocalPos( x, y, true ); + startSelection(); + } + } + + handled = TRUE; + } + + // Delay cursor flashing + resetCursorBlink(); + + if (handled && !gFocusMgr.getMouseCapture()) + { + gFocusMgr.setMouseCapture( this ); + } + return handled; } BOOL LLTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) { - if (hasTabStop()) - { - setFocus(TRUE); - } + if (hasTabStop()) + { + setFocus(TRUE); + } - bool show_menu = false; + bool show_menu = false; - // Prefer editor menu if it has selection. See EXT-6806. - if (hasSelection()) - { - S32 click_pos = getDocIndexFromLocalCoord(x, y, FALSE); - if (click_pos > mSelectionStart && click_pos < mSelectionEnd) - { - show_menu = true; - } - } + // Prefer editor menu if it has selection. See EXT-6806. + if (hasSelection()) + { + S32 click_pos = getDocIndexFromLocalCoord(x, y, FALSE); + if (click_pos > mSelectionStart && click_pos < mSelectionEnd) + { + show_menu = true; + } + } - // Let segments handle the click, if nothing does, show editor menu - if (!show_menu && !LLTextBase::handleRightMouseDown(x, y, mask)) - { - show_menu = true; - } + // Let segments handle the click, if nothing does, show editor menu + if (!show_menu && !LLTextBase::handleRightMouseDown(x, y, mask)) + { + show_menu = true; + } - if (show_menu && getShowContextMenu()) - { - showContextMenu(x, y); - } + if (show_menu && getShowContextMenu()) + { + showContextMenu(x, y); + } - return TRUE; + return TRUE; } BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) { - if (hasTabStop()) - { - setFocus(TRUE); - } + if (hasTabStop()) + { + setFocus(TRUE); + } - if (!LLTextBase::handleMouseDown(x, y, mask)) - { - if( canPastePrimary() ) - { - setCursorAtLocalPos( x, y, true ); - // does not rely on focus being set - pastePrimary(); - } - } - return TRUE; + if (!LLTextBase::handleMouseDown(x, y, mask)) + { + if( canPastePrimary() ) + { + setCursorAtLocalPos( x, y, true ); + // does not rely on focus being set + pastePrimary(); + } + } + return TRUE; } BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - if(hasMouseCapture() ) - { - if( mIsSelecting ) - { - if(mScroller) - { - mScroller->autoScroll(x, y); - } - S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); - S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); - setCursorAtLocalPos( clamped_x, clamped_y, true ); - mSelectionEnd = mCursorPos; - } - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; - getWindow()->setCursor(UI_CURSOR_IBEAM); - handled = TRUE; - } - - if( !handled ) - { - // Pass to children - handled = LLTextBase::handleHover(x, y, mask); - } - - if( handled ) - { - // Delay cursor flashing - resetCursorBlink(); - } - - if( !handled ) - { - getWindow()->setCursor(UI_CURSOR_IBEAM); - handled = TRUE; - } - - return handled; + BOOL handled = FALSE; + + if(hasMouseCapture() ) + { + if( mIsSelecting ) + { + if(mScroller) + { + mScroller->autoScroll(x, y); + } + S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); + S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); + setCursorAtLocalPos( clamped_x, clamped_y, true ); + mSelectionEnd = mCursorPos; + } + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; + getWindow()->setCursor(UI_CURSOR_IBEAM); + handled = TRUE; + } + + if( !handled ) + { + // Pass to children + handled = LLTextBase::handleHover(x, y, mask); + } + + if( handled ) + { + // Delay cursor flashing + resetCursorBlink(); + } + + if( !handled ) + { + getWindow()->setCursor(UI_CURSOR_IBEAM); + handled = TRUE; + } + + return handled; } BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - // if I'm not currently selecting text - if (!(mIsSelecting && hasMouseCapture())) - { - // let text segments handle mouse event - handled = LLTextBase::handleMouseUp(x, y, mask); - } - - if( !handled ) - { - if( mIsSelecting ) - { - if(mScroller) - { - mScroller->autoScroll(x, y); - } - S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); - S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); - setCursorAtLocalPos( clamped_x, clamped_y, true ); - endSelection(); - } - - // take selection to 'primary' clipboard - updatePrimary(); - - handled = TRUE; - } - - // Delay cursor flashing - resetCursorBlink(); - - if( hasMouseCapture() ) - { - gFocusMgr.setMouseCapture( NULL ); - - handled = TRUE; - } - - return handled; + BOOL handled = FALSE; + + // if I'm not currently selecting text + if (!(mIsSelecting && hasMouseCapture())) + { + // let text segments handle mouse event + handled = LLTextBase::handleMouseUp(x, y, mask); + } + + if( !handled ) + { + if( mIsSelecting ) + { + if(mScroller) + { + mScroller->autoScroll(x, y); + } + S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); + S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); + setCursorAtLocalPos( clamped_x, clamped_y, true ); + endSelection(); + } + + // take selection to 'primary' clipboard + updatePrimary(); + + handled = TRUE; + } + + // Delay cursor flashing + resetCursorBlink(); + + if( hasMouseCapture() ) + { + gFocusMgr.setMouseCapture( NULL ); + + handled = TRUE; + } + + return handled; } BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; + BOOL handled = FALSE; - // let scrollbar and text segments have first dibs - handled = LLTextBase::handleDoubleClick(x, y, mask); + // let scrollbar and text segments have first dibs + handled = LLTextBase::handleDoubleClick(x, y, mask); - if( !handled ) - { - setCursorAtLocalPos( x, y, false ); - deselect(); + if( !handled ) + { + setCursorAtLocalPos( x, y, false ); + deselect(); - LLWString text = getWText(); - - if( LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) - { - // Select word the cursor is over - while ((mCursorPos > 0) && LLWStringUtil::isPartOfWord(text[mCursorPos-1])) - { - if (!setCursorPos(mCursorPos - 1)) break; - } - startSelection(); + LLWString text = getWText(); - while ((mCursorPos < (S32)text.length()) && LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) - { - if (!setCursorPos(mCursorPos + 1)) break; - } - - mSelectionEnd = mCursorPos; - } - else if ((mCursorPos < (S32)text.length()) && !iswspace( text[mCursorPos]) ) - { - // Select the character the cursor is over - startSelection(); - setCursorPos(mCursorPos + 1); - mSelectionEnd = mCursorPos; - } + if( LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) + { + // Select word the cursor is over + while ((mCursorPos > 0) && LLWStringUtil::isPartOfWord(text[mCursorPos-1])) + { + if (!setCursorPos(mCursorPos - 1)) break; + } + startSelection(); + + while ((mCursorPos < (S32)text.length()) && LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) + { + if (!setCursorPos(mCursorPos + 1)) break; + } + + mSelectionEnd = mCursorPos; + } + else if ((mCursorPos < (S32)text.length()) && !iswspace( text[mCursorPos]) ) + { + // Select the character the cursor is over + startSelection(); + setCursorPos(mCursorPos + 1); + mSelectionEnd = mCursorPos; + } - // We don't want handleMouseUp() to "finish" the selection (and thereby - // set mSelectionEnd to where the mouse is), so we finish the selection here. - mIsSelecting = FALSE; + // We don't want handleMouseUp() to "finish" the selection (and thereby + // set mSelectionEnd to where the mouse is), so we finish the selection here. + mIsSelecting = FALSE; - // delay cursor flashing - resetCursorBlink(); + // delay cursor flashing + resetCursorBlink(); - // take selection to 'primary' clipboard - updatePrimary(); + // take selection to 'primary' clipboard + updatePrimary(); - handled = TRUE; - } + handled = TRUE; + } - return handled; + return handled; } @@ -969,228 +969,228 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) S32 LLTextEditor::execute( TextCmd* cmd ) { - if (!mReadOnly && mShowEmojiHelper) - { - // Any change to our contents should always hide the helper - LLEmojiHelper::instance().hideHelper(this); - } - - S32 delta = 0; - if( cmd->execute(this, &delta) ) - { - // Delete top of undo stack - undo_stack_t::iterator enditer = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); - std::for_each(mUndoStack.begin(), enditer, DeletePointer()); - mUndoStack.erase(mUndoStack.begin(), enditer); - // Push the new command is now on the top (front) of the undo stack. - mUndoStack.push_front(cmd); - mLastCmd = cmd; - - bool need_to_rollback = mPrevalidateFunc - && !mPrevalidateFunc(getViewModel()->getDisplay()); - if (need_to_rollback) - { - // get rid of this last command and clean up undo stack - undo(); - - // remove any evidence of this command from redo history - mUndoStack.pop_front(); - delete cmd; - - // failure, nothing changed - delta = 0; - } - } - else - { - // Operation failed, so don't put it on the undo stack. - delete cmd; - } - - return delta; + if (!mReadOnly && mShowEmojiHelper) + { + // Any change to our contents should always hide the helper + LLEmojiHelper::instance().hideHelper(this); + } + + S32 delta = 0; + if( cmd->execute(this, &delta) ) + { + // Delete top of undo stack + undo_stack_t::iterator enditer = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); + std::for_each(mUndoStack.begin(), enditer, DeletePointer()); + mUndoStack.erase(mUndoStack.begin(), enditer); + // Push the new command is now on the top (front) of the undo stack. + mUndoStack.push_front(cmd); + mLastCmd = cmd; + + bool need_to_rollback = mPrevalidateFunc + && !mPrevalidateFunc(getViewModel()->getDisplay()); + if (need_to_rollback) + { + // get rid of this last command and clean up undo stack + undo(); + + // remove any evidence of this command from redo history + mUndoStack.pop_front(); + delete cmd; + + // failure, nothing changed + delta = 0; + } + } + else + { + // Operation failed, so don't put it on the undo stack. + delete cmd; + } + + return delta; } S32 LLTextEditor::insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment) { - return execute( new TextCmdInsert( pos, group_with_next_op, wstr, segment ) ); + return execute( new TextCmdInsert( pos, group_with_next_op, wstr, segment ) ); } S32 LLTextEditor::remove(S32 pos, S32 length, bool group_with_next_op) { - S32 end_pos = getEditableIndex(pos + length, true); - BOOL removedChar = FALSE; + S32 end_pos = getEditableIndex(pos + length, true); + BOOL removedChar = FALSE; + + segment_vec_t segments_to_remove; + // store text segments + getSegmentsInRange(segments_to_remove, pos, pos + length, false); - segment_vec_t segments_to_remove; - // store text segments - getSegmentsInRange(segments_to_remove, pos, pos + length, false); - - if (pos <= end_pos) - { - removedChar = execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) ); - } + if (pos <= end_pos) + { + removedChar = execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) ); + } - return removedChar; + return removedChar; } S32 LLTextEditor::overwriteChar(S32 pos, llwchar wc) { - if ((S32)getLength() == pos) - { - return addChar(pos, wc); - } - else - { - return execute(new TextCmdOverwriteChar(pos, FALSE, wc)); - } + if ((S32)getLength() == pos) + { + return addChar(pos, wc); + } + else + { + return execute(new TextCmdOverwriteChar(pos, FALSE, wc)); + } } // Remove a single character from the text. Tries to remove // a pseudo-tab (up to for spaces in a row) void LLTextEditor::removeCharOrTab() { - if (!getEnabled()) - { - return; - } - - if (mCursorPos > 0) - { - S32 chars_to_remove = 1; - - LLWString text = getWText(); - if (text[mCursorPos - 1] == ' ') - { - // Try to remove a "tab" - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - if (offset > 0) - { - chars_to_remove = offset % SPACES_PER_TAB; - if (chars_to_remove == 0) - { - chars_to_remove = SPACES_PER_TAB; - } - - for (S32 i = 0; i < chars_to_remove; i++) - { - if (text[mCursorPos - i - 1] != ' ') - { - // Fewer than a full tab's worth of spaces, so - // just delete a single character. - chars_to_remove = 1; - break; - } - } - } - } - - for (S32 i = 0; i < chars_to_remove; i++) - { - setCursorPos(mCursorPos - 1); - remove(mCursorPos, 1, false); - } - - tryToShowEmojiHelper(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } -} + if (!getEnabled()) + { + return; + } -// Remove a single character from the text -S32 LLTextEditor::removeChar(S32 pos) -{ - return remove(pos, 1, false); + if (mCursorPos > 0) + { + S32 chars_to_remove = 1; + + LLWString text = getWText(); + if (text[mCursorPos - 1] == ' ') + { + // Try to remove a "tab" + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + if (offset > 0) + { + chars_to_remove = offset % SPACES_PER_TAB; + if (chars_to_remove == 0) + { + chars_to_remove = SPACES_PER_TAB; + } + + for (S32 i = 0; i < chars_to_remove; i++) + { + if (text[mCursorPos - i - 1] != ' ') + { + // Fewer than a full tab's worth of spaces, so + // just delete a single character. + chars_to_remove = 1; + break; + } + } + } + } + + for (S32 i = 0; i < chars_to_remove; i++) + { + setCursorPos(mCursorPos - 1); + remove(mCursorPos, 1, false); + } + + tryToShowEmojiHelper(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } +} + +// Remove a single character from the text +S32 LLTextEditor::removeChar(S32 pos) +{ + return remove(pos, 1, false); } void LLTextEditor::removeChar() { - if (!getEnabled()) - { - return; - } + if (!getEnabled()) + { + return; + } - if (mCursorPos > 0) - { - setCursorPos(mCursorPos - 1); - removeChar(mCursorPos); - tryToShowEmojiHelper(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } + if (mCursorPos > 0) + { + setCursorPos(mCursorPos - 1); + removeChar(mCursorPos); + tryToShowEmojiHelper(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } } // Add a single character to the text S32 LLTextEditor::addChar(S32 pos, llwchar wc) { - if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) > mMaxTextByteLength) - { - make_ui_sound("UISndBadKeystroke"); - return 0; - } - - if (mLastCmd && mLastCmd->canExtend(pos)) - { - S32 delta = 0; - if (mPrevalidateFunc) - { - // get a copy of current text contents - LLWString test_string(getViewModel()->getDisplay()); - - // modify text contents as if this addChar succeeded - llassert(pos <= (S32)test_string.size()); - test_string.insert(pos, 1, wc); - if (!mPrevalidateFunc( test_string)) - { - return 0; - } - } - mLastCmd->extendAndExecute(this, pos, wc, &delta); - - return delta; - } - else - { - return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr())); - } + if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) > mMaxTextByteLength) + { + make_ui_sound("UISndBadKeystroke"); + return 0; + } + + if (mLastCmd && mLastCmd->canExtend(pos)) + { + S32 delta = 0; + if (mPrevalidateFunc) + { + // get a copy of current text contents + LLWString test_string(getViewModel()->getDisplay()); + + // modify text contents as if this addChar succeeded + llassert(pos <= (S32)test_string.size()); + test_string.insert(pos, 1, wc); + if (!mPrevalidateFunc( test_string)) + { + return 0; + } + } + mLastCmd->extendAndExecute(this, pos, wc, &delta); + + return delta; + } + else + { + return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr())); + } } void LLTextEditor::addChar(llwchar wc) { - if( !getEnabled() ) - { - return; - } - if( hasSelection() ) - { - deleteSelection(TRUE); - } - else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - removeChar(mCursorPos); - } - - setCursorPos(mCursorPos + addChar( mCursorPos, wc )); - tryToShowEmojiHelper(); - - if (!mReadOnly && mAutoreplaceCallback != NULL) - { - // autoreplace the text, if necessary - S32 replacement_start; - S32 replacement_length; - LLWString replacement_string; - S32 new_cursor_pos = mCursorPos; - mAutoreplaceCallback(replacement_start, replacement_length, replacement_string, new_cursor_pos, getWText()); - - if (replacement_length > 0 || !replacement_string.empty()) - { - remove(replacement_start, replacement_length, true); - insert(replacement_start, replacement_string, false, LLTextSegmentPtr()); - setCursorPos(new_cursor_pos); - } - } + if( !getEnabled() ) + { + return; + } + if( hasSelection() ) + { + deleteSelection(TRUE); + } + else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + removeChar(mCursorPos); + } + + setCursorPos(mCursorPos + addChar( mCursorPos, wc )); + tryToShowEmojiHelper(); + + if (!mReadOnly && mAutoreplaceCallback != NULL) + { + // autoreplace the text, if necessary + S32 replacement_start; + S32 replacement_length; + LLWString replacement_string; + S32 new_cursor_pos = mCursorPos; + mAutoreplaceCallback(replacement_start, replacement_length, replacement_string, new_cursor_pos, getWText()); + + if (replacement_length > 0 || !replacement_string.empty()) + { + remove(replacement_start, replacement_length, true); + insert(replacement_start, replacement_string, false, LLTextSegmentPtr()); + setCursorPos(new_cursor_pos); + } + } } void LLTextEditor::showEmojiHelper() @@ -1226,792 +1226,792 @@ void LLTextEditor::tryToShowEmojiHelper() void LLTextEditor::addLineBreakChar(BOOL group_together) { - if( !getEnabled() ) - { - return; - } - if( hasSelection() ) - { - deleteSelection(TRUE); - } - else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - removeChar(mCursorPos); - } + if( !getEnabled() ) + { + return; + } + if( hasSelection() ) + { + deleteSelection(TRUE); + } + else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + removeChar(mCursorPos); + } + + LLStyleConstSP sp(new LLStyle(LLStyle::Params())); + LLTextSegmentPtr segment = new LLLineBreakTextSegment(sp, mCursorPos); - LLStyleConstSP sp(new LLStyle(LLStyle::Params())); - LLTextSegmentPtr segment = new LLLineBreakTextSegment(sp, mCursorPos); + S32 pos = execute(new TextCmdAddChar(mCursorPos, group_together, '\n', segment)); - S32 pos = execute(new TextCmdAddChar(mCursorPos, group_together, '\n', segment)); - - setCursorPos(mCursorPos + pos); + setCursorPos(mCursorPos + pos); } BOOL LLTextEditor::handleSelectionKey(const KEY key, const MASK mask) { - BOOL handled = FALSE; - - if( mask & MASK_SHIFT ) - { - handled = TRUE; - - switch( key ) - { - case KEY_LEFT: - if( 0 < mCursorPos ) - { - startSelection(); - setCursorPos(mCursorPos - 1); - if( mask & MASK_CONTROL ) - { - setCursorPos(prevWordPos(mCursorPos)); - } - mSelectionEnd = mCursorPos; - } - break; - - case KEY_RIGHT: - if( mCursorPos < getLength() ) - { - startSelection(); - setCursorPos(mCursorPos + 1); - if( mask & MASK_CONTROL ) - { - setCursorPos(nextWordPos(mCursorPos)); - } - mSelectionEnd = mCursorPos; - } - break; - - case KEY_UP: - startSelection(); - changeLine( -1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_PAGE_UP: - startSelection(); - changePage( -1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_HOME: - startSelection(); - if( mask & MASK_CONTROL ) - { - setCursorPos(0); - } - else - { - startOfLine(); - } - mSelectionEnd = mCursorPos; - break; - - case KEY_DOWN: - startSelection(); - changeLine( 1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_PAGE_DOWN: - startSelection(); - changePage( 1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_END: - startSelection(); - if( mask & MASK_CONTROL ) - { - setCursorPos(getLength()); - } - else - { - endOfLine(); - } - mSelectionEnd = mCursorPos; - break; - - default: - handled = FALSE; - break; - } - } - - if( handled ) - { - // take selection to 'primary' clipboard - updatePrimary(); - } - - return handled; + BOOL handled = FALSE; + + if( mask & MASK_SHIFT ) + { + handled = TRUE; + + switch( key ) + { + case KEY_LEFT: + if( 0 < mCursorPos ) + { + startSelection(); + setCursorPos(mCursorPos - 1); + if( mask & MASK_CONTROL ) + { + setCursorPos(prevWordPos(mCursorPos)); + } + mSelectionEnd = mCursorPos; + } + break; + + case KEY_RIGHT: + if( mCursorPos < getLength() ) + { + startSelection(); + setCursorPos(mCursorPos + 1); + if( mask & MASK_CONTROL ) + { + setCursorPos(nextWordPos(mCursorPos)); + } + mSelectionEnd = mCursorPos; + } + break; + + case KEY_UP: + startSelection(); + changeLine( -1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_PAGE_UP: + startSelection(); + changePage( -1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_HOME: + startSelection(); + if( mask & MASK_CONTROL ) + { + setCursorPos(0); + } + else + { + startOfLine(); + } + mSelectionEnd = mCursorPos; + break; + + case KEY_DOWN: + startSelection(); + changeLine( 1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_PAGE_DOWN: + startSelection(); + changePage( 1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_END: + startSelection(); + if( mask & MASK_CONTROL ) + { + setCursorPos(getLength()); + } + else + { + endOfLine(); + } + mSelectionEnd = mCursorPos; + break; + + default: + handled = FALSE; + break; + } + } + + if( handled ) + { + // take selection to 'primary' clipboard + updatePrimary(); + } + + return handled; } BOOL LLTextEditor::handleNavigationKey(const KEY key, const MASK mask) { - BOOL handled = FALSE; - - // Ignore capslock key - if( MASK_NONE == mask ) - { - handled = TRUE; - switch( key ) - { - case KEY_UP: - changeLine( -1 ); - break; - - case KEY_PAGE_UP: - changePage( -1 ); - break; - - case KEY_HOME: - startOfLine(); - break; - - case KEY_DOWN: - changeLine( 1 ); - deselect(); - break; - - case KEY_PAGE_DOWN: - changePage( 1 ); - break; - - case KEY_END: - endOfLine(); - break; - - case KEY_LEFT: - if( hasSelection() ) - { - setCursorPos(llmin( mSelectionStart, mSelectionEnd )); - } - else - { - if( 0 < mCursorPos ) - { - setCursorPos(mCursorPos - 1); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - } - break; - - case KEY_RIGHT: - if( hasSelection() ) - { - setCursorPos(llmax( mSelectionStart, mSelectionEnd )); - } - else - { - if( mCursorPos < getLength() ) - { - setCursorPos(mCursorPos + 1); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - } - break; - - default: - handled = FALSE; - break; - } - } - - if (handled) - { - deselect(); - } - - return handled; + BOOL handled = FALSE; + + // Ignore capslock key + if( MASK_NONE == mask ) + { + handled = TRUE; + switch( key ) + { + case KEY_UP: + changeLine( -1 ); + break; + + case KEY_PAGE_UP: + changePage( -1 ); + break; + + case KEY_HOME: + startOfLine(); + break; + + case KEY_DOWN: + changeLine( 1 ); + deselect(); + break; + + case KEY_PAGE_DOWN: + changePage( 1 ); + break; + + case KEY_END: + endOfLine(); + break; + + case KEY_LEFT: + if( hasSelection() ) + { + setCursorPos(llmin( mSelectionStart, mSelectionEnd )); + } + else + { + if( 0 < mCursorPos ) + { + setCursorPos(mCursorPos - 1); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + } + break; + + case KEY_RIGHT: + if( hasSelection() ) + { + setCursorPos(llmax( mSelectionStart, mSelectionEnd )); + } + else + { + if( mCursorPos < getLength() ) + { + setCursorPos(mCursorPos + 1); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + } + break; + + default: + handled = FALSE; + break; + } + } + + if (handled) + { + deselect(); + } + + return handled; } void LLTextEditor::deleteSelection(BOOL group_with_next_op ) { - if( getEnabled() && hasSelection() ) - { - S32 pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - - remove( pos, length, group_with_next_op ); + if( getEnabled() && hasSelection() ) + { + S32 pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); - deselect(); - setCursorPos(pos); - } + remove( pos, length, group_with_next_op ); + + deselect(); + setCursorPos(pos); + } } // virtual BOOL LLTextEditor::canCut() const { - return !mReadOnly && hasSelection(); + return !mReadOnly && hasSelection(); } // cut selection to clipboard void LLTextEditor::cut() { - if( !canCut() ) - { - return; - } - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard( getWText(), left_pos, length); - deleteSelection( FALSE ); + if( !canCut() ) + { + return; + } + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard( getWText(), left_pos, length); + deleteSelection( FALSE ); - onKeyStroke(); + onKeyStroke(); } BOOL LLTextEditor::canCopy() const { - return hasSelection(); + return hasSelection(); } // copy selection to clipboard void LLTextEditor::copy() { - if( !canCopy() ) - { - return; - } - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard(getWText(), left_pos, length); + if( !canCopy() ) + { + return; + } + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard(getWText(), left_pos, length); } BOOL LLTextEditor::canPaste() const { - return !mReadOnly && LLClipboard::instance().isTextAvailable(); + return !mReadOnly && LLClipboard::instance().isTextAvailable(); } // paste from clipboard void LLTextEditor::paste() { - bool is_primary = false; - pasteHelper(is_primary); + bool is_primary = false; + pasteHelper(is_primary); } // paste from primary void LLTextEditor::pastePrimary() { - bool is_primary = true; - pasteHelper(is_primary); + bool is_primary = true; + pasteHelper(is_primary); } // paste from primary (itsprimary==true) or clipboard (itsprimary==false) void LLTextEditor::pasteHelper(bool is_primary) { - mParseOnTheFly = FALSE; - bool can_paste_it; - if (is_primary) - { - can_paste_it = canPastePrimary(); - } - else - { - can_paste_it = canPaste(); - } + mParseOnTheFly = FALSE; + bool can_paste_it; + if (is_primary) + { + can_paste_it = canPastePrimary(); + } + else + { + can_paste_it = canPaste(); + } - if (!can_paste_it) - { - return; - } + if (!can_paste_it) + { + return; + } - LLWString paste; - LLClipboard::instance().pasteFromClipboard(paste, is_primary); + LLWString paste; + LLClipboard::instance().pasteFromClipboard(paste, is_primary); - if (paste.empty()) - { - return; - } + if (paste.empty()) + { + return; + } - // Delete any selected characters (the paste replaces them) - if( (!is_primary) && hasSelection() ) - { - deleteSelection(TRUE); - } + // Delete any selected characters (the paste replaces them) + if( (!is_primary) && hasSelection() ) + { + deleteSelection(TRUE); + } - // Clean up string (replace tabs and remove characters that our fonts don't support). - LLWString clean_string(paste); - cleanStringForPaste(clean_string); + // Clean up string (replace tabs and remove characters that our fonts don't support). + LLWString clean_string(paste); + cleanStringForPaste(clean_string); - // Insert the new text into the existing text. + // Insert the new text into the existing text. - //paste text with linebreaks. - pasteTextWithLinebreaks(clean_string); + //paste text with linebreaks. + pasteTextWithLinebreaks(clean_string); - deselect(); + deselect(); - onKeyStroke(); - mParseOnTheFly = TRUE; + onKeyStroke(); + mParseOnTheFly = TRUE; } // Clean up string (replace tabs and remove characters that our fonts don't support). void LLTextEditor::cleanStringForPaste(LLWString & clean_string) { - std::string clean_string_utf = wstring_to_utf8str(clean_string); - std::replace( clean_string_utf.begin(), clean_string_utf.end(), '\r', '\n'); - clean_string = utf8str_to_wstring(clean_string_utf); - - LLWStringUtil::replaceTabsWithSpaces(clean_string, SPACES_PER_TAB); - if( mAllowEmbeddedItems ) - { - const llwchar LF = 10; - S32 len = clean_string.length(); - for( S32 i = 0; i < len; i++ ) - { - llwchar wc = clean_string[i]; - if( (wc < LLFontFreetype::FIRST_CHAR) && (wc != LF) ) - { - clean_string[i] = LL_UNKNOWN_CHAR; - } - else if (wc >= FIRST_EMBEDDED_CHAR && wc <= LAST_EMBEDDED_CHAR) - { - clean_string[i] = pasteEmbeddedItem(wc); - } - } - } + std::string clean_string_utf = wstring_to_utf8str(clean_string); + std::replace( clean_string_utf.begin(), clean_string_utf.end(), '\r', '\n'); + clean_string = utf8str_to_wstring(clean_string_utf); + + LLWStringUtil::replaceTabsWithSpaces(clean_string, SPACES_PER_TAB); + if( mAllowEmbeddedItems ) + { + const llwchar LF = 10; + S32 len = clean_string.length(); + for( S32 i = 0; i < len; i++ ) + { + llwchar wc = clean_string[i]; + if( (wc < LLFontFreetype::FIRST_CHAR) && (wc != LF) ) + { + clean_string[i] = LL_UNKNOWN_CHAR; + } + else if (wc >= FIRST_EMBEDDED_CHAR && wc <= LAST_EMBEDDED_CHAR) + { + clean_string[i] = pasteEmbeddedItem(wc); + } + } + } } template <> void LLTextEditor::pasteTextWithLinebreaks(const LLWString & clean_string) { - std::basic_string::size_type start = 0; - std::basic_string::size_type pos = clean_string.find('\n',start); - - while((pos != -1) && (pos != clean_string.length() -1)) - { - if(pos!=start) - { - std::basic_string str = std::basic_string(clean_string,start,pos-start); - setCursorPos(mCursorPos + insert(mCursorPos, str, TRUE, LLTextSegmentPtr())); - } - addLineBreakChar(TRUE); // Add a line break and group with the next addition. - - start = pos+1; - pos = clean_string.find('\n',start); - } - - if (pos != start) - { - std::basic_string str = std::basic_string(clean_string,start,clean_string.length()-start); - setCursorPos(mCursorPos + insert(mCursorPos, str, FALSE, LLTextSegmentPtr())); - } - else - { - addLineBreakChar(FALSE); // Add a line break and end the grouping. - } + std::basic_string::size_type start = 0; + std::basic_string::size_type pos = clean_string.find('\n',start); + + while((pos != -1) && (pos != clean_string.length() -1)) + { + if(pos!=start) + { + std::basic_string str = std::basic_string(clean_string,start,pos-start); + setCursorPos(mCursorPos + insert(mCursorPos, str, TRUE, LLTextSegmentPtr())); + } + addLineBreakChar(TRUE); // Add a line break and group with the next addition. + + start = pos+1; + pos = clean_string.find('\n',start); + } + + if (pos != start) + { + std::basic_string str = std::basic_string(clean_string,start,clean_string.length()-start); + setCursorPos(mCursorPos + insert(mCursorPos, str, FALSE, LLTextSegmentPtr())); + } + else + { + addLineBreakChar(FALSE); // Add a line break and end the grouping. + } } // copy selection to primary void LLTextEditor::copyPrimary() { - if( !canCopy() ) - { - return; - } - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard(getWText(), left_pos, length, true); + if( !canCopy() ) + { + return; + } + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard(getWText(), left_pos, length, true); } BOOL LLTextEditor::canPastePrimary() const { - return !mReadOnly && LLClipboard::instance().isTextAvailable(true); + return !mReadOnly && LLClipboard::instance().isTextAvailable(true); } void LLTextEditor::updatePrimary() { - if (canCopy()) - { - copyPrimary(); - } -} - -BOOL LLTextEditor::handleControlKey(const KEY key, const MASK mask) -{ - BOOL handled = FALSE; - - if( mask & MASK_CONTROL ) - { - handled = TRUE; - - switch( key ) - { - case KEY_HOME: - if( mask & MASK_SHIFT ) - { - startSelection(); - setCursorPos(0); - mSelectionEnd = mCursorPos; - } - else - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - startOfDoc(); - } - break; - - case KEY_END: - { - if( mask & MASK_SHIFT ) - { - startSelection(); - } - else - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - } - endOfDoc(); - if( mask & MASK_SHIFT ) - { - mSelectionEnd = mCursorPos; - } - break; - } - - case KEY_RIGHT: - if( mCursorPos < getLength() ) - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - - setCursorPos(nextWordPos(mCursorPos + 1)); - } - break; - - - case KEY_LEFT: - if( mCursorPos > 0 ) - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - - setCursorPos(prevWordPos(mCursorPos - 1)); - } - break; - - default: - handled = FALSE; - break; - } - } - - if (handled && !gFocusMgr.getMouseCapture()) - { - updatePrimary(); - } - - return handled; -} - - -BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask) - { - BOOL handled = TRUE; - - if (mReadOnly) return FALSE; - - switch( key ) - { - case KEY_INSERT: - if (mask == MASK_NONE) - { - gKeyboard->toggleInsertMode(); - } - break; - - case KEY_BACKSPACE: - if( hasSelection() ) - { - deleteSelection(FALSE); - } - else - if( 0 < mCursorPos ) - { - removeCharOrTab(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - break; - - - case KEY_RETURN: - if (mask == MASK_NONE) - { - if( hasSelection() && !mKeepSelectionOnReturn ) - { - deleteSelection(FALSE); - } - if (mAutoIndent) - { - autoIndent(); - } - } - else - { - handled = FALSE; - break; - } - break; - - case KEY_TAB: - if (mask & MASK_CONTROL) - { - handled = FALSE; - break; - } - if( hasSelection() && selectionContainsLineBreaks() ) - { - indentSelectedLines( (mask & MASK_SHIFT) ? -SPACES_PER_TAB : SPACES_PER_TAB ); - } - else - { - if( hasSelection() ) - { - deleteSelection(FALSE); - } - - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - - S32 spaces_needed = SPACES_PER_TAB - (offset % SPACES_PER_TAB); - for( S32 i=0; i < spaces_needed; i++ ) - { - addChar( ' ' ); - } - } - break; - - default: - handled = FALSE; - break; - } - - if (handled) - { - onKeyStroke(); - } - return handled; + if (canCopy()) + { + copyPrimary(); + } } - -void LLTextEditor::unindentLineBeforeCloseBrace() +BOOL LLTextEditor::handleControlKey(const KEY key, const MASK mask) { - if( mCursorPos >= 1 ) - { - LLWString text = getWText(); - if( ' ' == text[ mCursorPos - 1 ] ) - { - S32 line = getLineNumFromDocIndex(mCursorPos, false); - S32 line_start = getLineStart(line); + BOOL handled = FALSE; + + if( mask & MASK_CONTROL ) + { + handled = TRUE; + + switch( key ) + { + case KEY_HOME: + if( mask & MASK_SHIFT ) + { + startSelection(); + setCursorPos(0); + mSelectionEnd = mCursorPos; + } + else + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + startOfDoc(); + } + break; + + case KEY_END: + { + if( mask & MASK_SHIFT ) + { + startSelection(); + } + else + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + } + endOfDoc(); + if( mask & MASK_SHIFT ) + { + mSelectionEnd = mCursorPos; + } + break; + } + + case KEY_RIGHT: + if( mCursorPos < getLength() ) + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + + setCursorPos(nextWordPos(mCursorPos + 1)); + } + break; + + + case KEY_LEFT: + if( mCursorPos > 0 ) + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + + setCursorPos(prevWordPos(mCursorPos - 1)); + } + break; + + default: + handled = FALSE; + break; + } + } + + if (handled && !gFocusMgr.getMouseCapture()) + { + updatePrimary(); + } + + return handled; +} + + +BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask) + { + BOOL handled = TRUE; + + if (mReadOnly) return FALSE; + + switch( key ) + { + case KEY_INSERT: + if (mask == MASK_NONE) + { + gKeyboard->toggleInsertMode(); + } + break; + + case KEY_BACKSPACE: + if( hasSelection() ) + { + deleteSelection(FALSE); + } + else + if( 0 < mCursorPos ) + { + removeCharOrTab(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + break; + + + case KEY_RETURN: + if (mask == MASK_NONE) + { + if( hasSelection() && !mKeepSelectionOnReturn ) + { + deleteSelection(FALSE); + } + if (mAutoIndent) + { + autoIndent(); + } + } + else + { + handled = FALSE; + break; + } + break; + + case KEY_TAB: + if (mask & MASK_CONTROL) + { + handled = FALSE; + break; + } + if( hasSelection() && selectionContainsLineBreaks() ) + { + indentSelectedLines( (mask & MASK_SHIFT) ? -SPACES_PER_TAB : SPACES_PER_TAB ); + } + else + { + if( hasSelection() ) + { + deleteSelection(FALSE); + } + + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + + S32 spaces_needed = SPACES_PER_TAB - (offset % SPACES_PER_TAB); + for( S32 i=0; i < spaces_needed; i++ ) + { + addChar( ' ' ); + } + } + break; - // Jump over spaces in the current line - while ((' ' == text[line_start]) && (line_start < mCursorPos)) - { - line_start++; - } + default: + handled = FALSE; + break; + } - // Make sure there is nothing but ' ' before the Brace we are unindenting - if (line_start == mCursorPos) - { - removeCharOrTab(); - } - } - } + if (handled) + { + onKeyStroke(); + } + return handled; +} + + +void LLTextEditor::unindentLineBeforeCloseBrace() +{ + if( mCursorPos >= 1 ) + { + LLWString text = getWText(); + if( ' ' == text[ mCursorPos - 1 ] ) + { + S32 line = getLineNumFromDocIndex(mCursorPos, false); + S32 line_start = getLineStart(line); + + // Jump over spaces in the current line + while ((' ' == text[line_start]) && (line_start < mCursorPos)) + { + line_start++; + } + + // Make sure there is nothing but ' ' before the Brace we are unindenting + if (line_start == mCursorPos) + { + removeCharOrTab(); + } + } + } } BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask ) { - BOOL handled = FALSE; - - // Special case for TAB. If want to move to next field, report - // not handled and let the parent take care of field movement. - if (KEY_TAB == key && mTabsToNextField) - { - return FALSE; - } - - if (mReadOnly && mScroller) - { - handled = (mScroller && mScroller->handleKeyHere( key, mask )) - || handleSelectionKey(key, mask) - || handleControlKey(key, mask); - } - else - { - if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) - { - return TRUE; - } - - if (mEnableTooltipPaste && - LLToolTipMgr::instance().toolTipVisible() && + BOOL handled = FALSE; + + // Special case for TAB. If want to move to next field, report + // not handled and let the parent take care of field movement. + if (KEY_TAB == key && mTabsToNextField) + { + return FALSE; + } + + if (mReadOnly && mScroller) + { + handled = (mScroller && mScroller->handleKeyHere( key, mask )) + || handleSelectionKey(key, mask) + || handleControlKey(key, mask); + } + else + { + if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) + { + return TRUE; + } + + if (mEnableTooltipPaste && + LLToolTipMgr::instance().toolTipVisible() && LLToolTipMgr::instance().isTooltipPastable() && - KEY_TAB == key) - { // Paste the first line of a tooltip into the editor - std::string message; - LLToolTipMgr::instance().getToolTipMessage(message); - LLWString tool_tip_text(utf8str_to_wstring(message)); - - if (tool_tip_text.size() > 0) - { - // Delete any selected characters (the tooltip text replaces them) - if(hasSelection()) - { - deleteSelection(TRUE); - } - - std::basic_string::size_type pos = tool_tip_text.find('\n',0); - if (pos != -1) - { // Extract the first line of the tooltip - tool_tip_text = std::basic_string(tool_tip_text, 0, pos); - } - - // Add the text - cleanStringForPaste(tool_tip_text); - pasteTextWithLinebreaks(tool_tip_text); - handled = TRUE; - } - } - else - { // Normal key handling - handled = handleNavigationKey( key, mask ) - || handleSelectionKey(key, mask) - || handleControlKey(key, mask) - || handleSpecialKey(key, mask); - } - } - - if( handled ) - { - resetCursorBlink(); - needsScroll(); - - if (mShowEmojiHelper) - { - // Dismiss the helper whenever we handled a key that it didn't - LLEmojiHelper::instance().hideHelper(this); - } - } - - return handled; + KEY_TAB == key) + { // Paste the first line of a tooltip into the editor + std::string message; + LLToolTipMgr::instance().getToolTipMessage(message); + LLWString tool_tip_text(utf8str_to_wstring(message)); + + if (tool_tip_text.size() > 0) + { + // Delete any selected characters (the tooltip text replaces them) + if(hasSelection()) + { + deleteSelection(TRUE); + } + + std::basic_string::size_type pos = tool_tip_text.find('\n',0); + if (pos != -1) + { // Extract the first line of the tooltip + tool_tip_text = std::basic_string(tool_tip_text, 0, pos); + } + + // Add the text + cleanStringForPaste(tool_tip_text); + pasteTextWithLinebreaks(tool_tip_text); + handled = TRUE; + } + } + else + { // Normal key handling + handled = handleNavigationKey( key, mask ) + || handleSelectionKey(key, mask) + || handleControlKey(key, mask) + || handleSpecialKey(key, mask); + } + } + + if( handled ) + { + resetCursorBlink(); + needsScroll(); + + if (mShowEmojiHelper) + { + // Dismiss the helper whenever we handled a key that it didn't + LLEmojiHelper::instance().hideHelper(this); + } + } + + return handled; } BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char) { - if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL - { - return FALSE; - } + if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL + { + return FALSE; + } - BOOL handled = FALSE; + BOOL handled = FALSE; - // Handle most keys only if the text editor is writeable. - if( !mReadOnly ) - { + // Handle most keys only if the text editor is writeable. + if( !mReadOnly ) + { if (mShowEmojiHelper && uni_char < 0x80 && LLEmojiHelper::instance().handleKey(this, (KEY)uni_char, MASK_NONE)) { return TRUE; } if( mAutoIndent && '}' == uni_char ) - { - unindentLineBeforeCloseBrace(); - } + { + unindentLineBeforeCloseBrace(); + } - // TODO: KLW Add auto show of tool tip on ( - addChar( uni_char ); + // TODO: KLW Add auto show of tool tip on ( + addChar( uni_char ); - // Keys that add characters temporarily hide the cursor - getWindow()->hideCursorUntilMouseMove(); + // Keys that add characters temporarily hide the cursor + getWindow()->hideCursorUntilMouseMove(); - handled = TRUE; - } + handled = TRUE; + } - if( handled ) - { - resetCursorBlink(); + if( handled ) + { + resetCursorBlink(); - // Most keystrokes will make the selection box go away, but not all will. - deselect(); + // Most keystrokes will make the selection box go away, but not all will. + deselect(); - onKeyStroke(); - } + onKeyStroke(); + } - return handled; + return handled; } // virtual BOOL LLTextEditor::canDoDelete() const { - return !mReadOnly && ( !mPassDelete || ( hasSelection() || (mCursorPos < getLength())) ); + return !mReadOnly && ( !mPassDelete || ( hasSelection() || (mCursorPos < getLength())) ); } void LLTextEditor::doDelete() { - if( !canDoDelete() ) - { - return; - } - if( hasSelection() ) - { - deleteSelection(FALSE); - } - else - if( mCursorPos < getLength() ) - { - S32 i; - S32 chars_to_remove = 1; - LLWString text = getWText(); - if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) ) - { - // Try to remove a full tab's worth of spaces - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - chars_to_remove = SPACES_PER_TAB - (offset % SPACES_PER_TAB); - if( chars_to_remove == 0 ) - { - chars_to_remove = SPACES_PER_TAB; - } - - for( i = 0; i < chars_to_remove; i++ ) - { - if( text[mCursorPos + i] != ' ' ) - { - chars_to_remove = 1; - break; - } - } - } - - for( i = 0; i < chars_to_remove; i++ ) - { - setCursorPos(mCursorPos + 1); - removeChar(); - } - - } - - onKeyStroke(); + if( !canDoDelete() ) + { + return; + } + if( hasSelection() ) + { + deleteSelection(FALSE); + } + else + if( mCursorPos < getLength() ) + { + S32 i; + S32 chars_to_remove = 1; + LLWString text = getWText(); + if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) ) + { + // Try to remove a full tab's worth of spaces + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + chars_to_remove = SPACES_PER_TAB - (offset % SPACES_PER_TAB); + if( chars_to_remove == 0 ) + { + chars_to_remove = SPACES_PER_TAB; + } + + for( i = 0; i < chars_to_remove; i++ ) + { + if( text[mCursorPos + i] != ' ' ) + { + chars_to_remove = 1; + break; + } + } + } + + for( i = 0; i < chars_to_remove; i++ ) + { + setCursorPos(mCursorPos + 1); + removeChar(); + } + + } + + onKeyStroke(); } //---------------------------------------------------------------------------- @@ -2019,624 +2019,624 @@ void LLTextEditor::doDelete() void LLTextEditor::blockUndo() { - mBaseDocIsPristine = FALSE; - mLastCmd = NULL; - std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); - mUndoStack.clear(); + mBaseDocIsPristine = FALSE; + mLastCmd = NULL; + std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); + mUndoStack.clear(); } // virtual BOOL LLTextEditor::canUndo() const { - return !mReadOnly && mLastCmd != NULL; + return !mReadOnly && mLastCmd != NULL; } void LLTextEditor::undo() { - if( !canUndo() ) - { - return; - } - deselect(); - S32 pos = 0; - do - { - pos = mLastCmd->undo(this); - undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); - if (iter != mUndoStack.end()) - ++iter; - if (iter != mUndoStack.end()) - mLastCmd = *iter; - else - mLastCmd = NULL; + if( !canUndo() ) + { + return; + } + deselect(); + S32 pos = 0; + do + { + pos = mLastCmd->undo(this); + undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); + if (iter != mUndoStack.end()) + ++iter; + if (iter != mUndoStack.end()) + mLastCmd = *iter; + else + mLastCmd = NULL; - } while( mLastCmd && mLastCmd->groupWithNext() ); + } while( mLastCmd && mLastCmd->groupWithNext() ); - setCursorPos(pos); + setCursorPos(pos); - onKeyStroke(); + onKeyStroke(); } BOOL LLTextEditor::canRedo() const { - return !mReadOnly && (mUndoStack.size() > 0) && (mLastCmd != mUndoStack.front()); + return !mReadOnly && (mUndoStack.size() > 0) && (mLastCmd != mUndoStack.front()); } void LLTextEditor::redo() { - if( !canRedo() ) - { - return; - } - deselect(); - S32 pos = 0; - do - { - if( !mLastCmd ) - { - mLastCmd = mUndoStack.back(); - } - else - { - undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); - if (iter != mUndoStack.begin()) - mLastCmd = *(--iter); - else - mLastCmd = NULL; - } - - if( mLastCmd ) - { - pos = mLastCmd->redo(this); - } - } while( - mLastCmd && - mLastCmd->groupWithNext() && - (mLastCmd != mUndoStack.front()) ); - - setCursorPos(pos); - - onKeyStroke(); + if( !canRedo() ) + { + return; + } + deselect(); + S32 pos = 0; + do + { + if( !mLastCmd ) + { + mLastCmd = mUndoStack.back(); + } + else + { + undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); + if (iter != mUndoStack.begin()) + mLastCmd = *(--iter); + else + mLastCmd = NULL; + } + + if( mLastCmd ) + { + pos = mLastCmd->redo(this); + } + } while( + mLastCmd && + mLastCmd->groupWithNext() && + (mLastCmd != mUndoStack.front()) ); + + setCursorPos(pos); + + onKeyStroke(); } void LLTextEditor::onFocusReceived() { - LLTextBase::onFocusReceived(); - updateAllowingLanguageInput(); + LLTextBase::onFocusReceived(); + updateAllowingLanguageInput(); } void LLTextEditor::focusLostHelper() { - updateAllowingLanguageInput(); + updateAllowingLanguageInput(); - // Route menu back to the default - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } + // Route menu back to the default + if( gEditMenuHandler == this ) + { + gEditMenuHandler = NULL; + } - if (mCommitOnFocusLost) - { - onCommit(); - } + if (mCommitOnFocusLost) + { + onCommit(); + } - // Make sure cursor is shown again - getWindow()->showCursorFromMouseMove(); + // Make sure cursor is shown again + getWindow()->showCursorFromMouseMove(); } void LLTextEditor::onFocusLost() { - focusLostHelper(); - LLTextBase::onFocusLost(); + focusLostHelper(); + LLTextBase::onFocusLost(); } void LLTextEditor::onCommit() { - setControlValue(getValue()); - LLTextBase::onCommit(); + setControlValue(getValue()); + LLTextBase::onCommit(); } void LLTextEditor::setEnabled(BOOL enabled) { - // just treat enabled as read-only flag - bool read_only = !enabled; - if (read_only != mReadOnly) - { - //mReadOnly = read_only; - LLTextBase::setReadOnly(read_only); - updateSegments(); - updateAllowingLanguageInput(); - } + // just treat enabled as read-only flag + bool read_only = !enabled; + if (read_only != mReadOnly) + { + //mReadOnly = read_only; + LLTextBase::setReadOnly(read_only); + updateSegments(); + updateAllowingLanguageInput(); + } } void LLTextEditor::showContextMenu(S32 x, S32 y) { - LLContextMenu* menu = static_cast(mContextMenuHandle.get()); - if (!menu) - { - llassert(LLMenuGL::sMenuContainer != NULL); - menu = LLUICtrlFactory::createFromFile("menu_text_editor.xml", - LLMenuGL::sMenuContainer, - LLMenuHolderGL::child_registry_t::instance()); + LLContextMenu* menu = static_cast(mContextMenuHandle.get()); + if (!menu) + { + llassert(LLMenuGL::sMenuContainer != NULL); + menu = LLUICtrlFactory::createFromFile("menu_text_editor.xml", + LLMenuGL::sMenuContainer, + LLMenuHolderGL::child_registry_t::instance()); if(!menu) { LL_WARNS() << "Failed to create menu for LLTextEditor: " << getName() << LL_ENDL; return; } - mContextMenuHandle = menu->getHandle(); - } - - // Route menu to this class - // previously this was done in ::handleRightMoseDown: - //if(hasTabStop()) - // setFocus(TRUE) - why? weird... - // and then inside setFocus - // .... - // gEditMenuHandler = this; - // .... - // but this didn't work in all cases and just weird... - //why not here? - // (all this was done for EXT-4443) - - gEditMenuHandler = this; - - S32 screen_x, screen_y; - localPointToScreen(x, y, &screen_x, &screen_y); - - setCursorAtLocalPos(x, y, false); - if (hasSelection()) - { - if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) - { - deselect(); - } - else - { - setCursorPos(llmax(mSelectionStart, mSelectionEnd)); - } - } - - bool use_spellcheck = getSpellCheck(), is_misspelled = false; - if (use_spellcheck) - { - mSuggestionList.clear(); - - // If the cursor is on a misspelled word, retrieve suggestions for it - std::string misspelled_word = getMisspelledWord(mCursorPos); - if ((is_misspelled = !misspelled_word.empty()) == true) - { - LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); - } - } - - menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); - menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); - menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); - menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); - menu->show(screen_x, screen_y, this); + mContextMenuHandle = menu->getHandle(); + } + + // Route menu to this class + // previously this was done in ::handleRightMoseDown: + //if(hasTabStop()) + // setFocus(TRUE) - why? weird... + // and then inside setFocus + // .... + // gEditMenuHandler = this; + // .... + // but this didn't work in all cases and just weird... + //why not here? + // (all this was done for EXT-4443) + + gEditMenuHandler = this; + + S32 screen_x, screen_y; + localPointToScreen(x, y, &screen_x, &screen_y); + + setCursorAtLocalPos(x, y, false); + if (hasSelection()) + { + if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) + { + deselect(); + } + else + { + setCursorPos(llmax(mSelectionStart, mSelectionEnd)); + } + } + + bool use_spellcheck = getSpellCheck(), is_misspelled = false; + if (use_spellcheck) + { + mSuggestionList.clear(); + + // If the cursor is on a misspelled word, retrieve suggestions for it + std::string misspelled_word = getMisspelledWord(mCursorPos); + if ((is_misspelled = !misspelled_word.empty()) == true) + { + LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); + } + } + + menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); + menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); + menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); + menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); + menu->show(screen_x, screen_y, this); } void LLTextEditor::drawPreeditMarker() { - static LLUICachedControl preedit_marker_brightness ("UIPreeditMarkerBrightness", 0); - static LLUICachedControl preedit_marker_gap ("UIPreeditMarkerGap", 0); - static LLUICachedControl preedit_marker_position ("UIPreeditMarkerPosition", 0); - static LLUICachedControl preedit_marker_thickness ("UIPreeditMarkerThickness", 0); - static LLUICachedControl preedit_standout_brightness ("UIPreeditStandoutBrightness", 0); - static LLUICachedControl preedit_standout_gap ("UIPreeditStandoutGap", 0); - static LLUICachedControl preedit_standout_position ("UIPreeditStandoutPosition", 0); - static LLUICachedControl preedit_standout_thickness ("UIPreeditStandoutThickness", 0); + static LLUICachedControl preedit_marker_brightness ("UIPreeditMarkerBrightness", 0); + static LLUICachedControl preedit_marker_gap ("UIPreeditMarkerGap", 0); + static LLUICachedControl preedit_marker_position ("UIPreeditMarkerPosition", 0); + static LLUICachedControl preedit_marker_thickness ("UIPreeditMarkerThickness", 0); + static LLUICachedControl preedit_standout_brightness ("UIPreeditStandoutBrightness", 0); + static LLUICachedControl preedit_standout_gap ("UIPreeditStandoutGap", 0); + static LLUICachedControl preedit_standout_position ("UIPreeditStandoutPosition", 0); + static LLUICachedControl preedit_standout_thickness ("UIPreeditStandoutThickness", 0); - if (!hasPreeditString()) - { - return; - } + if (!hasPreeditString()) + { + return; + } const LLWString textString(getWText()); - const llwchar *text = textString.c_str(); - const S32 text_len = getLength(); - const S32 num_lines = getLineCount(); - - S32 cur_line = getFirstVisibleLine(); - if (cur_line >= num_lines) - { - return; - } - - const S32 line_height = mFont->getLineHeight(); - - S32 line_start = getLineStart(cur_line); - S32 line_y = mVisibleTextRect.mTop - line_height; - while((mVisibleTextRect.mBottom <= line_y) && (num_lines > cur_line)) - { - S32 next_start = -1; - S32 line_end = text_len; - - if ((cur_line + 1) < num_lines) - { - next_start = getLineStart(cur_line + 1); - line_end = next_start; - } - if ( text[line_end-1] == '\n' ) - { - --line_end; - } - - // Does this line contain preedits? - if (line_start >= mPreeditPositions.back()) - { - // We have passed the preedits. - break; - } - if (line_end > mPreeditPositions.front()) - { - for (U32 i = 0; i < mPreeditStandouts.size(); i++) - { - S32 left = mPreeditPositions[i]; - S32 right = mPreeditPositions[i + 1]; - if (right <= line_start || left >= line_end) - { - continue; - } - - line_info& line = mLineInfoList[cur_line]; - LLRect text_rect(line.mRect); - text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents - text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position - - S32 preedit_left = text_rect.mLeft; - if (left > line_start) - { - preedit_left += mFont->getWidth(text, line_start, left - line_start); - } - S32 preedit_right = text_rect.mLeft; - if (right < line_end) - { - preedit_right += mFont->getWidth(text, line_start, right - line_start); - } - else - { - preedit_right += mFont->getWidth(text, line_start, line_end - line_start); - } - - if (mPreeditStandouts[i]) - { - gl_rect_2d(preedit_left + preedit_standout_gap, - text_rect.mBottom + mFont->getDescenderHeight() - 1, - preedit_right - preedit_standout_gap - 1, - text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_standout_thickness, - (mCursorColor.get() * preedit_standout_brightness + mWriteableBgColor.get() * (1 - preedit_standout_brightness)).setAlpha(1.0f)); - } - else - { - gl_rect_2d(preedit_left + preedit_marker_gap, - text_rect.mBottom + mFont->getDescenderHeight() - 1, - preedit_right - preedit_marker_gap - 1, - text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_marker_thickness, - (mCursorColor.get() * preedit_marker_brightness + mWriteableBgColor.get() * (1 - preedit_marker_brightness)).setAlpha(1.0f)); - } - } - } - - // move down one line - line_y -= line_height; - line_start = next_start; - cur_line++; - } + const llwchar *text = textString.c_str(); + const S32 text_len = getLength(); + const S32 num_lines = getLineCount(); + + S32 cur_line = getFirstVisibleLine(); + if (cur_line >= num_lines) + { + return; + } + + const S32 line_height = mFont->getLineHeight(); + + S32 line_start = getLineStart(cur_line); + S32 line_y = mVisibleTextRect.mTop - line_height; + while((mVisibleTextRect.mBottom <= line_y) && (num_lines > cur_line)) + { + S32 next_start = -1; + S32 line_end = text_len; + + if ((cur_line + 1) < num_lines) + { + next_start = getLineStart(cur_line + 1); + line_end = next_start; + } + if ( text[line_end-1] == '\n' ) + { + --line_end; + } + + // Does this line contain preedits? + if (line_start >= mPreeditPositions.back()) + { + // We have passed the preedits. + break; + } + if (line_end > mPreeditPositions.front()) + { + for (U32 i = 0; i < mPreeditStandouts.size(); i++) + { + S32 left = mPreeditPositions[i]; + S32 right = mPreeditPositions[i + 1]; + if (right <= line_start || left >= line_end) + { + continue; + } + + line_info& line = mLineInfoList[cur_line]; + LLRect text_rect(line.mRect); + text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents + text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position + + S32 preedit_left = text_rect.mLeft; + if (left > line_start) + { + preedit_left += mFont->getWidth(text, line_start, left - line_start); + } + S32 preedit_right = text_rect.mLeft; + if (right < line_end) + { + preedit_right += mFont->getWidth(text, line_start, right - line_start); + } + else + { + preedit_right += mFont->getWidth(text, line_start, line_end - line_start); + } + + if (mPreeditStandouts[i]) + { + gl_rect_2d(preedit_left + preedit_standout_gap, + text_rect.mBottom + mFont->getDescenderHeight() - 1, + preedit_right - preedit_standout_gap - 1, + text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_standout_thickness, + (mCursorColor.get() * preedit_standout_brightness + mWriteableBgColor.get() * (1 - preedit_standout_brightness)).setAlpha(1.0f)); + } + else + { + gl_rect_2d(preedit_left + preedit_marker_gap, + text_rect.mBottom + mFont->getDescenderHeight() - 1, + preedit_right - preedit_marker_gap - 1, + text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_marker_thickness, + (mCursorColor.get() * preedit_marker_brightness + mWriteableBgColor.get() * (1 - preedit_marker_brightness)).setAlpha(1.0f)); + } + } + } + + // move down one line + line_y -= line_height; + line_start = next_start; + cur_line++; + } } void LLTextEditor::draw() { - { - // pad clipping rectangle so that cursor can draw at full width - // when at left edge of mVisibleTextRect - LLRect clip_rect(mVisibleTextRect); - clip_rect.stretch(1); - LLLocalClipRect clip(clip_rect); - } + { + // pad clipping rectangle so that cursor can draw at full width + // when at left edge of mVisibleTextRect + LLRect clip_rect(mVisibleTextRect); + clip_rect.stretch(1); + LLLocalClipRect clip(clip_rect); + } - LLTextBase::draw(); + LLTextBase::draw(); drawPreeditMarker(); - //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret - // when in readonly mode - mBorder->setKeyboardFocusHighlight( hasFocus() );// && !mReadOnly); + //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret + // when in readonly mode + mBorder->setKeyboardFocusHighlight( hasFocus() );// && !mReadOnly); } // Start or stop the editor from accepting text-editing keystrokes // see also LLLineEditor void LLTextEditor::setFocus( BOOL new_state ) { - BOOL old_state = hasFocus(); + BOOL old_state = hasFocus(); - // Don't change anything if the focus state didn't change - if (new_state == old_state) return; + // Don't change anything if the focus state didn't change + if (new_state == old_state) return; - // Notify early if we are losing focus. - if (!new_state) - { - getWindow()->allowLanguageTextInput(this, FALSE); - } + // Notify early if we are losing focus. + if (!new_state) + { + getWindow()->allowLanguageTextInput(this, FALSE); + } - LLTextBase::setFocus( new_state ); + LLTextBase::setFocus( new_state ); - if( new_state ) - { - // Route menu to this class - gEditMenuHandler = this; + if( new_state ) + { + // Route menu to this class + gEditMenuHandler = this; - // Don't start the cursor flashing right away - resetCursorBlink(); - } - else - { - // Route menu back to the default - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } + // Don't start the cursor flashing right away + resetCursorBlink(); + } + else + { + // Route menu back to the default + if( gEditMenuHandler == this ) + { + gEditMenuHandler = NULL; + } - endSelection(); - } + endSelection(); + } } // public void LLTextEditor::setCursorAndScrollToEnd() { - deselect(); - endOfDoc(); + deselect(); + endOfDoc(); } -void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ) -{ - *line = getLineNumFromDocIndex(mCursorPos, include_wordwrap); - *col = getLineOffsetFromDocIndex(mCursorPos, include_wordwrap); +void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ) +{ + *line = getLineNumFromDocIndex(mCursorPos, include_wordwrap); + *col = getLineOffsetFromDocIndex(mCursorPos, include_wordwrap); } void LLTextEditor::autoIndent() { - // Count the number of spaces in the current line - S32 line = getLineNumFromDocIndex(mCursorPos, false); - S32 line_start = getLineStart(line); - S32 space_count = 0; - S32 i; + // Count the number of spaces in the current line + S32 line = getLineNumFromDocIndex(mCursorPos, false); + S32 line_start = getLineStart(line); + S32 space_count = 0; + S32 i; - LLWString text = getWText(); - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - while(( ' ' == text[line_start] ) && (space_count < offset)) - { - space_count++; - line_start++; - } + LLWString text = getWText(); + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + while(( ' ' == text[line_start] ) && (space_count < offset)) + { + space_count++; + line_start++; + } - // If we're starting a braced section, indent one level. - if( (mCursorPos > 0) && (text[mCursorPos -1] == '{') ) - { - space_count += SPACES_PER_TAB; - } + // If we're starting a braced section, indent one level. + if( (mCursorPos > 0) && (text[mCursorPos -1] == '{') ) + { + space_count += SPACES_PER_TAB; + } - // Insert that number of spaces on the new line + // Insert that number of spaces on the new line - //appendLineBreakSegment(LLStyle::Params());//addChar( '\n' ); - addLineBreakChar(); + //appendLineBreakSegment(LLStyle::Params());//addChar( '\n' ); + addLineBreakChar(); - for( i = 0; i < space_count; i++ ) - { - addChar( ' ' ); - } + for( i = 0; i < space_count; i++ ) + { + addChar( ' ' ); + } } // Inserts new text at the cursor position void LLTextEditor::insertText(const std::string &new_text) { - BOOL enabled = getEnabled(); - setEnabled( TRUE ); + BOOL enabled = getEnabled(); + setEnabled( TRUE ); + + // Delete any selected characters (the insertion replaces them) + if( hasSelection() ) + { + deleteSelection(TRUE); + } - // Delete any selected characters (the insertion replaces them) - if( hasSelection() ) - { - deleteSelection(TRUE); - } + setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE, LLTextSegmentPtr() )); - setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE, LLTextSegmentPtr() )); - - setEnabled( enabled ); + setEnabled( enabled ); } void LLTextEditor::insertText(LLWString &new_text) { - BOOL enabled = getEnabled(); - setEnabled( TRUE ); + BOOL enabled = getEnabled(); + setEnabled( TRUE ); - // Delete any selected characters (the insertion replaces them) - if( hasSelection() ) - { - deleteSelection(TRUE); - } + // Delete any selected characters (the insertion replaces them) + if( hasSelection() ) + { + deleteSelection(TRUE); + } - setCursorPos(mCursorPos + insert( mCursorPos, new_text, FALSE, LLTextSegmentPtr() )); + setCursorPos(mCursorPos + insert( mCursorPos, new_text, FALSE, LLTextSegmentPtr() )); - setEnabled( enabled ); + setEnabled( enabled ); } void LLTextEditor::appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo) { - // Save old state - S32 selection_start = mSelectionStart; - S32 selection_end = mSelectionEnd; - BOOL was_selecting = mIsSelecting; - S32 cursor_pos = mCursorPos; - S32 old_length = getLength(); - BOOL cursor_was_at_end = (mCursorPos == old_length); + // Save old state + S32 selection_start = mSelectionStart; + S32 selection_end = mSelectionEnd; + BOOL was_selecting = mIsSelecting; + S32 cursor_pos = mCursorPos; + S32 old_length = getLength(); + BOOL cursor_was_at_end = (mCursorPos == old_length); - deselect(); + deselect(); - setCursorPos(old_length); + setCursorPos(old_length); - LLWString widget_wide_text = utf8str_to_wstring(text); + LLWString widget_wide_text = utf8str_to_wstring(text); - LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size()); - insert(getLength(), widget_wide_text, FALSE, segment); + LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size()); + insert(getLength(), widget_wide_text, FALSE, segment); - // Set the cursor and scroll position - if( selection_start != selection_end ) - { - mSelectionStart = selection_start; - mSelectionEnd = selection_end; + // Set the cursor and scroll position + if( selection_start != selection_end ) + { + mSelectionStart = selection_start; + mSelectionEnd = selection_end; - mIsSelecting = was_selecting; - setCursorPos(cursor_pos); - } - else if( cursor_was_at_end ) - { - setCursorPos(getLength()); - } - else - { - setCursorPos(cursor_pos); - } + mIsSelecting = was_selecting; + setCursorPos(cursor_pos); + } + else if( cursor_was_at_end ) + { + setCursorPos(getLength()); + } + else + { + setCursorPos(cursor_pos); + } - if (!allow_undo) - { - blockUndo(); - } + if (!allow_undo) + { + blockUndo(); + } } void LLTextEditor::removeTextFromEnd(S32 num_chars) { - if (num_chars <= 0) return; + if (num_chars <= 0) return; - remove(getLength() - num_chars, num_chars, FALSE); + remove(getLength() - num_chars, num_chars, FALSE); - S32 len = getLength(); - setCursorPos (llclamp(mCursorPos, 0, len)); - mSelectionStart = llclamp(mSelectionStart, 0, len); - mSelectionEnd = llclamp(mSelectionEnd, 0, len); + S32 len = getLength(); + setCursorPos (llclamp(mCursorPos, 0, len)); + mSelectionStart = llclamp(mSelectionStart, 0, len); + mSelectionEnd = llclamp(mSelectionEnd, 0, len); - needsScroll(); + needsScroll(); } //---------------------------------------------------------------------------- void LLTextEditor::onSpellCheckPerformed() { - if (isPristine()) - { - mBaseDocIsPristine = FALSE; - } + if (isPristine()) + { + mBaseDocIsPristine = FALSE; + } } void LLTextEditor::makePristine() { - mPristineCmd = mLastCmd; - mBaseDocIsPristine = !mLastCmd; + mPristineCmd = mLastCmd; + mBaseDocIsPristine = !mLastCmd; - // Create a clean partition in the undo stack. We don't want a single command to extend from - // the "pre-pristine" state to the "post-pristine" state. - if( mLastCmd ) - { - mLastCmd->blockExtensions(); - } + // Create a clean partition in the undo stack. We don't want a single command to extend from + // the "pre-pristine" state to the "post-pristine" state. + if( mLastCmd ) + { + mLastCmd->blockExtensions(); + } } BOOL LLTextEditor::isPristine() const { - if( mPristineCmd ) - { - return (mPristineCmd == mLastCmd); - } - else - { - // No undo stack, so check if the version before and commands were done was the original version - return !mLastCmd && mBaseDocIsPristine; - } + if( mPristineCmd ) + { + return (mPristineCmd == mLastCmd); + } + else + { + // No undo stack, so check if the version before and commands were done was the original version + return !mLastCmd && mBaseDocIsPristine; + } } BOOL LLTextEditor::tryToRevertToPristineState() { - if( !isPristine() ) - { - deselect(); - S32 i = 0; - while( !isPristine() && canUndo() ) - { - undo(); - i--; - } - - while( !isPristine() && canRedo() ) - { - redo(); - i++; - } - - if( !isPristine() ) - { - // failed, so go back to where we started - while( i > 0 ) - { - undo(); - i--; - } - } - } - - return isPristine(); // TRUE => success + if( !isPristine() ) + { + deselect(); + S32 i = 0; + while( !isPristine() && canUndo() ) + { + undo(); + i--; + } + + while( !isPristine() && canRedo() ) + { + redo(); + i++; + } + + if( !isPristine() ) + { + // failed, so go back to where we started + while( i > 0 ) + { + undo(); + i--; + } + } + } + + return isPristine(); // TRUE => success } void LLTextEditor::updateLinkSegments() { - LLWString wtext = getWText(); - - // update any segments that contain a link - for (segment_set_t::iterator it = mSegments.begin(); it != mSegments.end(); ++it) - { - LLTextSegment *segment = *it; - if (segment && segment->getStyle() && segment->getStyle()->isLink()) - { - LLStyleConstSP style = segment->getStyle(); - LLStyleSP new_style(new LLStyle(*style)); - LLWString url_label = wtext.substr(segment->getStart(), segment->getEnd()-segment->getStart()); - - segment_set_t::const_iterator next_it = mSegments.upper_bound(segment); - LLTextSegment *next_segment = *next_it; - if (next_segment) - { - LLWString next_url_label = wtext.substr(next_segment->getStart(), next_segment->getEnd()-next_segment->getStart()); - std::string link_check = wstring_to_utf8str(url_label) + wstring_to_utf8str(next_url_label); - LLUrlMatch match; - - if ( LLUrlRegistry::instance().findUrl(link_check, match)) - { - if(match.getQuery() == wstring_to_utf8str(next_url_label)) - { - continue; - } - } - } - - // if the link's label (what the user can edit) is a valid Url, - // then update the link's HREF to be the same as the label text. - // This lets users edit Urls in-place. - if (acceptsTextInput() && LLUrlRegistry::instance().hasUrl(url_label)) - { - std::string new_url = wstring_to_utf8str(url_label); - LLStringUtil::trim(new_url); - new_style->setLinkHREF(new_url); - LLStyleConstSP sp(new_style); - segment->setStyle(sp); - } - } - } + LLWString wtext = getWText(); + + // update any segments that contain a link + for (segment_set_t::iterator it = mSegments.begin(); it != mSegments.end(); ++it) + { + LLTextSegment *segment = *it; + if (segment && segment->getStyle() && segment->getStyle()->isLink()) + { + LLStyleConstSP style = segment->getStyle(); + LLStyleSP new_style(new LLStyle(*style)); + LLWString url_label = wtext.substr(segment->getStart(), segment->getEnd()-segment->getStart()); + + segment_set_t::const_iterator next_it = mSegments.upper_bound(segment); + LLTextSegment *next_segment = *next_it; + if (next_segment) + { + LLWString next_url_label = wtext.substr(next_segment->getStart(), next_segment->getEnd()-next_segment->getStart()); + std::string link_check = wstring_to_utf8str(url_label) + wstring_to_utf8str(next_url_label); + LLUrlMatch match; + + if ( LLUrlRegistry::instance().findUrl(link_check, match)) + { + if(match.getQuery() == wstring_to_utf8str(next_url_label)) + { + continue; + } + } + } + + // if the link's label (what the user can edit) is a valid Url, + // then update the link's HREF to be the same as the label text. + // This lets users edit Urls in-place. + if (acceptsTextInput() && LLUrlRegistry::instance().hasUrl(url_label)) + { + std::string new_url = wstring_to_utf8str(url_label); + LLStringUtil::trim(new_url); + new_style->setLinkHREF(new_url); + LLStyleConstSP sp(new_style); + segment->setStyle(sp); + } + } + } } void LLTextEditor::onMouseCaptureLost() { - endSelection(); + endSelection(); } /////////////////////////////////////////////////////////////////// @@ -2644,135 +2644,135 @@ void LLTextEditor::onMouseCaptureLost() BOOL LLTextEditor::importBuffer(const char* buffer, S32 length ) { - std::istringstream instream(buffer); - - // Version 1 format: - // Linden text version 1\n - // {\n - // - // Text length \n - // (text may contain ext_char_values) - // }\n - - char tbuf[MAX_STRING]; /* Flawfinder: ignore */ - - S32 version = 0; - instream.getline(tbuf, MAX_STRING); - if( 1 != sscanf(tbuf, "Linden text version %d", &version) ) - { - LL_WARNS() << "Invalid Linden text file header " << LL_ENDL; - return FALSE; - } - - if( 1 != version ) - { - LL_WARNS() << "Invalid Linden text file version: " << version << LL_ENDL; - return FALSE; - } - - instream.getline(tbuf, MAX_STRING); - if( 0 != sscanf(tbuf, "{") ) - { - LL_WARNS() << "Invalid Linden text file format" << LL_ENDL; - return FALSE; - } - - S32 text_len = 0; - instream.getline(tbuf, MAX_STRING); - if( 1 != sscanf(tbuf, "Text length %d", &text_len) ) - { - LL_WARNS() << "Invalid Linden text length field" << LL_ENDL; - return FALSE; - } - - if( text_len > mMaxTextByteLength ) - { - LL_WARNS() << "Invalid Linden text length: " << text_len << LL_ENDL; - return FALSE; - } - - BOOL success = TRUE; - - char* text = new char[ text_len + 1]; - if (text == NULL) - { + std::istringstream instream(buffer); + + // Version 1 format: + // Linden text version 1\n + // {\n + // + // Text length \n + // (text may contain ext_char_values) + // }\n + + char tbuf[MAX_STRING]; /* Flawfinder: ignore */ + + S32 version = 0; + instream.getline(tbuf, MAX_STRING); + if( 1 != sscanf(tbuf, "Linden text version %d", &version) ) + { + LL_WARNS() << "Invalid Linden text file header " << LL_ENDL; + return FALSE; + } + + if( 1 != version ) + { + LL_WARNS() << "Invalid Linden text file version: " << version << LL_ENDL; + return FALSE; + } + + instream.getline(tbuf, MAX_STRING); + if( 0 != sscanf(tbuf, "{") ) + { + LL_WARNS() << "Invalid Linden text file format" << LL_ENDL; + return FALSE; + } + + S32 text_len = 0; + instream.getline(tbuf, MAX_STRING); + if( 1 != sscanf(tbuf, "Text length %d", &text_len) ) + { + LL_WARNS() << "Invalid Linden text length field" << LL_ENDL; + return FALSE; + } + + if( text_len > mMaxTextByteLength ) + { + LL_WARNS() << "Invalid Linden text length: " << text_len << LL_ENDL; + return FALSE; + } + + BOOL success = TRUE; + + char* text = new char[ text_len + 1]; + if (text == NULL) + { LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS() << "Memory allocation failure." << LL_ENDL; - return FALSE; - } - instream.get(text, text_len + 1, '\0'); - text[text_len] = '\0'; - if( text_len != (S32)strlen(text) )/* Flawfinder: ignore */ - { - LL_WARNS() << llformat("Invalid text length: %d != %d ",strlen(text),text_len) << LL_ENDL;/* Flawfinder: ignore */ - success = FALSE; - } - - instream.getline(tbuf, MAX_STRING); - if( success && (0 != sscanf(tbuf, "}")) ) - { - LL_WARNS() << "Invalid Linden text file format: missing terminal }" << LL_ENDL; - success = FALSE; - } - - if( success ) - { - // Actually set the text - setText( LLStringExplicit(text) ); - } - - delete[] text; - - startOfDoc(); - deselect(); - - return success; + LL_ERRS() << "Memory allocation failure." << LL_ENDL; + return FALSE; + } + instream.get(text, text_len + 1, '\0'); + text[text_len] = '\0'; + if( text_len != (S32)strlen(text) )/* Flawfinder: ignore */ + { + LL_WARNS() << llformat("Invalid text length: %d != %d ",strlen(text),text_len) << LL_ENDL;/* Flawfinder: ignore */ + success = FALSE; + } + + instream.getline(tbuf, MAX_STRING); + if( success && (0 != sscanf(tbuf, "}")) ) + { + LL_WARNS() << "Invalid Linden text file format: missing terminal }" << LL_ENDL; + success = FALSE; + } + + if( success ) + { + // Actually set the text + setText( LLStringExplicit(text) ); + } + + delete[] text; + + startOfDoc(); + deselect(); + + return success; } BOOL LLTextEditor::exportBuffer(std::string &buffer ) { - std::ostringstream outstream(buffer); - - outstream << "Linden text version 1\n"; - outstream << "{\n"; + std::ostringstream outstream(buffer); - outstream << llformat("Text length %d\n", getLength() ); - outstream << getText(); - outstream << "}\n"; + outstream << "Linden text version 1\n"; + outstream << "{\n"; - return TRUE; + outstream << llformat("Text length %d\n", getLength() ); + outstream << getText(); + outstream << "}\n"; + + return TRUE; } void LLTextEditor::updateAllowingLanguageInput() { - LLWindow* window = getWindow(); - if (!window) - { - // test app, no window available - return; - } - if (hasFocus() && !mReadOnly) - { - window->allowLanguageTextInput(this, TRUE); - } - else - { - window->allowLanguageTextInput(this, FALSE); - } + LLWindow* window = getWindow(); + if (!window) + { + // test app, no window available + return; + } + if (hasFocus() && !mReadOnly) + { + window->allowLanguageTextInput(this, TRUE); + } + else + { + window->allowLanguageTextInput(this, FALSE); + } } // Preedit is managed off the undo/redo command stack. BOOL LLTextEditor::hasPreeditString() const { - return (mPreeditPositions.size() > 1); + return (mPreeditPositions.size() > 1); } void LLTextEditor::resetPreedit() { if (hasSelection()) { - if (hasPreeditString()) + if (hasPreeditString()) { LL_WARNS() << "Preedit and selection!" << LL_ENDL; deselect(); @@ -2782,277 +2782,277 @@ void LLTextEditor::resetPreedit() deleteSelection(TRUE); } } - if (hasPreeditString()) - { - if (hasSelection()) - { - LL_WARNS() << "Preedit and selection!" << LL_ENDL; - deselect(); - } + if (hasPreeditString()) + { + if (hasSelection()) + { + LL_WARNS() << "Preedit and selection!" << LL_ENDL; + deselect(); + } - setCursorPos(mPreeditPositions.front()); - removeStringNoUndo(mCursorPos, mPreeditPositions.back() - mCursorPos); - insertStringNoUndo(mCursorPos, mPreeditOverwrittenWString); + setCursorPos(mPreeditPositions.front()); + removeStringNoUndo(mCursorPos, mPreeditPositions.back() - mCursorPos); + insertStringNoUndo(mCursorPos, mPreeditOverwrittenWString); - mPreeditWString.clear(); - mPreeditOverwrittenWString.clear(); - mPreeditPositions.clear(); + mPreeditWString.clear(); + mPreeditOverwrittenWString.clear(); + mPreeditPositions.clear(); - // A call to updatePreedit should soon follow under a - // normal course of operation, so we don't need to - // maintain internal variables such as line start - // positions now. - } + // A call to updatePreedit should soon follow under a + // normal course of operation, so we don't need to + // maintain internal variables such as line start + // positions now. + } } void LLTextEditor::updatePreedit(const LLWString &preedit_string, - const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) + const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) { - // Just in case. - if (mReadOnly) - { - return; - } + // Just in case. + if (mReadOnly) + { + return; + } + + getWindow()->hideCursorUntilMouseMove(); - getWindow()->hideCursorUntilMouseMove(); + S32 insert_preedit_at = mCursorPos; - S32 insert_preedit_at = mCursorPos; + mPreeditWString = preedit_string; + mPreeditPositions.resize(preedit_segment_lengths.size() + 1); + S32 position = insert_preedit_at; + for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++) + { + mPreeditPositions[i] = position; + position += preedit_segment_lengths[i]; + } + mPreeditPositions.back() = position; - mPreeditWString = preedit_string; - mPreeditPositions.resize(preedit_segment_lengths.size() + 1); - S32 position = insert_preedit_at; - for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++) - { - mPreeditPositions[i] = position; - position += preedit_segment_lengths[i]; - } - mPreeditPositions.back() = position; + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + mPreeditOverwrittenWString = getWText().substr(insert_preedit_at, mPreeditWString.length()); + removeStringNoUndo(insert_preedit_at, mPreeditWString.length()); + } + else + { + mPreeditOverwrittenWString.clear(); + } - if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - mPreeditOverwrittenWString = getWText().substr(insert_preedit_at, mPreeditWString.length()); - removeStringNoUndo(insert_preedit_at, mPreeditWString.length()); - } - else - { - mPreeditOverwrittenWString.clear(); - } - - segment_vec_t segments; - //pass empty segments to let "insertStringNoUndo" make new LLNormalTextSegment and insert it, if needed. - insertStringNoUndo(insert_preedit_at, mPreeditWString, &segments); + segment_vec_t segments; + //pass empty segments to let "insertStringNoUndo" make new LLNormalTextSegment and insert it, if needed. + insertStringNoUndo(insert_preedit_at, mPreeditWString, &segments); - mPreeditStandouts = preedit_standouts; + mPreeditStandouts = preedit_standouts; - setCursorPos(insert_preedit_at + caret_position); + setCursorPos(insert_preedit_at + caret_position); - // Update of the preedit should be caused by some key strokes. - resetCursorBlink(); + // Update of the preedit should be caused by some key strokes. + resetCursorBlink(); - onKeyStroke(); + onKeyStroke(); } BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const { - if (control) - { - LLRect control_rect_screen; - localRectToScreen(mVisibleTextRect, &control_rect_screen); - LLUI::getInstance()->screenRectToGL(control_rect_screen, control); - } - - S32 preedit_left_position, preedit_right_position; - if (hasPreeditString()) - { - preedit_left_position = mPreeditPositions.front(); - preedit_right_position = mPreeditPositions.back(); - } - else - { - preedit_left_position = preedit_right_position = mCursorPos; - } - - const S32 query = (query_offset >= 0 ? preedit_left_position + query_offset : mCursorPos); - if (query < preedit_left_position || query > preedit_right_position) - { - return FALSE; - } - - const S32 first_visible_line = getFirstVisibleLine(); - if (query < getLineStart(first_visible_line)) - { - return FALSE; - } - - S32 current_line = first_visible_line; - S32 current_line_start, current_line_end; - for (;;) - { - current_line_start = getLineStart(current_line); - current_line_end = getLineStart(current_line + 1); - if (query >= current_line_start && query < current_line_end) - { - break; - } - if (current_line_start == current_line_end) - { - // We have reached on the last line. The query position must be here. - break; - } - current_line++; - } + if (control) + { + LLRect control_rect_screen; + localRectToScreen(mVisibleTextRect, &control_rect_screen); + LLUI::getInstance()->screenRectToGL(control_rect_screen, control); + } + + S32 preedit_left_position, preedit_right_position; + if (hasPreeditString()) + { + preedit_left_position = mPreeditPositions.front(); + preedit_right_position = mPreeditPositions.back(); + } + else + { + preedit_left_position = preedit_right_position = mCursorPos; + } + + const S32 query = (query_offset >= 0 ? preedit_left_position + query_offset : mCursorPos); + if (query < preedit_left_position || query > preedit_right_position) + { + return FALSE; + } + + const S32 first_visible_line = getFirstVisibleLine(); + if (query < getLineStart(first_visible_line)) + { + return FALSE; + } + + S32 current_line = first_visible_line; + S32 current_line_start, current_line_end; + for (;;) + { + current_line_start = getLineStart(current_line); + current_line_end = getLineStart(current_line + 1); + if (query >= current_line_start && query < current_line_end) + { + break; + } + if (current_line_start == current_line_end) + { + // We have reached on the last line. The query position must be here. + break; + } + current_line++; + } const LLWString textString(getWText()); - const llwchar * const text = textString.c_str(); - const S32 line_height = mFont->getLineHeight(); - - if (coord) - { - const S32 query_x = mVisibleTextRect.mLeft + mFont->getWidth(text, current_line_start, query - current_line_start); - const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2; - S32 query_screen_x, query_screen_y; - localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y); - LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); - } - - if (bounds) - { - S32 preedit_left = mVisibleTextRect.mLeft; - if (preedit_left_position > current_line_start) - { - preedit_left += mFont->getWidth(text, current_line_start, preedit_left_position - current_line_start); - } - - S32 preedit_right = mVisibleTextRect.mLeft; - if (preedit_right_position < current_line_end) - { - preedit_right += mFont->getWidth(text, current_line_start, preedit_right_position - current_line_start); - } - else - { - preedit_right += mFont->getWidth(text, current_line_start, current_line_end - current_line_start); - } - - const S32 preedit_top = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height; - const S32 preedit_bottom = preedit_top - line_height; - - const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom); - LLRect preedit_rect_screen; - localRectToScreen(preedit_rect_local, &preedit_rect_screen); - LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds); - } - - return TRUE; + const llwchar * const text = textString.c_str(); + const S32 line_height = mFont->getLineHeight(); + + if (coord) + { + const S32 query_x = mVisibleTextRect.mLeft + mFont->getWidth(text, current_line_start, query - current_line_start); + const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2; + S32 query_screen_x, query_screen_y; + localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y); + LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); + } + + if (bounds) + { + S32 preedit_left = mVisibleTextRect.mLeft; + if (preedit_left_position > current_line_start) + { + preedit_left += mFont->getWidth(text, current_line_start, preedit_left_position - current_line_start); + } + + S32 preedit_right = mVisibleTextRect.mLeft; + if (preedit_right_position < current_line_end) + { + preedit_right += mFont->getWidth(text, current_line_start, preedit_right_position - current_line_start); + } + else + { + preedit_right += mFont->getWidth(text, current_line_start, current_line_end - current_line_start); + } + + const S32 preedit_top = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height; + const S32 preedit_bottom = preedit_top - line_height; + + const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom); + LLRect preedit_rect_screen; + localRectToScreen(preedit_rect_local, &preedit_rect_screen); + LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds); + } + + return TRUE; } void LLTextEditor::getSelectionRange(S32 *position, S32 *length) const { - if (hasSelection()) - { - *position = llmin(mSelectionStart, mSelectionEnd); - *length = llabs(mSelectionStart - mSelectionEnd); - } - else - { - *position = mCursorPos; - *length = 0; - } + if (hasSelection()) + { + *position = llmin(mSelectionStart, mSelectionEnd); + *length = llabs(mSelectionStart - mSelectionEnd); + } + else + { + *position = mCursorPos; + *length = 0; + } } void LLTextEditor::getPreeditRange(S32 *position, S32 *length) const { - if (hasPreeditString()) - { - *position = mPreeditPositions.front(); - *length = mPreeditPositions.back() - mPreeditPositions.front(); - } - else - { - *position = mCursorPos; - *length = 0; - } + if (hasPreeditString()) + { + *position = mPreeditPositions.front(); + *length = mPreeditPositions.back() - mPreeditPositions.front(); + } + else + { + *position = mCursorPos; + *length = 0; + } } void LLTextEditor::markAsPreedit(S32 position, S32 length) { - deselect(); - setCursorPos(position); - if (hasPreeditString()) - { - LL_WARNS() << "markAsPreedit invoked when hasPreeditString is true." << LL_ENDL; - } - mPreeditWString = LLWString( getWText(), position, length ); - if (length > 0) - { - mPreeditPositions.resize(2); - mPreeditPositions[0] = position; - mPreeditPositions[1] = position + length; - mPreeditStandouts.resize(1); - mPreeditStandouts[0] = FALSE; - } - else - { - mPreeditPositions.clear(); - mPreeditStandouts.clear(); - } - if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - mPreeditOverwrittenWString = mPreeditWString; - } - else - { - mPreeditOverwrittenWString.clear(); - } + deselect(); + setCursorPos(position); + if (hasPreeditString()) + { + LL_WARNS() << "markAsPreedit invoked when hasPreeditString is true." << LL_ENDL; + } + mPreeditWString = LLWString( getWText(), position, length ); + if (length > 0) + { + mPreeditPositions.resize(2); + mPreeditPositions[0] = position; + mPreeditPositions[1] = position + length; + mPreeditStandouts.resize(1); + mPreeditStandouts[0] = FALSE; + } + else + { + mPreeditPositions.clear(); + mPreeditStandouts.clear(); + } + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + mPreeditOverwrittenWString = mPreeditWString; + } + else + { + mPreeditOverwrittenWString.clear(); + } } S32 LLTextEditor::getPreeditFontSize() const { - return ll_round((F32)mFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); + return ll_round((F32)mFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); } BOOL LLTextEditor::isDirty() const { - if(mReadOnly) - { - return FALSE; - } + if(mReadOnly) + { + return FALSE; + } - if( mPristineCmd ) - { - return ( mPristineCmd == mLastCmd ); - } - else - { - return ( NULL != mLastCmd ); - } + if( mPristineCmd ) + { + return ( mPristineCmd == mLastCmd ); + } + else + { + return ( NULL != mLastCmd ); + } } void LLTextEditor::setKeystrokeCallback(const keystroke_signal_t::slot_type& callback) { - mKeystrokeSignal.connect(callback); + mKeystrokeSignal.connect(callback); } void LLTextEditor::onKeyStroke() { - mKeystrokeSignal(this); + mKeystrokeSignal(this); - mSpellCheckStart = mSpellCheckEnd = -1; - mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); + mSpellCheckStart = mSpellCheckEnd = -1; + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } //virtual void LLTextEditor::clear() { - getViewModel()->setDisplay(LLWStringUtil::null); - clearSegments(); + getViewModel()->setDisplay(LLWStringUtil::null); + clearSegments(); } bool LLTextEditor::canLoadOrSaveToFile() { - return !mReadOnly; + return !mReadOnly; } S32 LLTextEditor::spacesPerTab() { - return SPACES_PER_TAB; + return SPACES_PER_TAB; } diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 658bfb9295..2bc4184ca8 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -48,316 +48,316 @@ class LLUICtrlFactory; class LLScrollContainer; class LLTextEditor : - public LLTextBase, - protected LLPreeditor + public LLTextBase, + protected LLPreeditor { public: - struct Params : public LLInitParam::Block - { - Optional default_text; - Optional prevalidate_callback; - - Optional embedded_items, - ignore_tab, - commit_on_focus_lost, - show_context_menu, - show_emoji_helper, - enable_tooltip_paste, - auto_indent; - - //colors - Optional default_color; - - Params(); - }; - - void initFromParams(const Params&); + struct Params : public LLInitParam::Block + { + Optional default_text; + Optional prevalidate_callback; + + Optional embedded_items, + ignore_tab, + commit_on_focus_lost, + show_context_menu, + show_emoji_helper, + enable_tooltip_paste, + auto_indent; + + //colors + Optional default_color; + + Params(); + }; + + void initFromParams(const Params&); protected: - LLTextEditor(const Params&); - friend class LLUICtrlFactory; + LLTextEditor(const Params&); + friend class LLUICtrlFactory; public: - // - // Constants - // - static const llwchar FIRST_EMBEDDED_CHAR = 0x100000; - static const llwchar LAST_EMBEDDED_CHAR = 0x10ffff; - static const S32 MAX_EMBEDDED_ITEMS = LAST_EMBEDDED_CHAR - FIRST_EMBEDDED_CHAR + 1; + // + // Constants + // + static const llwchar FIRST_EMBEDDED_CHAR = 0x100000; + static const llwchar LAST_EMBEDDED_CHAR = 0x10ffff; + static const S32 MAX_EMBEDDED_ITEMS = LAST_EMBEDDED_CHAR - FIRST_EMBEDDED_CHAR + 1; - virtual ~LLTextEditor(); + virtual ~LLTextEditor(); - typedef boost::signals2::signal keystroke_signal_t; + typedef boost::signals2::signal keystroke_signal_t; - void setKeystrokeCallback(const keystroke_signal_t::slot_type& callback); + void setKeystrokeCallback(const keystroke_signal_t::slot_type& callback); - void setParseHighlights(BOOL parsing) {mParseHighlights=parsing;} + void setParseHighlights(BOOL parsing) {mParseHighlights=parsing;} - static S32 spacesPerTab(); + static S32 spacesPerTab(); - void insertEmoji(llwchar emoji); - void handleEmojiCommit(llwchar emoji); + void insertEmoji(llwchar emoji); + void handleEmojiCommit(llwchar emoji); - // mousehandler overrides - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask ); - virtual BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask); + // mousehandler overrides + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask ); + virtual BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask); - virtual BOOL handleKeyHere(KEY key, MASK mask ); - virtual BOOL handleUnicodeCharHere(llwchar uni_char); + virtual BOOL handleKeyHere(KEY key, MASK mask ); + virtual BOOL handleUnicodeCharHere(llwchar uni_char); - virtual void onMouseCaptureLost(); + virtual void onMouseCaptureLost(); - // view overrides - virtual void draw(); - virtual void onFocusReceived(); - virtual void onFocusLost(); - virtual void onCommit(); - virtual void setEnabled(BOOL enabled); + // view overrides + virtual void draw(); + virtual void onFocusReceived(); + virtual void onFocusLost(); + virtual void onCommit(); + virtual void setEnabled(BOOL enabled); - // uictrl overrides - virtual void clear(); - virtual void setFocus( BOOL b ); - virtual BOOL isDirty() const; + // uictrl overrides + virtual void clear(); + virtual void setFocus( BOOL b ); + virtual BOOL isDirty() const; - // LLEditMenuHandler interface - virtual void undo(); - virtual BOOL canUndo() const; - virtual void redo(); - virtual BOOL canRedo() const; + // LLEditMenuHandler interface + virtual void undo(); + virtual BOOL canUndo() const; + virtual void redo(); + virtual BOOL canRedo() const; - virtual void cut(); - virtual BOOL canCut() const; - virtual void copy(); - virtual BOOL canCopy() const; - virtual void paste(); - virtual BOOL canPaste() const; + virtual void cut(); + virtual BOOL canCut() const; + virtual void copy(); + virtual BOOL canCopy() const; + virtual void paste(); + virtual BOOL canPaste() const; - virtual void updatePrimary(); - virtual void copyPrimary(); - virtual void pastePrimary(); - virtual BOOL canPastePrimary() const; + virtual void updatePrimary(); + virtual void copyPrimary(); + virtual void pastePrimary(); + virtual BOOL canPastePrimary() const; - virtual void doDelete(); - virtual BOOL canDoDelete() const; - virtual void selectAll(); - virtual BOOL canSelectAll() const; + virtual void doDelete(); + virtual BOOL canDoDelete() const; + virtual void selectAll(); + virtual BOOL canSelectAll() const; - void selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos); + void selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos); - virtual bool canLoadOrSaveToFile(); + virtual bool canLoadOrSaveToFile(); - void selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap = TRUE); - BOOL replaceText(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive, BOOL wrap = TRUE); - void replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive); + void selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap = TRUE); + BOOL replaceText(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive, BOOL wrap = TRUE); + void replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive); - // Undo/redo stack - void blockUndo(); + // Undo/redo stack + void blockUndo(); - // Text editing - virtual void makePristine(); - BOOL isPristine() const; - BOOL allowsEmbeddedItems() const { return mAllowEmbeddedItems; } + // Text editing + virtual void makePristine(); + BOOL isPristine() const; + BOOL allowsEmbeddedItems() const { return mAllowEmbeddedItems; } - // Autoreplace (formerly part of LLLineEditor) - typedef boost::function autoreplace_callback_t; - autoreplace_callback_t mAutoreplaceCallback; - void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; } + // Autoreplace (formerly part of LLLineEditor) + typedef boost::function autoreplace_callback_t; + autoreplace_callback_t mAutoreplaceCallback; + void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; } - /*virtual*/ void onSpellCheckPerformed(); + /*virtual*/ void onSpellCheckPerformed(); - // - // Text manipulation - // + // + // Text manipulation + // - // inserts text at cursor - void insertText(const std::string &text); - void insertText(LLWString &text); + // inserts text at cursor + void insertText(const std::string &text); + void insertText(LLWString &text); - void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo); - // Non-undoable - void setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params = LLStyle::Params()); + void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo); + // Non-undoable + void setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params = LLStyle::Params()); - // Removes text from the end of document - // Does not change highlight or cursor position. - void removeTextFromEnd(S32 num_chars); + // Removes text from the end of document + // Does not change highlight or cursor position. + void removeTextFromEnd(S32 num_chars); - BOOL tryToRevertToPristineState(); + BOOL tryToRevertToPristineState(); - void setCursorAndScrollToEnd(); + void setCursorAndScrollToEnd(); - void getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ); + void getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ); - // Hacky methods to make it into a word-wrapping, potentially scrolling, - // read-only text box. - void setCommitOnFocusLost(BOOL b) { mCommitOnFocusLost = b; } + // Hacky methods to make it into a word-wrapping, potentially scrolling, + // read-only text box. + void setCommitOnFocusLost(BOOL b) { mCommitOnFocusLost = b; } - // Hack to handle Notecards - virtual BOOL importBuffer(const char* buffer, S32 length ); - virtual BOOL exportBuffer(std::string& buffer ); + // Hack to handle Notecards + virtual BOOL importBuffer(const char* buffer, S32 length ); + virtual BOOL exportBuffer(std::string& buffer ); - const LLUUID& getSourceID() const { return mSourceID; } + const LLUUID& getSourceID() const { return mSourceID; } - const LLTextSegmentPtr getPreviousSegment() const; - const LLTextSegmentPtr getLastSegment() const; - void getSelectedSegments(segment_vec_t& segments) const; + const LLTextSegmentPtr getPreviousSegment() const; + const LLTextSegmentPtr getLastSegment() const; + void getSelectedSegments(segment_vec_t& segments) const; - void setShowContextMenu(bool show) { mShowContextMenu = show; } - bool getShowContextMenu() const { return mShowContextMenu; } + void setShowContextMenu(bool show) { mShowContextMenu = show; } + bool getShowContextMenu() const { return mShowContextMenu; } - void showEmojiHelper(); - void setShowEmojiHelper(bool show); - bool getShowEmojiHelper() const { return mShowEmojiHelper; } + void showEmojiHelper(); + void setShowEmojiHelper(bool show); + bool getShowEmojiHelper() const { return mShowEmojiHelper; } - void setPassDelete(BOOL b) { mPassDelete = b; } + void setPassDelete(BOOL b) { mPassDelete = b; } protected: - void showContextMenu(S32 x, S32 y); - void drawPreeditMarker(); + void showContextMenu(S32 x, S32 y); + void drawPreeditMarker(); - void assignEmbedded(const std::string &s); + void assignEmbedded(const std::string &s); - void removeCharOrTab(); + void removeCharOrTab(); - void indentSelectedLines( S32 spaces ); - S32 indentLine( S32 pos, S32 spaces ); - void unindentLineBeforeCloseBrace(); + void indentSelectedLines( S32 spaces ); + S32 indentLine( S32 pos, S32 spaces ); + void unindentLineBeforeCloseBrace(); - virtual BOOL handleSpecialKey(const KEY key, const MASK mask); - BOOL handleNavigationKey(const KEY key, const MASK mask); - BOOL handleSelectionKey(const KEY key, const MASK mask); - BOOL handleControlKey(const KEY key, const MASK mask); + virtual BOOL handleSpecialKey(const KEY key, const MASK mask); + BOOL handleNavigationKey(const KEY key, const MASK mask); + BOOL handleSelectionKey(const KEY key, const MASK mask); + BOOL handleControlKey(const KEY key, const MASK mask); - BOOL selectionContainsLineBreaks(); - void deleteSelection(BOOL transient_operation); + BOOL selectionContainsLineBreaks(); + void deleteSelection(BOOL transient_operation); - S32 prevWordPos(S32 cursorPos) const; - S32 nextWordPos(S32 cursorPos) const; + S32 prevWordPos(S32 cursorPos) const; + S32 nextWordPos(S32 cursorPos) const; - void autoIndent(); + void autoIndent(); - void findEmbeddedItemSegments(S32 start, S32 end); - void getSegmentsInRange(segment_vec_t& segments, S32 start, S32 end, bool include_partial) const; + void findEmbeddedItemSegments(S32 start, S32 end); + void getSegmentsInRange(segment_vec_t& segments, S32 start, S32 end, bool include_partial) const; - virtual llwchar pasteEmbeddedItem(llwchar ext_char) { return ext_char; } + virtual llwchar pasteEmbeddedItem(llwchar ext_char) { return ext_char; } - // Here's the method that takes and applies text commands. - S32 execute(TextCmd* cmd); + // Here's the method that takes and applies text commands. + S32 execute(TextCmd* cmd); - // Undoable operations - void addChar(llwchar c); // at mCursorPos - S32 addChar(S32 pos, llwchar wc); + // Undoable operations + void addChar(llwchar c); // at mCursorPos + S32 addChar(S32 pos, llwchar wc); public: - void addLineBreakChar(BOOL group_together = FALSE); + void addLineBreakChar(BOOL group_together = FALSE); protected: - S32 overwriteChar(S32 pos, llwchar wc); - void removeChar(); - S32 removeChar(S32 pos); - S32 insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment); - S32 remove(S32 pos, S32 length, bool group_with_next_op); - - void tryToShowEmojiHelper(); - void focusLostHelper(); - void updateAllowingLanguageInput(); - BOOL hasPreeditString() const; - - // Overrides LLPreeditor - virtual void resetPreedit(); - virtual void updatePreedit(const LLWString &preedit_string, - const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position); - virtual void markAsPreedit(S32 position, S32 length); - virtual void getPreeditRange(S32 *position, S32 *length) const; - virtual void getSelectionRange(S32 *position, S32 *length) const; - virtual BOOL getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const; - virtual S32 getPreeditFontSize() const; - virtual LLWString getPreeditString() const { return getWText(); } - // - // Protected data - // - // Probably deserves serious thought to hiding as many of these - // as possible behind protected accessor methods. - // - - // Use these to determine if a click on an embedded item is a drag or not. - S32 mMouseDownX; - S32 mMouseDownY; - - LLWString mPreeditWString; - LLWString mPreeditOverwrittenWString; - std::vector mPreeditPositions; - std::vector mPreeditStandouts; + S32 overwriteChar(S32 pos, llwchar wc); + void removeChar(); + S32 removeChar(S32 pos); + S32 insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment); + S32 remove(S32 pos, S32 length, bool group_with_next_op); + + void tryToShowEmojiHelper(); + void focusLostHelper(); + void updateAllowingLanguageInput(); + BOOL hasPreeditString() const; + + // Overrides LLPreeditor + virtual void resetPreedit(); + virtual void updatePreedit(const LLWString &preedit_string, + const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position); + virtual void markAsPreedit(S32 position, S32 length); + virtual void getPreeditRange(S32 *position, S32 *length) const; + virtual void getSelectionRange(S32 *position, S32 *length) const; + virtual BOOL getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const; + virtual S32 getPreeditFontSize() const; + virtual LLWString getPreeditString() const { return getWText(); } + // + // Protected data + // + // Probably deserves serious thought to hiding as many of these + // as possible behind protected accessor methods. + // + + // Use these to determine if a click on an embedded item is a drag or not. + S32 mMouseDownX; + S32 mMouseDownY; + + LLWString mPreeditWString; + LLWString mPreeditOverwrittenWString; + std::vector mPreeditPositions; + std::vector mPreeditStandouts; protected: - LLUIColor mDefaultColor; + LLUIColor mDefaultColor; - bool mAutoIndent; - bool mParseOnTheFly; + bool mAutoIndent; + bool mParseOnTheFly; - void updateLinkSegments(); - void keepSelectionOnReturn(bool keep) { mKeepSelectionOnReturn = keep; } - class LLViewBorder* mBorder; + void updateLinkSegments(); + void keepSelectionOnReturn(bool keep) { mKeepSelectionOnReturn = keep; } + class LLViewBorder* mBorder; private: - // - // Methods - // - void pasteHelper(bool is_primary); - void cleanStringForPaste(LLWString & clean_string); + // + // Methods + // + void pasteHelper(bool is_primary); + void cleanStringForPaste(LLWString & clean_string); public: - template - void pasteTextWithLinebreaks(const STRINGTYPE& clean_string) - { - pasteTextWithLinebreaks(ll_convert(clean_string)); - } - template <> - void pasteTextWithLinebreaks(const LLWString & clean_string); + template + void pasteTextWithLinebreaks(const STRINGTYPE& clean_string) + { + pasteTextWithLinebreaks(ll_convert(clean_string)); + } + template <> + void pasteTextWithLinebreaks(const LLWString & clean_string); private: - void onKeyStroke(); + void onKeyStroke(); - // Concrete TextCmd sub-classes used by the LLTextEditor base class - class TextCmdInsert; - class TextCmdAddChar; - class TextCmdOverwriteChar; - class TextCmdRemove; + // Concrete TextCmd sub-classes used by the LLTextEditor base class + class TextCmdInsert; + class TextCmdAddChar; + class TextCmdOverwriteChar; + class TextCmdRemove; - BOOL mBaseDocIsPristine; - TextCmd* mPristineCmd; + BOOL mBaseDocIsPristine; + TextCmd* mPristineCmd; - TextCmd* mLastCmd; + TextCmd* mLastCmd; - typedef std::deque undo_stack_t; - undo_stack_t mUndoStack; + typedef std::deque undo_stack_t; + undo_stack_t mUndoStack; - BOOL mTabsToNextField; // if true, tab moves focus to next field, else inserts spaces - BOOL mCommitOnFocusLost; - BOOL mTakesFocus; + BOOL mTabsToNextField; // if true, tab moves focus to next field, else inserts spaces + BOOL mCommitOnFocusLost; + BOOL mTakesFocus; - BOOL mAllowEmbeddedItems; - bool mShowContextMenu; - bool mShowEmojiHelper; - bool mEnableTooltipPaste; - bool mPassDelete; - bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter + BOOL mAllowEmbeddedItems; + bool mShowContextMenu; + bool mShowEmojiHelper; + bool mEnableTooltipPaste; + bool mPassDelete; + bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter - LLUUID mSourceID; + LLUUID mSourceID; - LLCoordGL mLastIMEPosition; // Last position of the IME editor + LLCoordGL mLastIMEPosition; // Last position of the IME editor - keystroke_signal_t mKeystrokeSignal; - LLTextValidate::validate_func_t mPrevalidateFunc; + keystroke_signal_t mKeystrokeSignal; + LLTextValidate::validate_func_t mPrevalidateFunc; - LLHandle mContextMenuHandle; + LLHandle mContextMenuHandle; }; // end class LLTextEditor // Build time optimization, generate once in .cpp file #ifndef LLTEXTEDITOR_CPP extern template class LLTextEditor* LLView::getChild( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; #endif #endif // LL_TEXTEDITOR_H -- cgit v1.2.3 From 65bd23651d97722cd3777c2716c010ee14bd9ec7 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 15 May 2024 13:46:57 -0400 Subject: Fix missing #include in lltextvalidate.cpp --- indra/llui/lltextvalidate.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/llui') diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp index 9e27ed6232..10b3be1c23 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 -- cgit v1.2.3 From c808d849aa6aa17db95a7814e6eb6bc5162ba816 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 16 May 2024 02:29:52 +0300 Subject: adjust the flag to be untrusted block/allow/throttle --- indra/llui/llmenugl.h | 8 ++++---- indra/llui/lluictrl.h | 15 +++++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 1dcf79d02c..a906663d0e 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -950,17 +950,17 @@ 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, bool allow_untrusted = false) + static void addCommit(view_listener_t *listener, const std::string &name, LLUICtrl::LLCommitCallbackInfo::EUntrustedCall handle_untrusted = LLUICtrl::LLCommitCallbackInfo::UNTRUSTED_BLOCK) { LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(name, - LLUICtrl::LLCommitCallbackInfo(boost::bind(&view_listener_t::handleEvent, listener, _2), allow_untrusted)); + LLUICtrl::LLCommitCallbackInfo(boost::bind(&view_listener_t::handleEvent, listener, _2), handle_untrusted)); } - static void addMenu(view_listener_t* listener, const std::string& name, bool allow_untrusted = true) + static void addMenu(view_listener_t *listener, const std::string &name, LLUICtrl::LLCommitCallbackInfo::EUntrustedCall handle_untrusted = LLUICtrl::LLCommitCallbackInfo::UNTRUSTED_BLOCK) { // For now, add to both click and enable registries addEnable(listener, name); - addCommit(listener, name, allow_untrusted); + addCommit(listener, name, handle_untrusted); } static void cleanup() diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 5039d3e22c..ca8b66cfca 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -285,13 +285,20 @@ public: struct LLCommitCallbackInfo { - LLCommitCallbackInfo(commit_callback_t func = NULL, bool allow_untrusted = false) - : callback_func(func), mAllowUntrusted(allow_untrusted) + enum EUntrustedCall + { + UNTRUSTED_ALLOW, + UNTRUSTED_BLOCK, + UNTRUSTED_THROTTLE + }; + + LLCommitCallbackInfo(commit_callback_t func = NULL, EUntrustedCall handle_untrusted = UNTRUSTED_ALLOW) + : callback_func(func), mHandleUntrusted(handle_untrusted) {} public: - bool mAllowUntrusted; - commit_callback_t callback_func; + EUntrustedCall mHandleUntrusted; + commit_callback_t callback_func; }; class SharedCommitCallbackRegistry : public CallbackRegistry -- cgit v1.2.3 From 83d91c82f42f6c024e7e4dc6d6a64b067ad6117a Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 16 May 2024 04:16:29 +0300 Subject: set UNTRUSTED_ALLOW as default; some LLCommitCallbackInfo clean up --- indra/llui/llmenugl.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 708010a067..79f83b5773 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -950,15 +950,14 @@ 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, - LLUICtrl::LLCommitCallbackInfo::EUntrustedCall handle_untrusted = LLUICtrl::LLCommitCallbackInfo::UNTRUSTED_BLOCK) + typedef LLUICtrl::LLCommitCallbackInfo cb_info; + static void addCommit(view_listener_t *listener, const std::string &name, cb_info::EUntrustedCall handle_untrusted = cb_info::UNTRUSTED_ALLOW) { LLUICtrl::SharedCommitCallbackRegistry::currentRegistrar().add(name, - LLUICtrl::LLCommitCallbackInfo(boost::bind(&view_listener_t::handleEvent, listener, _2), handle_untrusted)); + cb_info(boost::bind(&view_listener_t::handleEvent, listener, _2), handle_untrusted)); } - static void addMenu(view_listener_t *listener, const std::string &name, - LLUICtrl::LLCommitCallbackInfo::EUntrustedCall handle_untrusted = LLUICtrl::LLCommitCallbackInfo::UNTRUSTED_BLOCK) + 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); -- cgit v1.2.3 From 0f00dc2f658869cc73a18b03b024a6cc88964e0b Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Wed, 22 May 2024 20:29:55 +0300 Subject: Add support for sending messages to Nearby chat from Lua script --- indra/llui/llchat.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'indra/llui') diff --git a/indra/llui/llchat.h b/indra/llui/llchat.h index 56105add7e..8fd92c2550 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,9 @@ public: std::string mURL; EChatStyle mChatStyle; LLUUID mSessionID; + + bool mIsScript; }; +static const std::string LUA_PREFIX("[LUA]"); #endif -- cgit v1.2.3 From b0ef843fe0702482e843379b4975b2dda4d58935 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 24 May 2024 09:22:40 -0400 Subject: Nat's ideas from PR #1547 --- indra/llui/llchat.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'indra/llui') diff --git a/indra/llui/llchat.h b/indra/llui/llchat.h index 8fd92c2550..70d7e82970 100644 --- a/indra/llui/llchat.h +++ b/indra/llui/llchat.h @@ -113,4 +113,17 @@ public: }; 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 -- cgit v1.2.3 From f08a3c80d61795bb1fc0e576948bca3362ef8e6c Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Fri, 31 May 2024 20:03:13 +0300 Subject: Cherry-pick leap.lua changes; other clean up --- indra/llui/llmenugl.h | 4 ++-- indra/llui/lluictrl.cpp | 2 +- indra/llui/lluictrl.h | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 79f83b5773..98b76c08ff 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -950,11 +950,11 @@ public: LLUICtrl::EnableCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); } - typedef LLUICtrl::LLCommitCallbackInfo cb_info; + 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::SharedCommitCallbackRegistry::currentRegistrar().add(name, - cb_info(boost::bind(&view_listener_t::handleEvent, listener, _2), handle_untrusted)); + cb_info([listener](LLUICtrl*, const LLSD& param){ return listener->handleEvent(param); }, handle_untrusted)); } static void addMenu(view_listener_t *listener, const std::string &name, cb_info::EUntrustedCall handle_untrusted = cb_info::UNTRUSTED_ALLOW) diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 0fa43081ba..6082a8f771 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -284,7 +284,7 @@ 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)); - LLUICtrl::LLCommitCallbackInfo *info = LLUICtrl::SharedCommitCallbackRegistry::getValue(function_name); + LLUICtrl::CommitCallbackInfo *info = LLUICtrl::SharedCommitCallbackRegistry::getValue(function_name); if (func) { if (cb.parameter.isProvided()) diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 790c483aee..e507178d89 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -284,7 +284,7 @@ public: LLSINGLETON_EMPTY_CTOR(EnableCallbackRegistry); }; - struct LLCommitCallbackInfo + struct CommitCallbackInfo { enum EUntrustedCall { @@ -293,16 +293,16 @@ public: UNTRUSTED_THROTTLE }; - LLCommitCallbackInfo(commit_callback_t func = NULL, EUntrustedCall handle_untrusted = UNTRUSTED_ALLOW) - : callback_func(func), mHandleUntrusted(handle_untrusted) + CommitCallbackInfo(commit_callback_t func = {}, EUntrustedCall handle_untrusted = UNTRUSTED_ALLOW) + : callback_func(func), handle_untrusted(handle_untrusted) {} public: - EUntrustedCall mHandleUntrusted; commit_callback_t callback_func; + EUntrustedCall handle_untrusted; }; - class SharedCommitCallbackRegistry : public CallbackRegistry + class SharedCommitCallbackRegistry : public CallbackRegistry { LLSINGLETON_EMPTY_CTOR(SharedCommitCallbackRegistry); }; -- cgit v1.2.3 From ad608dbc5f0d57ad29ec3a15e4d0a434dfaa38d2 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Mon, 10 Jun 2024 14:29:22 +0300 Subject: Remove SharedCommitCallbackRegistry; add helpers CommitRegistrarHelper and ScopedRegistrarHelper --- indra/llui/llmenugl.h | 2 +- indra/llui/llnotifications.cpp | 2 +- indra/llui/llscrolllistctrl.cpp | 2 +- indra/llui/lltextbase.cpp | 2 +- indra/llui/lltoolbar.cpp | 2 +- indra/llui/llui.cpp | 3 +-- indra/llui/lluictrl.cpp | 18 ++++--------- indra/llui/lluictrl.h | 56 ++++++++++++++++++++++++++++------------- 8 files changed, 50 insertions(+), 37 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 98b76c08ff..baa6e9624d 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -953,7 +953,7 @@ public: 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::SharedCommitCallbackRegistry::currentRegistrar().add(name, + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, cb_info([listener](LLUICtrl*, const LLSD& param){ return listener->handleEvent(param); }, handle_untrusted)); } diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 2fbae73b65..7905ff7ce0 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::instanceCount(); diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 7fb732eca3..d32af15f0c 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1991,7 +1991,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 c1eedf93a7..32b28834b2 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -2085,7 +2085,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/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index 8a6cb683d2..cb9539a573 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 c7539fcec7..07a962e515 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -167,8 +167,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", boost::bind(&LLFloaterReg::toggleInstance, _2, LLSD())); reg.add("Floater.ToggleOrBringToFront", boost::bind(&LLFloaterReg::toggleInstanceOrBringToFront, _2, LLSD())); diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 6082a8f771..68d15eb424 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,16 +283,8 @@ 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)); - LLUICtrl::CommitCallbackInfo *info = LLUICtrl::SharedCommitCallbackRegistry::getValue(function_name); - if (func) - { - if (cb.parameter.isProvided()) - return boost::bind((*func), _1, cb.parameter); - else - return commit_signal_t::slot_type(*func); - } - else if (info && info->callback_func) + LLUICtrl::CommitCallbackInfo *info = (CommitCallbackRegistry::getValue(function_name)); + if (info && info->callback_func) { if (cb.parameter.isProvided()) return boost::bind((info->callback_func), _1, cb.parameter); diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index e507178d89..46d651b19c 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -273,17 +273,6 @@ public: template class CallbackRegistry : public LLRegistrySingleton {}; - - class CommitCallbackRegistry : public CallbackRegistry - { - LLSINGLETON_EMPTY_CTOR(CommitCallbackRegistry); - }; - // the enable callback registry is also used for visiblity callbacks - class EnableCallbackRegistry : public CallbackRegistry - { - LLSINGLETON_EMPTY_CTOR(EnableCallbackRegistry); - }; - struct CommitCallbackInfo { enum EUntrustedCall @@ -293,18 +282,51 @@ public: UNTRUSTED_THROTTLE }; - CommitCallbackInfo(commit_callback_t func = {}, EUntrustedCall handle_untrusted = UNTRUSTED_ALLOW) - : callback_func(func), handle_untrusted(handle_untrusted) - {} + CommitCallbackInfo(commit_callback_t func = {}, EUntrustedCall handle_untrusted = UNTRUSTED_ALLOW) : + callback_func(func), + handle_untrusted(handle_untrusted) + { + } public: commit_callback_t callback_func; - EUntrustedCall handle_untrusted; + EUntrustedCall handle_untrusted; + }; + typedef LLUICtrl::CommitCallbackInfo cb_info; + class CommitCallbackRegistry : public CallbackRegistry + { + LLSINGLETON_EMPTY_CTOR(CommitCallbackRegistry); + }; + + class CommitRegistrarHelper + { + public: + CommitRegistrarHelper(LLUICtrl::CommitCallbackRegistry::Registrar ®istrar) : mRegistrar(registrar) {} + + template void add(const std::string &name, ARGS &&...args) + { + mRegistrar.add(name, {std::forward(args)...}); + } + private: + LLUICtrl::CommitCallbackRegistry::Registrar &mRegistrar; + }; + + class ScopedRegistrarHelper + { + public: + template void add(const std::string &name, ARGS &&...args) + { + mRegistrar.add(name, {std::forward(args)...}); + } + + private: + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar mRegistrar; }; - class SharedCommitCallbackRegistry : public CallbackRegistry + // the enable callback registry is also used for visiblity callbacks + class EnableCallbackRegistry : public CallbackRegistry { - LLSINGLETON_EMPTY_CTOR(SharedCommitCallbackRegistry); + LLSINGLETON_EMPTY_CTOR(EnableCallbackRegistry); }; protected: -- cgit v1.2.3 From eb6d24e531aa5faa251b7aaf8b13c62f06708696 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 25 Jun 2024 14:51:53 +0300 Subject: Add wear/detach actions to Appearance listener; update example script --- indra/llui/llluafloater.cpp | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'indra/llui') diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp index e584a67a00..b08508bf9b 100644 --- a/indra/llui/llluafloater.cpp +++ b/indra/llui/llluafloater.cpp @@ -101,6 +101,15 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : } }, requiredParams); + mDispatchListener.add("clear_list", "", [this](const LLSD &event) + { + LLScrollListCtrl *ctrl = getChild(event["ctrl_name"].asString()); + if(ctrl) + { + ctrl->deleteAllItems(); + } + }, llsd::map("ctrl_name", LLSD())); + mDispatchListener.add("add_text", "", [this](const LLSD &event) { LLTextEditor *editor = getChild(event["ctrl_name"].asString()); @@ -111,15 +120,35 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : } }, requiredParams); + mDispatchListener.add("set_label", "", [this](const LLSD &event) + { + LLButton *btn = getChild(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(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() -- cgit v1.2.3 From f2f0fa7fd0efc221f1358dd4e440b5d51a5fb8b4 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 18 Jul 2024 13:29:34 -0400 Subject: Ditch `LLEventTrackable` aka `boost::signals2::trackable`. Remove documented `LLEventPump` support for `LLEventTrackable`. That claimed support was always a little bit magical/fragile. IF: * a class included `LLEventTrackable` as a base class AND * an instance of that class was managed by `boost::shared_ptr` AND * you passed one of that class's methods and the `boost::shared_ptr` specifically to `boost::bind()` AND * the resulting `boost::bind()` object was passed into `LLEventPump::listen()` THEN the promise was that on destruction of that object, that listener would automatically be disconnected -- instead of leaving a dangling pointer bound into the `LLEventPump`, causing a crash on the next `LLEventPump::post()` call. The only existing code in the viewer code base that exercised `LLEventTrackable` functionality was in test programs. When the viewer calls `LLEventPump::listen()`, it typically stores the resulting connection object in an `LLTempBoundListener` variable, which guarantees disconnection on destruction of that variable. The fact that `LLEventTrackable` support is specific to `boost::bind()`, that it silently fails to keep its promise with `std::bind()` or a lambda or any other form of C++ callable, makes it untrustworthy for new code. Note that the code base still uses `boost::signals2::trackable` for other `boost::signals2::signal` instances not associated with `LLEventPump`. We are not changing those at this time. --- indra/llui/llnotifications.h | 2 +- indra/llui/llnotificationslistener.cpp | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index ab4f009a80..206c521592 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -734,7 +734,7 @@ typedef std::multimap 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 ace9e37e25..2ad1689a45 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; -- cgit v1.2.3 From 99307b619a5aa27bef3bb67027c4cb5e54f21ad4 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Fri, 2 Aug 2024 19:46:52 +0300 Subject: Lua api for adjusting toolbars --- indra/llui/llcommandmanager.cpp | 10 ++++++++++ indra/llui/llcommandmanager.h | 2 ++ 2 files changed, 12 insertions(+) (limited to 'indra/llui') diff --git a/indra/llui/llcommandmanager.cpp b/indra/llui/llcommandmanager.cpp index 270ec86e01..0c27e519dd 100644 --- a/indra/llui/llcommandmanager.cpp +++ b/indra/llui/llcommandmanager.cpp @@ -189,3 +189,13 @@ bool LLCommandManager::load() return true; } + +LLSD LLCommandManager::getCommandNames() +{ + LLSD cmd_names; + for (auto &it : mCommands) + { + cmd_names.append(it->name()); + } + return cmd_names; + } diff --git a/indra/llui/llcommandmanager.h b/indra/llui/llcommandmanager.h index 3b2586a5a1..cf2270e658 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: -- cgit v1.2.3 From cf29b701b19644062a1428a64023c3cf9829e2de Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Mon, 5 Aug 2024 20:37:03 +0300 Subject: Allow getting the list of floater names, hide top menu items; add demo script --- indra/llui/llfloaterreg.cpp | 10 ++++++++++ indra/llui/llfloaterreg.h | 2 ++ indra/llui/llfloaterreglistener.cpp | 11 +++++++++++ indra/llui/llfloaterreglistener.h | 1 + 4 files changed, 24 insertions(+) (limited to 'indra/llui') diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index 989ce12d09..a9ed678973 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -607,3 +607,13 @@ U32 LLFloaterReg::getVisibleFloaterInstanceCount() return count; } + +LLSD LLFloaterReg::getFloaterNames() +{ + LLSD names; + for (auto &it : sGroupMap) + { + names.append(it.first); + } + return names; +} diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h index 43f3f7b170..31a334b89c 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 8316101264..e17f9f4dd6 100644 --- a/indra/llui/llfloaterreglistener.cpp +++ b/indra/llui/llfloaterreglistener.cpp @@ -80,6 +80,11 @@ LLFloaterRegListener::LLFloaterRegListener(): add("getFloaterEvents", "Return the table of Lua Floater events which are send to the script", &LLFloaterRegListener::getLuaFloaterEvents); + + add("getFloaterNames", + "Return the table of all registered floaters", + &LLFloaterRegListener::getFloaterNames, + llsd::map("reply", LLSD())); } void LLFloaterRegListener::getBuildMap(const LLSD& event) const @@ -121,6 +126,12 @@ void LLFloaterRegListener::instanceVisible(const LLSD& event) const event); } + +void LLFloaterRegListener::getFloaterNames(const LLSD &event) const +{ + Response response(llsd::map("floaters", LLFloaterReg::getFloaterNames()), event); +} + void LLFloaterRegListener::clickButton(const LLSD& event) const { // If the caller requests a reply, build the reply. diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h index 9cb0af2de5..2165b1b62f 100644 --- a/indra/llui/llfloaterreglistener.h +++ b/indra/llui/llfloaterreglistener.h @@ -49,6 +49,7 @@ 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; }; -- cgit v1.2.3 From eb82c78b071d71a0fd2d7be1c573997e41bab51e Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 6 Aug 2024 20:38:06 +0300 Subject: code clean up --- indra/llui/llcommandmanager.cpp | 8 ++------ indra/llui/llfloaterreg.cpp | 7 +------ 2 files changed, 3 insertions(+), 12 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llcommandmanager.cpp b/indra/llui/llcommandmanager.cpp index 0c27e519dd..6c3e676c9b 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" @@ -192,10 +193,5 @@ bool LLCommandManager::load() LLSD LLCommandManager::getCommandNames() { - LLSD cmd_names; - for (auto &it : mCommands) - { - cmd_names.append(it->name()); - } - return cmd_names; + return llsd::toArray(mCommands, [](const auto &cmd) { return cmd->name(); }); } diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index a9ed678973..8f9268ffcb 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -610,10 +610,5 @@ U32 LLFloaterReg::getVisibleFloaterInstanceCount() LLSD LLFloaterReg::getFloaterNames() { - LLSD names; - for (auto &it : sGroupMap) - { - names.append(it.first); - } - return names; + return llsd::toArray(sGroupMap, [](const auto &pair) { return pair.first; }); } -- cgit v1.2.3 From 03d7f2b84daf9ab991de6cad7d6149abda1ef716 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 28 Aug 2024 21:16:56 -0400 Subject: Ditch trailing spaces. --- indra/llui/llfloaterreglistener.cpp | 10 ++--- indra/llui/llfloaterreglistener.h | 10 ++--- indra/llui/llluafloater.cpp | 80 ++++++++++++++++++------------------- indra/llui/llluafloater.h | 10 ++--- indra/llui/llmenugl.h | 2 +- indra/llui/lluictrl.cpp | 2 +- 6 files changed, 57 insertions(+), 57 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp index e17f9f4dd6..b0dceb55c8 100644 --- a/indra/llui/llfloaterreglistener.cpp +++ b/indra/llui/llfloaterreglistener.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-08-12 * @brief Implementation for llfloaterreglistener. - * + * * $LicenseInfo:firstyear=2009&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$ */ diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h index 2165b1b62f..42e7178cbc 100644 --- a/indra/llui/llfloaterreglistener.h +++ b/indra/llui/llfloaterreglistener.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-08-12 * @brief Wrap (subset of) LLFloaterReg API with an event API - * + * * $LicenseInfo:firstyear=2009&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$ */ diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp index b08508bf9b..ca80a2c451 100644 --- a/indra/llui/llluafloater.cpp +++ b/indra/llui/llluafloater.cpp @@ -1,24 +1,24 @@ -/** +/** * @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$ * @@ -68,25 +68,25 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : }; LLSD requiredParams = llsd::map("ctrl_name", LLSD(), "value", LLSD()); - mDispatchListener.add("set_enabled", "", [ctrl_lookup](const LLSD &event) - { + 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) - { + 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) - { + 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) - { + mDispatchListener.add("add_list_element", "", [this](const LLSD &event) + { LLScrollListCtrl *ctrl = getChild(event["ctrl_name"].asString()); - if(ctrl) + if(ctrl) { - LLSD element_data = event["value"]; + LLSD element_data = event["value"]; if (element_data.isArray()) { for (const auto &row : llsd::inArray(element_data)) @@ -94,34 +94,34 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : ctrl->addElement(row); } } - else + else { ctrl->addElement(element_data); } } }, requiredParams); - mDispatchListener.add("clear_list", "", [this](const LLSD &event) - { + mDispatchListener.add("clear_list", "", [this](const LLSD &event) + { LLScrollListCtrl *ctrl = getChild(event["ctrl_name"].asString()); - if(ctrl) + if(ctrl) { ctrl->deleteAllItems(); } }, llsd::map("ctrl_name", LLSD())); - mDispatchListener.add("add_text", "", [this](const LLSD &event) - { + mDispatchListener.add("add_text", "", [this](const LLSD &event) + { LLTextEditor *editor = getChild(event["ctrl_name"].asString()); - if (editor) + if (editor) { editor->pasteTextWithLinebreaks(stringize(event["value"])); editor->addLineBreakChar(true); } }, requiredParams); - mDispatchListener.add("set_label", "", [this](const LLSD &event) - { + mDispatchListener.add("set_label", "", [this](const LLSD &event) + { LLButton *btn = getChild(event["ctrl_name"].asString()); if (btn) { @@ -129,17 +129,17 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : } }, requiredParams); - mDispatchListener.add("set_title", "", [this](const LLSD &event) - { + 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) - { + + 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) + mDispatchListener.add("get_selected_id", "", [this](const LLSD &event) { LLScrollListCtrl *ctrl = getChild(event["ctrl_name"].asString()); if (!ctrl) @@ -157,7 +157,7 @@ LLLuaFloater::~LLLuaFloater() post(LLSD()); } -BOOL LLLuaFloater::postBuild() +BOOL LLLuaFloater::postBuild() { for (LLView *view : *getChildList()) { @@ -217,10 +217,10 @@ void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::str 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) - { + 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)); + post(event.with("x", x).with("y", y)); }; auto post_with_value = [this, data](LLSD value) @@ -260,12 +260,12 @@ void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::str { list->setDoubleClickCallback( [post_with_value, list](){ post_with_value(LLSD(list->getCurrentID())); }); } - else + else { ctrl->setDoubleClickCallback(mouse_event_coords_cb); } } - else if (event_is(event, "keystroke")) + else if (event_is(event, "keystroke")) { LLTextEditor* text_editor = dynamic_cast(ctrl); if (text_editor) @@ -278,7 +278,7 @@ void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::str line_editor->setKeystrokeCallback([post_with_value](LLLineEditor *editor, void* userdata) { post_with_value(editor->getValue()); }, NULL); } } - else + else { LL_WARNS("LuaFloater") << "Can't register callback for unknown event: " << event << " , control: " << ctrl_name << LL_ENDL; } @@ -292,7 +292,7 @@ void LLLuaFloater::post(const LLSD &data) LLEventPumps::instance().obtain(mReplyPumpName).post(stamped_data); } -void LLLuaFloater::postEvent(LLSD data, const std::string &event_name) +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)); @@ -302,12 +302,12 @@ 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()) + 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()); diff --git a/indra/llui/llluafloater.h b/indra/llui/llluafloater.h index ccc3ccb39b..d0641d41b0 100644 --- a/indra/llui/llluafloater.h +++ b/indra/llui/llluafloater.h @@ -1,24 +1,24 @@ -/** +/** * @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$ */ diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index b6b83c4716..65211bf122 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -953,7 +953,7 @@ public: 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, + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, cb_info([listener](LLUICtrl*, const LLSD& param){ return listener->handleEvent(param); }, handle_untrusted)); } diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index d6631a9cd9..f1dc3d7c08 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -284,7 +284,7 @@ LLUICtrl::commit_signal_t::slot_type LLUICtrl::initCommitCallback(const CommitCa std::string function_name = cb.function_name; setFunctionName(function_name); LLUICtrl::CommitCallbackInfo *info = (CommitCallbackRegistry::getValue(function_name)); - if (info && info->callback_func) + if (info && info->callback_func) { if (cb.parameter.isProvided()) return boost::bind((info->callback_func), _1, cb.parameter); -- cgit v1.2.3 From a8dd7135f0423384dbbb1e3b98514149c6a69e6b Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 3 Sep 2024 20:50:18 -0400 Subject: Use Lua result-set logic for "LLFloaterReg"s "getFloaterNames" op. This is the query that produced so many results that, before we lifted the infinite-loop interrupt limit, inspect(result) hit the limit and terminated. --- indra/llui/llfloaterreglistener.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp index e17f9f4dd6..bd8d87086e 100644 --- a/indra/llui/llfloaterreglistener.cpp +++ b/indra/llui/llfloaterreglistener.cpp @@ -38,6 +38,7 @@ #include "llfloater.h" #include "llbutton.h" #include "llluafloater.h" +#include "resultset.h" LLFloaterRegListener::LLFloaterRegListener(): LLEventAPI("LLFloaterReg", @@ -82,9 +83,9 @@ LLFloaterRegListener::LLFloaterRegListener(): &LLFloaterRegListener::getLuaFloaterEvents); add("getFloaterNames", - "Return the table of all registered floaters", + "Return result set key [\"floaters\"] for names of all registered floaters", &LLFloaterRegListener::getFloaterNames, - llsd::map("reply", LLSD())); + llsd::map("reply", LLSD::String())); } void LLFloaterRegListener::getBuildMap(const LLSD& event) const @@ -126,10 +127,22 @@ 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 { - Response response(llsd::map("floaters", LLFloaterReg::getFloaterNames()), event); + auto nameresult = new NameResultSet; + sendReply(llsd::map("floaters", nameresult->getKeyLength()), event); } void LLFloaterRegListener::clickButton(const LLSD& event) const @@ -178,4 +191,3 @@ void LLFloaterRegListener::getLuaFloaterEvents(const LLSD &event) const { Response response(llsd::map("events", LLLuaFloater::getEventsData()), event); } - -- cgit v1.2.3 From c4f29a535359fe1ecdb8bec45596f40b02891cd1 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 4 Sep 2024 14:17:32 -0400 Subject: Resolve a few unresolved merge conflicts. --- indra/llui/llmenugl.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 65211bf122..da5d7874c6 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -562,6 +562,8 @@ public: // add a context menu branch bool appendContextSubMenu(LLMenuGL *menu); + void createSpilloverBranch(); + void cleanupSpilloverBranch(); // Add the menu item to this menu. virtual bool append( LLMenuItemGL* item ); @@ -806,15 +808,9 @@ public: void resetMenuTrigger() { mAltKeyTrigger = false; } // add a menu - this will create a drop down menu. -<<<<<<< variant A - virtual BOOL appendMenu(LLMenuGL *menu); + virtual bool appendMenu(LLMenuGL *menu); private: ->>>>>>> variant B - virtual bool appendMenu( LLMenuGL* menu ); -####### Ancestor - virtual BOOL appendMenu( LLMenuGL* menu ); -======= end // rearrange the child rects so they fit the shape of the menu // bar. virtual void arrange( void ); -- cgit v1.2.3 From a980a8f30870d35a5a45cbf52169f7bf35cf95ce Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 4 Sep 2024 14:23:31 -0400 Subject: Swat a few more buzzing BOOLs. --- indra/llui/llluafloater.cpp | 2 +- indra/llui/llluafloater.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp index ca80a2c451..ccdadc6ae0 100644 --- a/indra/llui/llluafloater.cpp +++ b/indra/llui/llluafloater.cpp @@ -157,7 +157,7 @@ LLLuaFloater::~LLLuaFloater() post(LLSD()); } -BOOL LLLuaFloater::postBuild() +bool LLLuaFloater::postBuild() { for (LLView *view : *getChildList()) { diff --git a/indra/llui/llluafloater.h b/indra/llui/llluafloater.h index d0641d41b0..41132f926d 100644 --- a/indra/llui/llluafloater.h +++ b/indra/llui/llluafloater.h @@ -34,7 +34,7 @@ class LLLuaFloater : public LLFloater { public: LLLuaFloater(const LLSD &key); - BOOL postBuild(); + bool postBuild(); virtual ~LLLuaFloater(); void registerCallback(const std::string &ctrl_name, const std::string &event); -- cgit v1.2.3 From 0a3e5074bbacdd9184311bd99a74913d1ce0423c Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 6 Sep 2024 14:43:05 -0400 Subject: Allow LLMenuGL::insert() to append as well as inserting. Appending is effected by passing position == getItemCount(). Until now, insert() disallowed that value, so you could insert before the last existing entry but not after it. --- indra/llui/llmenugl.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'indra/llui') 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(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; } -- cgit v1.2.3 From dca6f0deae49d133f180ef937939b8648649fbc6 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 10 Sep 2024 17:16:14 -0400 Subject: Fix risky signature of `wchar_to_utf8chars()`. Add `ll_convert()` alias. `wchar_to_utf8chars()` used to require a `char*` output buffer with no length, assuming that its caller knew enough to provide a buffer of sufficient length. In fact a `char[8]` buffer suffices, but nothing in the header indicated that. Eliminate the output parameter and return `std::string`. Fix the few existing callers. Also set an `ll_convert_alias` so that `ll_convert_to(llwchar)` directly calls `wchar_to_utf8chars()`. Replace instances of the workaround `wstring_to_utf8str(LLWString(1, llwchar))`. --- indra/llui/llviewereventrecorder.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llviewereventrecorder.cpp b/indra/llui/llviewereventrecorder.cpp index 6d907d7e45..0a4fe5234b 100644 --- a/indra/llui/llviewereventrecorder.cpp +++ b/indra/llui/llviewereventrecorder.cpp @@ -24,9 +24,10 @@ */ -#include "llviewereventrecorder.h" -#include "llui.h" #include "llleap.h" +#include "llstring.h" +#include "llui.h" +#include "llviewereventrecorder.h" LLViewerEventRecorder::LLViewerEventRecorder() { @@ -247,11 +248,9 @@ void LLViewerEventRecorder::logKeyUnicodeEvent(llwchar uni_char) { // keycode...or // char - LL_DEBUGS() << "Wrapped in conversion to wstring " << wstring_to_utf8str(LLWString( 1, uni_char)) << "\n" << LL_ENDL; + LL_DEBUGS() << "Wrapped in conversion to wstring " << ll_convert_to(uni_char) << "\n" << LL_ENDL; - event.insert("char", - LLSD( wstring_to_utf8str(LLWString( 1,uni_char)) ) - ); + event.insert("char", LLSD(ll_convert_to(uni_char))); // path (optional) - for now we are not recording path for key events during record - should not be needed for full record and playback of recorded steps // as a vita script - it does become useful if you edit the resulting vita script and wish to remove some steps leading to a key event - that sort of edit might -- cgit v1.2.3 From 55f2103adc36db0d3f068a31a144e15465226e13 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 13 Sep 2024 20:50:19 +0300 Subject: viewer#2565 Optimize LLFolderViewItem::draw() --- indra/llui/llfolderview.cpp | 2 +- indra/llui/llfolderviewitem.cpp | 116 ++++++++++++++++++++++------------------ indra/llui/llfolderviewitem.h | 9 +++- 3 files changed, 72 insertions(+), 55 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 388dc5b1ac..42a9e267d2 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -1649,7 +1649,7 @@ void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constr { LLRect local_rect = item->getLocalRect(); S32 icon_height = mIcon.isNull() ? 0 : mIcon->getHeight(); - S32 label_height = getLabelFontForStyle(mLabelStyle)->getLineHeight(); + S32 label_height = getLabelFont()->getLineHeight(); // when navigating with keyboard, only move top of opened folder on screen, otherwise show whole folder S32 max_height_to_show = item->isOpen() && mScrollContainer->hasFocus() ? (llmax( icon_height, label_height ) + item->getIconPad()) : local_rect.getHeight(); diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 73803786a6..18bde344a0 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -48,7 +48,6 @@ static LLDefaultChildRegistry::Register r("folder_view_item"); // statics std::map LLFolderViewItem::sFonts; // map of styles to fonts -bool LLFolderViewItem::sColorSetInitialized = false; LLUIColor LLFolderViewItem::sFgColor; LLUIColor LLFolderViewItem::sHighlightBgColor; LLUIColor LLFolderViewItem::sFlashBgColor; @@ -58,6 +57,10 @@ LLUIColor LLFolderViewItem::sFilterBGColor; LLUIColor LLFolderViewItem::sFilterTextColor; LLUIColor LLFolderViewItem::sSuffixColor; LLUIColor LLFolderViewItem::sSearchStatusColor; +S32 LLFolderViewItem::sTopPad = 0; +LLUIImagePtr LLFolderViewItem::sFolderArrowImg; +LLUIImagePtr LLFolderViewItem::sSelectionImg; +LLFontGL* LLFolderViewItem::sSuffixFont = nullptr; // only integers can be initialized in header const F32 LLFolderViewItem::FOLDER_CLOSE_TIME_CONSTANT = 0.02f; @@ -83,15 +86,42 @@ LLFontGL* LLFolderViewItem::getLabelFontForStyle(U8 style) return rtn; } + +const LLFontGL* LLFolderViewItem::getLabelFont() +{ + if (!pLabelFont) + { + pLabelFont = getLabelFontForStyle(mLabelStyle); + } + return pLabelFont; +} //static void LLFolderViewItem::initClass() { + const Params& default_params = LLUICtrlFactory::getDefaultParams(); + sTopPad = default_params.item_top_pad; + sFolderArrowImg = default_params.folder_arrow_image; + sSelectionImg = default_params.selection_image; + sSuffixFont = getLabelFontForStyle(LLFontGL::NORMAL); + + sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE); + sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE); + sFlashBgColor = LLUIColorTable::instance().getColor("MenuItemFlashBgColor", DEFAULT_WHITE); + sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE); + sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE); + sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE); + sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE); + sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE); + sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE); } //static void LLFolderViewItem::cleanupClass() { sFonts.clear(); + sFolderArrowImg = nullptr; + sSelectionImg = nullptr; + sSuffixFont = nullptr; } @@ -134,6 +164,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) mIsItemCut(false), mCutGeneration(0), mLabelStyle( LLFontGL::NORMAL ), + pLabelFont(nullptr), mHasVisibleChildren(false), mLocalIndentation(p.folder_indentation), mIndentation(0), @@ -158,20 +189,6 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) mMaxFolderItemOverlap(p.max_folder_item_overlap), mDoubleClickOverride(p.double_click_override) { - if (!sColorSetInitialized) - { - sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE); - sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE); - sFlashBgColor = LLUIColorTable::instance().getColor("MenuItemFlashBgColor", DEFAULT_WHITE); - sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE); - sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE); - sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE); - sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE); - sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE); - sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE); - sColorSetInitialized = true; - } - if (mViewModelItem) { mViewModelItem->setFolderViewItem(this); @@ -320,6 +337,7 @@ void LLFolderViewItem::refresh() // Very Expensive! // Can do a number of expensive checks, like checking active motions, wearables or friend list mLabelStyle = vmi.getLabelStyle(); + pLabelFont = nullptr; // refresh can be called from a coro, don't use getLabelFontForStyle, coro trips font list tread safety mLabelSuffix = utf8str_to_wstring(vmi.getLabelSuffix()); mSuffixFontBuffer.reset(); } @@ -346,6 +364,7 @@ void LLFolderViewItem::refreshSuffix() // Very Expensive! // Can do a number of expensive checks, like checking active motions, wearables or friend list mLabelStyle = vmi->getLabelStyle(); + pLabelFont = nullptr; mLabelSuffix = utf8str_to_wstring(vmi->getLabelSuffix()); } @@ -738,19 +757,17 @@ bool LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, return handled; } -void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const LLUIColor& fg_color) +void LLFolderViewItem::drawOpenFolderArrow() { //--------------------------------------------------------------------------------// // Draw open folder arrow // - const S32 TOP_PAD = default_params.item_top_pad; if (hasVisibleChildren() || !isFolderComplete()) { - LLUIImage* arrow_image = default_params.folder_arrow_image; gl_draw_scaled_rotated_image( - mIndentation, getRect().getHeight() - mArrowSize - mTextPad - TOP_PAD, - mArrowSize, mArrowSize, mControlLabelRotation, arrow_image->getImage(), fg_color); + mIndentation, getRect().getHeight() - mArrowSize - mTextPad - sTopPad, + mArrowSize, mArrowSize, mControlLabelRotation, sFolderArrowImg->getImage(), sFgColor); } } @@ -766,7 +783,7 @@ void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const L /*virtual*/ bool LLFolderViewItem::isFadeItem() { - LLClipboard& clipboard = LLClipboard::instance(); + static const LLClipboard& clipboard = LLClipboard::instance(); // Make it a 'simpleton'? if (mCutGeneration != clipboard.getGeneration()) { mCutGeneration = clipboard.getGeneration(); @@ -902,16 +919,14 @@ void LLFolderViewItem::draw() const bool show_context = (getRoot() ? getRoot()->getShowSelectionContext() : false); const bool filled = show_context || (getRoot() ? getRoot()->getParentPanel()->hasFocus() : false); // If we have keyboard focus, draw selection filled - const Params& default_params = LLUICtrlFactory::getDefaultParams(); - const S32 TOP_PAD = default_params.item_top_pad; - - const LLFontGL* font = getLabelFontForStyle(mLabelStyle); + const LLFontGL* font = getLabelFont(); + S32 line_height = font->getLineHeight(); getViewModelItem()->update(); if (!mSingleFolderMode) { - drawOpenFolderArrow(default_params, sFgColor); + drawOpenFolderArrow(); } drawHighlight(show_context, filled, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor); @@ -920,18 +935,19 @@ void LLFolderViewItem::draw() // Draw open icon // const S32 icon_x = mIndentation + mArrowSize + mTextPad; + const S32 rect_height = getRect().getHeight(); if (!mIconOpen.isNull() && (llabs(mControlLabelRotation) > 80)) // For open folders { - mIconOpen->draw(icon_x, getRect().getHeight() - mIconOpen->getHeight() - TOP_PAD + 1); + mIconOpen->draw(icon_x, rect_height - mIconOpen->getHeight() - sTopPad + 1); } else if (mIcon) { - mIcon->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1); + mIcon->draw(icon_x, rect_height - mIcon->getHeight() - sTopPad + 1); } if (mIconOverlay && getRoot()->showItemLinkOverlays()) { - mIconOverlay->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1); + mIconOverlay->draw(icon_x, rect_height - mIcon->getHeight() - sTopPad + 1); } //--------------------------------------------------------------------------------// @@ -944,24 +960,22 @@ void LLFolderViewItem::draw() S32 filter_string_length = mViewModelItem->hasFilterStringMatch() ? (S32)mViewModelItem->getFilterStringSize() : 0; F32 right_x = 0; - F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; + F32 y = (F32)rect_height - line_height - (F32)mTextPad - (F32)sTopPad; F32 text_left = (F32)getLabelXPos(); LLWString combined_string = mLabel + mLabelSuffix; - const LLFontGL* suffix_font = getLabelFontForStyle(LLFontGL::NORMAL); S32 filter_offset = static_cast(mViewModelItem->getFilterStringOffset()); if (filter_string_length > 0) { - S32 bottom = getRect().getHeight() - font->getLineHeight() - 3 - TOP_PAD; - S32 top = getRect().getHeight() - TOP_PAD; - if(mLabelSuffix.empty() || (font == suffix_font)) + S32 bottom = rect_height - line_height - 3 - sTopPad; + S32 top = rect_height - sTopPad; + if(mLabelSuffix.empty() || (font == sSuffixFont)) { - S32 left = ll_round(text_left) + font->getWidth(combined_string.c_str(), 0, static_cast(mViewModelItem->getFilterStringOffset())) - 2; - S32 right = left + font->getWidth(combined_string.c_str(), static_cast(mViewModelItem->getFilterStringOffset()), filter_string_length) + 2; + S32 left = ll_round(text_left) + font->getWidth(combined_string.c_str(), 0, filter_offset) - 2; + S32 right = left + font->getWidth(combined_string.c_str(), filter_offset, filter_string_length) + 2; - LLUIImage* box_image = default_params.selection_image; - LLRect box_rect(left, top, right, bottom); - box_image->draw(box_rect, sFilterBGColor); + LLRect box_rect(left, top, right, bottom); + sSelectionImg->draw(box_rect, sFilterBGColor); } else { @@ -970,19 +984,17 @@ void LLFolderViewItem::draw() { S32 left = (S32)(ll_round(text_left) + font->getWidthF32(mLabel.c_str(), 0, llmin(filter_offset, (S32)mLabel.size()))) - 2; S32 right = left + (S32)font->getWidthF32(mLabel.c_str(), filter_offset, label_filter_length) + 2; - LLUIImage* box_image = default_params.selection_image; LLRect box_rect(left, top, right, bottom); - box_image->draw(box_rect, sFilterBGColor); + sSelectionImg->draw(box_rect, sFilterBGColor); } S32 suffix_filter_length = label_filter_length > 0 ? filter_string_length - label_filter_length : filter_string_length; if(suffix_filter_length > 0) { S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size()); - S32 left = (S32)(ll_round(text_left) + font->getWidthF32(mLabel.c_str(), 0, static_cast(mLabel.size())) + suffix_font->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset)) - 2; - S32 right = left + (S32)suffix_font->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length) + 2; - LLUIImage* box_image = default_params.selection_image; + S32 left = (S32)(ll_round(text_left) + font->getWidthF32(mLabel.c_str(), 0, static_cast(mLabel.size())) + sSuffixFont->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset)) - 2; + S32 right = left + (S32)sSuffixFont->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length) + 2; LLRect box_rect(left, top, right, bottom); - box_image->draw(box_rect, sFilterBGColor); + sSelectionImg->draw(box_rect, sFilterBGColor); } } } @@ -1001,7 +1013,7 @@ void LLFolderViewItem::draw() // if (!mLabelSuffix.empty()) { - mSuffixFontBuffer.render(suffix_font, mLabelSuffix, 0, right_x, y, isFadeItem() ? color : sSuffixColor.get(), + mSuffixFontBuffer.render(sSuffixFont, mLabelSuffix, 0, right_x, y, isFadeItem() ? color : sSuffixColor.get(), LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, &right_x); } @@ -1011,10 +1023,10 @@ void LLFolderViewItem::draw() // if (filter_string_length > 0) { - if(mLabelSuffix.empty() || (font == suffix_font)) + if(mLabelSuffix.empty() || (font == sSuffixFont)) { F32 match_string_left = text_left + font->getWidthF32(combined_string.c_str(), 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string.c_str(), filter_offset, filter_string_length); - F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; + F32 yy = (F32)rect_height - line_height - (F32)mTextPad - (F32)sTopPad; font->render(combined_string, filter_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, filter_string_length, S32_MAX, &right_x); @@ -1025,7 +1037,7 @@ void LLFolderViewItem::draw() if(label_filter_length > 0) { F32 match_string_left = text_left + font->getWidthF32(mLabel.c_str(), 0, filter_offset + label_filter_length) - font->getWidthF32(mLabel.c_str(), filter_offset, label_filter_length); - F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; + F32 yy = (F32)rect_height - line_height - (F32)mTextPad - (F32)sTopPad; font->render(mLabel, filter_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, label_filter_length, S32_MAX, &right_x); @@ -1035,9 +1047,9 @@ void LLFolderViewItem::draw() if(suffix_filter_length > 0) { S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size()); - F32 match_string_left = text_left + font->getWidthF32(mLabel.c_str(), 0, static_cast(mLabel.size())) + suffix_font->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset + suffix_filter_length) - suffix_font->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length); - F32 yy = (F32)getRect().getHeight() - suffix_font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; - suffix_font->render(mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor, + F32 match_string_left = text_left + font->getWidthF32(mLabel.c_str(), 0, static_cast(mLabel.size())) + sSuffixFont->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset + suffix_filter_length) - sSuffixFont->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length); + F32 yy = (F32)rect_height - sSuffixFont->getLineHeight() - (F32)mTextPad - (F32)sTopPad; + sSuffixFont->render(mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, suffix_filter_length, S32_MAX, &right_x); } diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index 7ac28b1a8e..cc8a7d934c 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -135,7 +135,6 @@ protected: LLUIColor mFontHighlightColor; // For now assuming all colors are the same in derived classes. - static bool sColorSetInitialized; static LLUIColor sFgColor; static LLUIColor sFgDisabledColor; static LLUIColor sHighlightBgColor; @@ -158,6 +157,7 @@ protected: virtual void setFlashState(bool) { } static LLFontGL* getLabelFontForStyle(U8 style); + const LLFontGL* getLabelFont(); bool mIsSelected; @@ -297,7 +297,7 @@ public: // virtual void handleDropped(); virtual void draw(); - void drawOpenFolderArrow(const Params& default_params, const LLUIColor& fg_color); + void drawOpenFolderArrow(); void drawHighlight(bool showContent, bool hasKeyboardFocus, const LLUIColor& selectColor, const LLUIColor& flashColor, const LLUIColor& outlineColor, const LLUIColor& mouseOverColor); void drawLabel(const LLFontGL* font, const F32 x, const F32 y, const LLColor4& color, F32 &right_x); virtual bool handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, @@ -308,9 +308,14 @@ public: private: static std::map sFonts; // map of styles to fonts + static S32 sTopPad; + static LLUIImagePtr sFolderArrowImg; + static LLUIImagePtr sSelectionImg; + static LLFontGL* sSuffixFont; LLFontVertexBuffer mLabelFontBuffer; LLFontVertexBuffer mSuffixFontBuffer; + LLFontGL* pLabelFont{nullptr}; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- cgit v1.2.3 From d9da5bbb33ce70e3bc799ba6696c8b10de0e5f04 Mon Sep 17 00:00:00 2001 From: Ansariel Hiller Date: Wed, 18 Sep 2024 16:09:51 +0200 Subject: Remove quads rendering mode entirely (#2593) --- indra/llui/llbadge.cpp | 6 +++--- indra/llui/llfloater.cpp | 24 ++++++++---------------- indra/llui/llstatbar.cpp | 10 ++++++++-- 3 files changed, 19 insertions(+), 21 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llbadge.cpp b/indra/llui/llbadge.cpp index c6654ee0aa..6875e7c0ad 100644 --- a/indra/llui/llbadge.cpp +++ b/indra/llui/llbadge.cpp @@ -205,12 +205,12 @@ void renderBadgeBackground(F32 centerX, F32 centerY, F32 width, F32 height, cons (F32)ll_round(y) + height); LLVector3 vertices[4]; - vertices[0] = LLVector3(screen_rect.mRight, screen_rect.mTop, 1.0f); - vertices[1] = LLVector3(screen_rect.mLeft, screen_rect.mTop, 1.0f); + vertices[0] = LLVector3(screen_rect.mLeft, screen_rect.mTop, 1.0f); + vertices[1] = LLVector3(screen_rect.mRight, screen_rect.mTop, 1.0f); vertices[2] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 1.0f); vertices[3] = LLVector3(screen_rect.mRight, screen_rect.mBottom, 1.0f); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { gGL.vertexBatchPreTransformed(vertices, 4); } diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 92fb4b75bf..4b904f09e0 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -2275,36 +2275,28 @@ void LLFloater::drawConeToOwner(F32 &context_cone_opacity, gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); LLGLEnable(GL_CULL_FACE); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); - gGL.vertex2i(owner_rect.mRight, owner_rect.mTop); - gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); - gGL.vertex2i(local_rect.mRight, local_rect.mTop); - gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); - gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom); - gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); - + gGL.vertex2i(owner_rect.mRight, owner_rect.mTop); gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); - gGL.vertex2i(local_rect.mRight, local_rect.mBottom); gGL.vertex2i(local_rect.mRight, local_rect.mTop); gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); - gGL.vertex2i(owner_rect.mRight, owner_rect.mTop); gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom); - - gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); - gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); gGL.vertex2i(local_rect.mRight, local_rect.mBottom); gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); - gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom); gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); + gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mTop); } gGL.end(); } diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp index 2693243eb1..62c0401869 100644 --- a/indra/llui/llstatbar.cpp +++ b/indra/llui/llstatbar.cpp @@ -460,7 +460,7 @@ void LLStatBar::draw() max_value = 0.f; gGL.color4f(1.f, 0.f, 0.f, 1.f); - gGL.begin( LLRender::QUADS ); + gGL.begin(LLRender::TRIANGLES); const S32 max_frame = llmin(num_frames, num_values); U32 num_samples = 0; for (S32 i = 1; i <= max_frame; i++) @@ -498,6 +498,9 @@ void LLStatBar::draw() gGL.vertex2f((F32)bar_rect.mRight - offset, max); gGL.vertex2f((F32)bar_rect.mRight - offset, min); gGL.vertex2f((F32)bar_rect.mRight - offset - 1, min); + + gGL.vertex2f((F32)bar_rect.mRight - offset, max); + gGL.vertex2f((F32)bar_rect.mRight - offset - 1, min); gGL.vertex2f((F32)bar_rect.mRight - offset - 1, max); } else @@ -505,7 +508,10 @@ void LLStatBar::draw() gGL.vertex2f(min, (F32)bar_rect.mBottom + offset + 1); gGL.vertex2f(min, (F32)bar_rect.mBottom + offset); gGL.vertex2f(max, (F32)bar_rect.mBottom + offset); - gGL.vertex2f(max, (F32)bar_rect.mBottom + offset + 1 ); + + gGL.vertex2f(min, (F32)bar_rect.mBottom + offset + 1); + gGL.vertex2f(max, (F32)bar_rect.mBottom + offset); + gGL.vertex2f(max, (F32)bar_rect.mBottom + offset + 1); } } gGL.end(); -- cgit v1.2.3 From 27b8e6d576346e3174760087a15811478a90459e Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Wed, 18 Sep 2024 11:44:03 +0200 Subject: #2408 The long covenant with emojis significantly slows down some operations in the viewer --- indra/llui/lltextbase.cpp | 98 +++++++++++++++++++++++++++++++++++++++++++++++ indra/llui/lltextbase.h | 15 ++++++++ 2 files changed, 113 insertions(+) (limited to 'indra/llui') diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index e2d31085c4..cbbf83d679 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -2368,6 +2368,34 @@ S32 LLTextBase::removeFirstLine() return 0; } +// virtual +void LLTextBase::copyContents(const LLTextBase* source) +{ + llassert(source); + if (!source) + return; + + beforeValueChange(); + deselect(); + + mSegments.clear(); + for (const LLTextSegmentPtr& segp : source->mSegments) + { + mSegments.emplace(segp->clone(*this)); + } + + mLineInfoList.clear(); + for (const line_info& li : mLineInfoList) + { + mLineInfoList.push_back(line_info(li)); + } + + getViewModel()->setDisplay(source->getViewModel()->getDisplay()); + + onValueChange(0, getLength()); + needsReflow(); +} + void LLTextBase::appendLineBreakSegment(const LLStyle::Params& style_params) { segment_vec_t segments; @@ -3233,6 +3261,24 @@ boost::signals2::connection LLTextBase::setIsObjectBlockedCallback(const is_bloc LLTextSegment::~LLTextSegment() {} +// static +LLStyleSP LLTextSegment::cloneStyle(LLTextBase& target, const LLStyle* source) +{ + // Take most params from target + LLStyle::Params params = target.getStyleParams(); + LLStyle* style = new LLStyle(params); + + // Take some params from source + style->setLinkHREF(source->getLinkHREF()); + if (source->isImage()) + { + style->setImage(source->getImage()->getName()); + } + + return style; +} + + bool LLTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { width = 0; height = 0; return false; } bool LLTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const { @@ -3574,6 +3620,13 @@ void LLNormalTextSegment::setToolTip(const std::string& tooltip) mTooltip = tooltip; } +// virtual +LLTextSegmentPtr LLNormalTextSegment::clone(LLTextBase& target) const +{ + LLStyleConstSP sp(cloneStyle(target, mStyle)); + return new LLNormalTextSegment(sp, mStart, mEnd, target); +} + bool LLNormalTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { height = 0; @@ -3701,6 +3754,13 @@ LLLabelTextSegment::LLLabelTextSegment( const LLUIColor& color, S32 start, S32 e { } +// virtual +LLTextSegmentPtr LLLabelTextSegment::clone(LLTextBase& target) const +{ + LLStyleConstSP sp(cloneStyle(target, mStyle)); + return new LLLabelTextSegment(sp, mStart, mEnd, target); +} + /*virtual*/ const LLWString& LLLabelTextSegment::getWText() const { @@ -3725,6 +3785,13 @@ LLEmojiTextSegment::LLEmojiTextSegment(const LLUIColor& color, S32 start, S32 en { } +// virtual +LLTextSegmentPtr LLEmojiTextSegment::clone(LLTextBase& target) const +{ + LLStyleConstSP sp(cloneStyle(target, mStyle)); + return new LLEmojiTextSegment(sp, mStart, mEnd, target); +} + bool LLEmojiTextSegment::handleToolTip(S32 x, S32 y, MASK mask) { if (mTooltip.empty()) @@ -3748,6 +3815,14 @@ LLOnHoverChangeableTextSegment::LLOnHoverChangeableTextSegment( LLStyleConstSP s mHoveredStyle(style), mNormalStyle(normal_style){} +// virtual +LLTextSegmentPtr LLOnHoverChangeableTextSegment::clone(LLTextBase& target) const +{ + LLStyleConstSP hsp(cloneStyle(target, mHoveredStyle)); + LLStyleConstSP nsp(cloneStyle(target, mNormalStyle)); + return new LLOnHoverChangeableTextSegment(hsp, nsp, mStart, mEnd, target); +} + /*virtual*/ F32 LLOnHoverChangeableTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect) { @@ -3787,6 +3862,13 @@ LLInlineViewSegment::~LLInlineViewSegment() mView->die(); } +// virtual +LLTextSegmentPtr LLInlineViewSegment::clone(LLTextBase& target) const +{ + llassert_always_msg(false, "NOT SUPPORTED"); + return nullptr; +} + bool LLInlineViewSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { if (first_char == 0 && num_chars == 0) @@ -3874,6 +3956,14 @@ LLLineBreakTextSegment::LLLineBreakTextSegment(LLStyleConstSP style,S32 pos):LLT LLLineBreakTextSegment::~LLLineBreakTextSegment() { } + +// virtual +LLTextSegmentPtr LLLineBreakTextSegment::clone(LLTextBase& target) const +{ + LLLineBreakTextSegment* copy = new LLLineBreakTextSegment(mStart); + copy->mFontHeight = mFontHeight; + return copy; +} bool LLLineBreakTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { width = 0; @@ -3901,8 +3991,16 @@ LLImageTextSegment::~LLImageTextSegment() { } +// virtual +LLTextSegmentPtr LLImageTextSegment::clone(LLTextBase& target) const +{ + LLStyleConstSP sp(cloneStyle(target, mStyle)); + return new LLImageTextSegment(sp, mStart, target); +} + static const S32 IMAGE_HPAD = 3; +// virtual bool LLImageTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { width = 0; diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index eb4697da15..76d4e160af 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -45,6 +45,7 @@ class LLScrollContainer; class LLContextMenu; class LLUrlMatch; +class LLTextBase; /// /// A text segment is used to specify a subsection of a text string @@ -62,6 +63,9 @@ public: mEnd(end) {} virtual ~LLTextSegment(); + virtual LLTextSegmentPtr clone(LLTextBase& terget) const { return new LLTextSegment(mStart, mEnd); } + static LLStyleSP cloneStyle(LLTextBase& target, const LLStyle* source); + bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const; virtual bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; @@ -128,6 +132,7 @@ public: LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor ); LLNormalTextSegment( const LLUIColor& color, S32 start, S32 end, LLTextBase& editor, bool is_visible = true); virtual ~LLNormalTextSegment(); + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const; /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; /*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const; @@ -180,6 +185,7 @@ class LLLabelTextSegment : public LLNormalTextSegment public: LLLabelTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor ); LLLabelTextSegment( const LLUIColor& color, S32 start, S32 end, LLTextBase& editor, bool is_visible = true); + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const; protected: @@ -194,6 +200,7 @@ class LLEmojiTextSegment : public LLNormalTextSegment public: LLEmojiTextSegment(LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor); LLEmojiTextSegment(const LLUIColor& color, S32 start, S32 end, LLTextBase& editor, bool is_visible = true); + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const override; bool canEdit() const override { return false; } bool handleToolTip(S32 x, S32 y, MASK mask) override; @@ -204,6 +211,7 @@ class LLOnHoverChangeableTextSegment : public LLNormalTextSegment { public: LLOnHoverChangeableTextSegment( LLStyleConstSP style, LLStyleConstSP normal_style, S32 start, S32 end, LLTextBase& editor ); + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const; /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); /*virtual*/ bool handleHover(S32 x, S32 y, MASK mask); protected: @@ -218,6 +226,7 @@ class LLIndexSegment : public LLTextSegment { public: LLIndexSegment() : LLTextSegment(0, 0) {} + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const { return new LLIndexSegment(); } }; class LLInlineViewSegment : public LLTextSegment @@ -235,6 +244,8 @@ public: LLInlineViewSegment(const Params& p, S32 start, S32 end); ~LLInlineViewSegment(); + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const; + /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const; /*virtual*/ void updateLayout(const class LLTextBase& editor); @@ -259,6 +270,7 @@ public: LLLineBreakTextSegment(LLStyleConstSP style,S32 pos); LLLineBreakTextSegment(S32 pos); ~LLLineBreakTextSegment(); + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const; /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const; F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); @@ -272,6 +284,8 @@ class LLImageTextSegment : public LLTextSegment public: LLImageTextSegment(LLStyleConstSP style,S32 pos,class LLTextBase& editor); ~LLImageTextSegment(); + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const; + /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 char_offset, S32 max_chars, S32 line_ind) const; F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); @@ -510,6 +524,7 @@ public: const LLFontGL* getFont() const override { return mFont; } + virtual void copyContents(const LLTextBase* source); virtual void appendLineBreakSegment(const LLStyle::Params& style_params); virtual void appendImageSegment(const LLStyle::Params& style_params); virtual void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo); -- cgit v1.2.3 From 6d842ac0af814a088c56f437dc885e4ce58b61a8 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 18 Sep 2024 17:11:03 +0300 Subject: Expose LLVector4a in LLRender Avoid using a bunch of allocators. Make sure we use LLVector4a's SSE logic instead of LLVector3's. Some minor optimizations. --- indra/llui/llbadge.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llbadge.cpp b/indra/llui/llbadge.cpp index 6875e7c0ad..42b6f1f07b 100644 --- a/indra/llui/llbadge.cpp +++ b/indra/llui/llbadge.cpp @@ -204,11 +204,11 @@ void renderBadgeBackground(F32 centerX, F32 centerY, F32 width, F32 height, cons (F32)ll_round(x) + width, (F32)ll_round(y) + height); - LLVector3 vertices[4]; - vertices[0] = LLVector3(screen_rect.mLeft, screen_rect.mTop, 1.0f); - vertices[1] = LLVector3(screen_rect.mRight, screen_rect.mTop, 1.0f); - vertices[2] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 1.0f); - vertices[3] = LLVector3(screen_rect.mRight, screen_rect.mBottom, 1.0f); + LLVector4a vertices[4]; + vertices[0].set(screen_rect.mLeft, screen_rect.mTop, 1.0f); + vertices[1].set(screen_rect.mRight, screen_rect.mTop, 1.0f); + vertices[2].set(screen_rect.mLeft, screen_rect.mBottom, 1.0f); + vertices[3].set(screen_rect.mRight, screen_rect.mBottom, 1.0f); gGL.begin(LLRender::TRIANGLE_STRIP); { -- cgit v1.2.3 From 0fc76aad910bad219e8394b93c2aa336cf7ff22a Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Sat, 21 Sep 2024 21:26:01 +0200 Subject: #2618 Roles and Members tab is a mess (show ctrl pos in debug views) --- indra/llui/llview.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 7d6c937b85..b4cd4075cf 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1370,8 +1370,9 @@ void LLView::drawDebugRect() y = rect_height - LINE_HEIGHT * (depth % lines + 1); - std::string debug_text = llformat("%s (%d x %d)", getName().c_str(), - debug_rect.getWidth(), debug_rect.getHeight()); + std::string debug_text = llformat("%s [%d, %d] + (%d x %d)", getName().c_str(), + debug_rect.mLeft, mParentView->getRect().getHeight() - debug_rect.mTop, + debug_rect.getWidth(), debug_rect.getHeight()); LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color, LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); } -- cgit v1.2.3 From 06b6d5ed37943ea330c7f7f2a1a3a43e951c9f8b Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Sun, 22 Sep 2024 08:22:04 +0200 Subject: #2618 Roles and Members tab is a mess --- indra/llui/llview.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index b4cd4075cf..0206e46b57 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1370,9 +1370,10 @@ void LLView::drawDebugRect() y = rect_height - LINE_HEIGHT * (depth % lines + 1); - std::string debug_text = llformat("%s [%d, %d] + (%d x %d)", getName().c_str(), + std::string debug_text = llformat("%s [%d, %d] + (%d x %d) = [%d, %d]", getName().c_str(), debug_rect.mLeft, mParentView->getRect().getHeight() - debug_rect.mTop, - debug_rect.getWidth(), debug_rect.getHeight()); + debug_rect.getWidth(), debug_rect.getHeight(), + debug_rect.mRight, mParentView->getRect().getHeight() - debug_rect.mBottom); LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color, LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); } -- cgit v1.2.3 From 86d2fb93b73d2689104c564ec859be7f83416691 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 23 Sep 2024 23:49:06 +0200 Subject: #2559 No mouseover if a link is embedded with an emoji --- indra/llui/llstyle.cpp | 25 +++++- indra/llui/llstyle.h | 11 ++- indra/llui/lltextbase.cpp | 222 +++++++++++++++++++++++++--------------------- indra/llui/lltextbase.h | 33 ++++--- 4 files changed, 167 insertions(+), 124 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llstyle.cpp b/indra/llui/llstyle.cpp index df4b0ef6a0..f1d57a2273 100644 --- a/indra/llui/llstyle.cpp +++ b/indra/llui/llstyle.cpp @@ -43,8 +43,8 @@ LLStyle::Params::Params() image("image"), link_href("href"), is_link("is_link") -{} - +{ +} LLStyle::LLStyle(const LLStyle::Params& p) : mVisible(p.visible), @@ -57,14 +57,31 @@ LLStyle::LLStyle(const LLStyle::Params& p) mDropShadow(p.drop_shadow), mImagep(p.image()), mAlpha(p.alpha) -{} +{ +} + +LLStyle* LLStyle::makeCopy() const +{ + LLStyle* copy = new LLStyle(); + copy->mDropShadow = mDropShadow; + copy->mFontName = mFontName; + copy->mLink = mLink; + copy->mColor = mColor; + copy->mReadOnlyColor = mReadOnlyColor; + copy->mSelectedColor = mSelectedColor; + copy->mFont = mFont; + copy->mImagep = mImagep; + copy->mAlpha = mAlpha; + copy->mVisible = mVisible; + copy->mIsLink = mIsLink; + return copy; +} void LLStyle::setFont(const LLFontGL* font) { mFont = font; } - const LLFontGL* LLStyle::getFont() const { return mFont; diff --git a/indra/llui/llstyle.h b/indra/llui/llstyle.h index e506895de5..d3a50f99a5 100644 --- a/indra/llui/llstyle.h +++ b/indra/llui/llstyle.h @@ -33,6 +33,10 @@ #include "lluiimage.h" class LLFontGL; +class LLStyle; + +typedef LLPointer LLStyleSP; +typedef LLPointer LLStyleConstSP; class LLStyle : public LLRefCount { @@ -52,6 +56,9 @@ public: Params(); }; LLStyle(const Params& p = Params()); + LLStyleSP clone() const { return makeCopy(); } + LLStyleConstSP cloneConst() const { return makeCopy(); } + public: const LLUIColor& getColor() const { return mColor; } void setColor(const LLUIColor &color) { mColor = color; } @@ -104,6 +111,7 @@ public: protected: ~LLStyle() = default; + LLStyle* makeCopy() const; private: std::string mFontName; @@ -118,7 +126,4 @@ private: bool mIsLink; }; -typedef LLPointer LLStyleSP; -typedef LLPointer LLStyleConstSP; - #endif // LL_LLSTYLE_H diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 1bfb137e0f..2a8b71055d 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -886,7 +886,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s } // shift remaining segments to right - for(;seg_iter != mSegments.end(); ++seg_iter) + for (;seg_iter != mSegments.end(); ++seg_iter) { LLTextSegmentPtr segmentp = *seg_iter; segmentp->setStart(segmentp->getStart() + insert_len); @@ -913,22 +913,29 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s // Insert special segments where necessary (insertSegment takes care of splitting normal text segments around them for us) if (mUseEmoji) { - LLStyleSP emoji_style; LLEmojiDictionary* ed = LLEmojiDictionary::instanceExists() ? LLEmojiDictionary::getInstance() : NULL; - for (S32 text_kitty = 0, text_len = static_cast(wstr.size()); text_kitty < text_len; text_kitty++) + for (std::size_t i = 0; i < wstr.size(); ++i) { - llwchar code = wstr[text_kitty]; + llwchar code = wstr[i]; bool isEmoji = ed ? ed->isEmoji(code) : LLStringOps::isEmoji(code); if (isEmoji) { - if (!emoji_style) + S32 new_seg_start = pos + (S32)i; + segment_set_t::iterator cur_seg_iter = getSegIterContaining(new_seg_start); + LLStyleSP new_style; + if (cur_seg_iter != mSegments.end()) // Should be 100% { - emoji_style = new LLStyle(getStyleParams()); - emoji_style->setFont(LLFontGL::getFontEmojiLarge()); + // Use font EmojiLarge but preserve the target font style + new_style = (*cur_seg_iter)->getStyle()->clone(); + U8 font_style = new_style->getFont()->getFontDesc().getStyle(); + new_style->setFont(LLFontGL::getFont(LLFontDescriptor("Emoji", "Large", font_style))); } - - S32 new_seg_start = pos + text_kitty; - insertSegment(new LLEmojiTextSegment(emoji_style, new_seg_start, new_seg_start + 1, *this)); + else // Very unlikely + { + new_style = new LLStyle(getStyleParams()); + new_style->setFont(LLFontGL::getFontEmojiLarge()); + } + insertSegment(new LLEmojiTextSegment(new_style, new_seg_start, new_seg_start + 1, *this)); } } } @@ -1059,14 +1066,18 @@ void LLTextBase::insertSegment(LLTextSegmentPtr segment_to_insert) S32 old_segment_end = cur_segmentp->getEnd(); // split old at start point for new segment cur_segmentp->setEnd(segment_to_insert->getStart()); - // advance to next segment - // insert remainder of old segment - LLStyleConstSP sp = cur_segmentp->getStyle(); - LLTextSegmentPtr remainder_segment = new LLNormalTextSegment( sp, segment_to_insert->getStart(), old_segment_end, *this); - mSegments.insert(cur_seg_iter, remainder_segment); - remainder_segment->linkToDocument(this); // insert new segment before remainder of old segment mSegments.insert(cur_seg_iter, segment_to_insert); + // advance to next segment + // insert remainder of old segment + if (segment_to_insert->getEnd() < old_segment_end) + { + LLTextSegmentPtr remainder_segment = cur_segmentp->clone(*this); + remainder_segment->setStart(segment_to_insert->getEnd()); + remainder_segment->setEnd(old_segment_end); + mSegments.insert(cur_seg_iter, remainder_segment); + remainder_segment->linkToDocument(this); + } segment_to_insert->linkToDocument(this); // at this point, there will be two overlapping segments owning the text @@ -1080,7 +1091,7 @@ void LLTextBase::insertSegment(LLTextSegmentPtr segment_to_insert) // now delete/truncate remaining segments as necessary // cur_seg_iter points to segment before incoming segment - while(cur_seg_iter != mSegments.end()) + while (cur_seg_iter != mSegments.end()) { cur_segmentp = *cur_seg_iter; if (cur_segmentp == segment_to_insert) @@ -1966,7 +1977,7 @@ void LLTextBase::updateSegments() createDefaultSegment(); } -void LLTextBase::getSegmentAndOffset( S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp ) const +void LLTextBase::getSegmentAndOffset(S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp) const { *seg_iter = getSegIterContaining(startpos); if (*seg_iter == mSegments.end()) @@ -1979,7 +1990,7 @@ void LLTextBase::getSegmentAndOffset( S32 startpos, segment_set_t::const_iterato } } -void LLTextBase::getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp ) +void LLTextBase::getSegmentAndOffset(S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp) { *seg_iter = getSegIterContaining(startpos); if (*seg_iter == mSegments.end()) @@ -1997,7 +2008,8 @@ LLTextBase::segment_set_t::iterator LLTextBase::getEditableSegIterContaining(S32 segment_set_t::iterator it = getSegIterContaining(index); segment_set_t::iterator orig_it = it; - if (it == mSegments.end()) return it; + if (it == mSegments.end()) + return it; if (!(*it)->canEdit() && index == (*it)->getStart() @@ -2009,6 +2021,7 @@ LLTextBase::segment_set_t::iterator LLTextBase::getEditableSegIterContaining(S32 return it; } } + return orig_it; } @@ -2016,7 +2029,8 @@ LLTextBase::segment_set_t::const_iterator LLTextBase::getEditableSegIterContaini { segment_set_t::const_iterator it = getSegIterContaining(index); segment_set_t::const_iterator orig_it = it; - if (it == mSegments.end()) return it; + if (it == mSegments.end()) + return it; if (!(*it)->canEdit() && index == (*it)->getStart() @@ -2028,6 +2042,7 @@ LLTextBase::segment_set_t::const_iterator LLTextBase::getEditableSegIterContaini return it; } } + return orig_it; } @@ -2036,7 +2051,10 @@ LLTextBase::segment_set_t::iterator LLTextBase::getSegIterContaining(S32 index) static LLPointer index_segment = new LLIndexSegment(); // when there are no segments, we return the end iterator, which must be checked by caller - if (mSegments.size() <= 1) { return mSegments.begin(); } + if (mSegments.size() <= 1) + { + return mSegments.begin(); + } index_segment->setStart(index); index_segment->setEnd(index); @@ -2049,7 +2067,10 @@ LLTextBase::segment_set_t::const_iterator LLTextBase::getSegIterContaining(S32 i static LLPointer index_segment = new LLIndexSegment(); // when there are no segments, we return the end iterator, which must be checked by caller - if (mSegments.size() <= 1) { return mSegments.begin(); } + if (mSegments.size() <= 1) + { + return mSegments.begin(); + } index_segment->setStart(index); index_segment->setEnd(index); @@ -2058,7 +2079,7 @@ LLTextBase::segment_set_t::const_iterator LLTextBase::getSegIterContaining(S32 i } // Finds the text segment (if any) at the give local screen position -LLTextSegmentPtr LLTextBase::getSegmentAtLocalPos( S32 x, S32 y, bool hit_past_end_of_line) +LLTextSegmentPtr LLTextBase::getSegmentAtLocalPos(S32 x, S32 y, bool hit_past_end_of_line) { // Find the cursor position at the requested local screen position S32 offset = getDocIndexFromLocalCoord( x, y, false, hit_past_end_of_line); @@ -2067,10 +2088,8 @@ LLTextSegmentPtr LLTextBase::getSegmentAtLocalPos( S32 x, S32 y, bool hit_past_e { return *seg_iter; } - else - { - return LLTextSegmentPtr(); - } + + return LLTextSegmentPtr(); } void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) @@ -2078,7 +2097,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) // work out the XUI menu file to use for this url LLUrlMatch match; std::string url = in_url; - if (! LLUrlRegistry::instance().findUrl(url, match)) + if (!LLUrlRegistry::instance().findUrl(url, match)) { return; } @@ -2192,10 +2211,8 @@ static LLUIImagePtr image_from_icon_name(const std::string& icon_name) { return LLUI::getUIImageByID( LLUUID(icon_name) ); } - else - { - return LLUI::getUIImage(icon_name); - } + + return LLUI::getUIImage(icon_name); } @@ -2205,17 +2222,17 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para LLStyle::Params style_params(getStyleParams()); style_params.overwriteFrom(input_params); - S32 part = (S32)LLTextParser::WHOLE; + LLTextParser::EHighlightPosition part = LLTextParser::WHOLE; if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358). { - S32 start=0,end=0; + U32 next = 0; LLUrlMatch match; std::string text = new_text; while (LLUrlRegistry::instance().findUrl(text, match, boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3), isContentTrusted() || mAlwaysShowIcons)) { - start = match.getStart(); - end = match.getEnd()+1; + U32 start = match.getStart(); + next = match.getEnd() + 1; LLStyle::Params link_params(style_params); link_params.overwriteFrom(match.getStyle()); @@ -2223,16 +2240,16 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para // output the text before the Url if (start > 0) { - if (part == (S32)LLTextParser::WHOLE || - part == (S32)LLTextParser::START) + if (part == LLTextParser::WHOLE || + part == LLTextParser::START) { - part = (S32)LLTextParser::START; + part = LLTextParser::START; } else { - part = (S32)LLTextParser::MIDDLE; + part = LLTextParser::MIDDLE; } - std::string subtext=text.substr(0,start); + std::string subtext = text.substr(0, start); appendAndHighlightText(subtext, part, style_params); } @@ -2244,14 +2261,8 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para } // output the styled Url - appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.underlineOnHoverOnly()); - bool tooltip_required = !match.getTooltip().empty(); - - // set the tooltip for the Url label - if (tooltip_required) - { - setLastSegmentToolTip(match.getTooltip()); - } + appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.underlineOnHoverOnly(), match.getTooltip()); + bool tooltip_required = !match.getTooltip().empty(); // show query part of url with gray color only for LLUrlEntryHTTP url entries std::string label = match.getQuery(); @@ -2259,31 +2270,27 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para { link_params.color = LLColor4::grey; link_params.readonly_color = LLColor4::grey; - appendAndHighlightTextImpl(label, part, link_params, match.underlineOnHoverOnly()); - - // set the tooltip for the query part of url - if (tooltip_required) - { - setLastSegmentToolTip(match.getTooltip()); - } + appendAndHighlightTextImpl(label, part, link_params, match.underlineOnHoverOnly(), match.getTooltip()); } - // move on to the rest of the text after the Url - if (end < (S32)text.length()) - { - text = text.substr(end,text.length() - end); - end=0; - part=(S32)LLTextParser::END; - } - else - { + if (next >= text.length()) break; - } + + // move on to the rest of the text after the Url + text = text.substr(next, text.length() - next); + next = 0; + part = LLTextParser::END; } - if (part != (S32)LLTextParser::WHOLE) - part=(S32)LLTextParser::END; - if (end < (S32)text.length()) + + if (part != LLTextParser::WHOLE) + { + part = LLTextParser::END; + } + + if (next < text.length()) + { appendAndHighlightText(text, part, style_params); + } } else { @@ -2307,7 +2314,7 @@ void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, c if (new_text.empty()) return; - if(prepend_newline) + if (prepend_newline) appendLineBreakSegment(input_params); appendTextImpl(new_text,input_params); } @@ -2365,6 +2372,7 @@ S32 LLTextBase::removeFirstLine() removeStringNoUndo(0, length); return length; } + return 0; } @@ -2407,10 +2415,11 @@ void LLTextBase::appendLineBreakSegment(const LLStyle::Params& style_params) void LLTextBase::appendImageSegment(const LLStyle::Params& style_params) { - if(getPlainText()) + if (getPlainText()) { return; } + segment_vec_t segments; LLStyleConstSP sp(new LLStyle(style_params)); segments.push_back(new LLImageTextSegment(sp, getLength(),*this)); @@ -2427,7 +2436,8 @@ void LLTextBase::appendWidget(const LLInlineViewSegment::Params& params, const s insertStringNoUndo(getLength(), widget_wide_text, &segments); } -void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only) +void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, LLTextParser::EHighlightPosition highlight_part, + const LLStyle::Params& style_params, bool underline_on_hover_only, std::string tooltip) { // Save old state S32 selection_start = mSelectionStart; @@ -2445,7 +2455,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig { LLStyle::Params highlight_params(style_params); - auto pieces = LLTextParser::instance().parsePartialLineHighlights(new_text, highlight_params.color, (LLTextParser::EHighlightPosition)highlight_part); + auto pieces = LLTextParser::instance().parsePartialLineHighlights(new_text, highlight_params.color, highlight_part); for (S32 i = 0; i < pieces.size(); i++) { const auto& piece_pair = pieces[i]; @@ -2467,8 +2477,13 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig { segmentp = new LLNormalTextSegment(sp, cur_length, cur_length + static_cast(wide_text.size()), *this); } - segment_vec_t segments; - segments.push_back(segmentp); + + if (!tooltip.empty()) + { + segmentp->setToolTip(tooltip); + } + + segment_vec_t segments = { segmentp }; insertStringNoUndo(cur_length, wide_text, &segments); } } @@ -2477,22 +2492,28 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig LLWString wide_text; wide_text = utf8str_to_wstring(new_text); - segment_vec_t segments; S32 segment_start = old_length; S32 segment_end = old_length + static_cast(wide_text.size()); LLStyleConstSP sp(new LLStyle(style_params)); + LLTextSegmentPtr segmentp; if (underline_on_hover_only || mSkipLinkUnderline) { LLStyle::Params normal_style_params(style_params); normal_style_params.font.style("NORMAL"); LLStyleConstSP normal_sp(new LLStyle(normal_style_params)); - segments.push_back(new LLOnHoverChangeableTextSegment(sp, normal_sp, segment_start, segment_end, *this)); + segmentp = new LLOnHoverChangeableTextSegment(sp, normal_sp, segment_start, segment_end, *this); } else { - segments.push_back(new LLNormalTextSegment(sp, segment_start, segment_end, *this)); + segmentp = new LLNormalTextSegment(sp, segment_start, segment_end, *this); } + if (!tooltip.empty()) + { + segmentp->setToolTip(tooltip); + } + + segment_vec_t segments = { segmentp }; insertStringNoUndo(getLength(), wide_text, &segments); } @@ -2515,7 +2536,9 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig } } -void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only) +void LLTextBase::appendAndHighlightText(const std::string &new_text, + LLTextParser::EHighlightPosition highlight_part, + const LLStyle::Params& style_params, bool underline_on_hover_only) { if (new_text.empty()) { @@ -2527,13 +2550,15 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlig while (pos != std::string::npos) { - if (pos != start) + if (pos > start) { - std::string str = std::string(new_text,start,pos-start); + std::string str = std::string(new_text, start, pos - start); appendAndHighlightTextImpl(str, highlight_part, style_params, underline_on_hover_only); } appendLineBreakSegment(style_params); - start = pos+1; + start = pos + 1; + if (start >= new_text.length()) + return; pos = new_text.find("\n", start); } @@ -3259,26 +3284,9 @@ boost::signals2::connection LLTextBase::setIsObjectBlockedCallback(const is_bloc // LLTextSegment::~LLTextSegment() -{} - -// static -LLStyleSP LLTextSegment::cloneStyle(LLTextBase& target, const LLStyle* source) { - // Take most params from target - LLStyle::Params params = target.getStyleParams(); - LLStyle* style = new LLStyle(params); - - // Take some params from source - style->setLinkHREF(source->getLinkHREF()); - if (source->isImage()) - { - style->setImage(source->getImage()->getName()); - } - - return style; } - bool LLTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { width = 0; height = 0; return false; } bool LLTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const { @@ -3614,19 +3622,27 @@ void LLNormalTextSegment::setToolTip(const std::string& tooltip) // we cannot replace a keyword tooltip that's loaded from a file if (mToken) { - LL_WARNS() << "LLTextSegment::setToolTip: cannot replace keyword tooltip." << LL_ENDL; + LL_WARNS() << "Cannot replace keyword tooltip." << LL_ENDL; return; } mTooltip = tooltip; } +LLStyleConstSP LLNormalTextSegment::cloneStyle(LLTextBase& target, const LLStyle* source) const +{ + return (&target == &mEditor) ? mStyle : mStyle->cloneConst(); +} + // virtual LLTextSegmentPtr LLNormalTextSegment::clone(LLTextBase& target) const { LLStyleConstSP sp(cloneStyle(target, mStyle)); - return new LLNormalTextSegment(sp, mStart, mEnd, target); + LLNormalTextSegment* copy = new LLNormalTextSegment(sp, mStart, mEnd, target); + copy->mTooltip = mTooltip; + return copy; } +// virtual bool LLNormalTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { height = 0; @@ -3994,7 +4010,7 @@ LLImageTextSegment::~LLImageTextSegment() // virtual LLTextSegmentPtr LLImageTextSegment::clone(LLTextBase& target) const { - LLStyleConstSP sp(cloneStyle(target, mStyle)); + LLStyleConstSP sp((&target == &mEditor) ? mStyle : mStyle->cloneConst()); return new LLImageTextSegment(sp, mStart, target); } diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 76d4e160af..b3fde84f5f 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -35,6 +35,7 @@ #include "llstyle.h" #include "llkeywords.h" #include "llpanel.h" +#include "lltextparser.h" #include #include @@ -64,7 +65,6 @@ public: {} virtual ~LLTextSegment(); virtual LLTextSegmentPtr clone(LLTextBase& terget) const { return new LLTextSegment(mStart, mEnd); } - static LLStyleSP cloneStyle(LLTextBase& target, const LLStyle* source); bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const; @@ -132,6 +132,7 @@ public: LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor ); LLNormalTextSegment( const LLUIColor& color, S32 start, S32 end, LLTextBase& editor, bool is_visible = true); virtual ~LLNormalTextSegment(); + LLStyleConstSP cloneStyle(LLTextBase& target, const LLStyle* source) const; /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const; /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; @@ -267,7 +268,7 @@ class LLLineBreakTextSegment : public LLTextSegment { public: - LLLineBreakTextSegment(LLStyleConstSP style,S32 pos); + LLLineBreakTextSegment(LLStyleConstSP style, S32 pos); LLLineBreakTextSegment(S32 pos); ~LLLineBreakTextSegment(); /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const; @@ -282,19 +283,19 @@ private: class LLImageTextSegment : public LLTextSegment { public: - LLImageTextSegment(LLStyleConstSP style,S32 pos,class LLTextBase& editor); + LLImageTextSegment(LLStyleConstSP style, S32 pos,class LLTextBase& editor); ~LLImageTextSegment(); /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const; - /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; - S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 char_offset, S32 max_chars, S32 line_ind) const; - F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); + /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; + /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 char_offset, S32 max_chars, S32 line_ind) const; + /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); /*virtual*/ bool handleToolTip(S32 x, S32 y, MASK mask); /*virtual*/ void setToolTip(const std::string& tooltip); private: - class LLTextBase& mEditor; + LLTextBase& mEditor; LLStyleConstSP mStyle; protected: @@ -622,16 +623,19 @@ protected: void drawText(); // modify contents - S32 insertStringNoUndo(S32 pos, const LLWString &wstr, segment_vec_t* segments = NULL); // returns num of chars actually inserted + S32 insertStringNoUndo(S32 pos, const LLWString &wstr, + segment_vec_t* segments = NULL); // returns num of chars actually inserted S32 removeStringNoUndo(S32 pos, S32 length); S32 overwriteCharNoUndo(S32 pos, llwchar wc); - void appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& stylep, bool underline_on_hover_only = false); + void appendAndHighlightText(const std::string &new_text, + LLTextParser::EHighlightPosition highlight_part, + const LLStyle::Params& stylep, bool underline_on_hover_only = false); // manage segments - void getSegmentAndOffset( S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp ) const; - void getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp ); - LLTextSegmentPtr getSegmentAtLocalPos( S32 x, S32 y, bool hit_past_end_of_line = true); + void getSegmentAndOffset(S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp) const; + void getSegmentAndOffset(S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp); + LLTextSegmentPtr getSegmentAtLocalPos(S32 x, S32 y, bool hit_past_end_of_line = true); segment_set_t::iterator getEditableSegIterContaining(S32 index); segment_set_t::const_iterator getEditableSegIterContaining(S32 index) const; segment_set_t::iterator getSegIterContaining(S32 index); @@ -673,8 +677,9 @@ protected: // avatar names are looked up. void replaceUrl(const std::string &url, const std::string &label, const std::string& icon); - void appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params = LLStyle::Params()); - void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only = false); + void appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params = LLStyle::Params()); + void appendAndHighlightTextImpl(const std::string &new_text, LLTextParser::EHighlightPosition highlight_part, + const LLStyle::Params& style_params, bool underline_on_hover_only, std::string tooltip = LLStringUtil::null); S32 normalizeUri(std::string& uri); protected: -- cgit v1.2.3 From 4f7a0a3da2d10217e399d22508262e197c208c22 Mon Sep 17 00:00:00 2001 From: Ansariel Hiller Date: Wed, 25 Sep 2024 18:10:00 +0200 Subject: Restore currently entered text in chat entry textbox after going through history with Ctrl-PgUp/PgDown (#2680) --- indra/llui/llchatentry.cpp | 16 +++++++++++----- indra/llui/llchatentry.h | 2 ++ 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llchatentry.cpp b/indra/llui/llchatentry.cpp index da5afd0386..e8d942b8af 100644 --- a/indra/llui/llchatentry.cpp +++ b/indra/llui/llchatentry.cpp @@ -45,7 +45,8 @@ LLChatEntry::LLChatEntry(const Params& p) mExpandLinesCount(p.expand_lines_count), mPrevLinesCount(0), mSingleLineMode(false), - mPrevExpandedLineCount(S32_MAX) + mPrevExpandedLineCount(S32_MAX), + mCurrentInput("") { // Initialize current history line iterator mCurrentHistoryLine = mLineHistory.begin(); @@ -189,6 +190,7 @@ bool LLChatEntry::handleSpecialKey(const KEY key, const MASK mask) { needsReflow(); } + mCurrentInput = ""; break; case KEY_UP: @@ -196,6 +198,11 @@ bool LLChatEntry::handleSpecialKey(const KEY key, const MASK mask) { if (!mLineHistory.empty() && mCurrentHistoryLine > mLineHistory.begin()) { + if (mCurrentHistoryLine == mLineHistory.end()) + { + mCurrentInput = getText(); + } + setText(*(--mCurrentHistoryLine)); endOfDoc(); } @@ -210,16 +217,15 @@ bool LLChatEntry::handleSpecialKey(const KEY key, const MASK mask) case KEY_DOWN: if (mHasHistory && MASK_CONTROL == mask) { - if (!mLineHistory.empty() && mCurrentHistoryLine < (mLineHistory.end() - 1) ) + if (!mLineHistory.empty() && mCurrentHistoryLine < (mLineHistory.end() - 1)) { setText(*(++mCurrentHistoryLine)); endOfDoc(); } - else if (!mLineHistory.empty() && mCurrentHistoryLine == (mLineHistory.end() - 1) ) + else if (!mLineHistory.empty() && mCurrentHistoryLine == (mLineHistory.end() - 1)) { mCurrentHistoryLine++; - std::string empty(""); - setText(empty); + setText(mCurrentInput); needsReflow(); endOfDoc(); } diff --git a/indra/llui/llchatentry.h b/indra/llui/llchatentry.h index 5621ede1e7..9a0e8ee91e 100644 --- a/indra/llui/llchatentry.h +++ b/indra/llui/llchatentry.h @@ -101,6 +101,8 @@ private: S32 mExpandLinesCount; S32 mPrevLinesCount; S32 mPrevExpandedLineCount; + + std::string mCurrentInput; }; #endif /* LLCHATENTRY_H_ */ -- cgit v1.2.3 From d511ff7365284a4475b1d729cf3448d378c83341 Mon Sep 17 00:00:00 2001 From: Nicky Dasmijn Date: Sun, 29 Sep 2024 00:59:41 +0200 Subject: Linux/GCC 13 build fix for template specialization of pasteTextWithLinebreaks (#2729) GCC 13 did not like having a template<> inside the class body at all. Thus turn the specialization of pasteTextWithLinebreaks into a class methode pasteTextWithLinebreaksImpl. --- indra/llui/lltexteditor.cpp | 4 +--- indra/llui/lltexteditor.h | 5 ++--- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index c8cde90032..ecac800def 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1594,9 +1594,7 @@ void LLTextEditor::cleanStringForPaste(LLWString & clean_string) } } - -template <> -void LLTextEditor::pasteTextWithLinebreaks(const LLWString & clean_string) +void LLTextEditor::pasteTextWithLinebreaksImpl(const LLWString & clean_string) { std::basic_string::size_type start = 0; std::basic_string::size_type pos = clean_string.find('\n',start); diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 765c88a933..fab46a00e3 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -313,10 +313,9 @@ public: template void pasteTextWithLinebreaks(const STRINGTYPE& clean_string) { - pasteTextWithLinebreaks(ll_convert(clean_string)); + pasteTextWithLinebreaksImpl(ll_convert(clean_string)); } - template <> - void pasteTextWithLinebreaks(const LLWString & clean_string); + void pasteTextWithLinebreaksImpl(const LLWString & clean_string); private: void onKeyStroke(); -- cgit v1.2.3