summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
authorKitty Barnett <develop@catznip.com>2024-09-30 15:54:20 +0200
committerKitty Barnett <develop@catznip.com>2024-09-30 15:54:20 +0200
commited2d4f02d93459bf114ebeab8727d507b7bfc0ef (patch)
treea216907e2c01db7932c83e212319cb7a8c790013 /indra/llui
parenta8d8314cb9af193ea7ce95456fb308217ba28e3c (diff)
parenta409503653bebacbc498409806f9e1a4b97ed6ac (diff)
Merge branch 'develop' into rlva/base
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/CMakeLists.txt2
-rw-r--r--indra/llui/llbadge.cpp12
-rw-r--r--indra/llui/llchat.h19
-rw-r--r--indra/llui/llchatentry.cpp16
-rw-r--r--indra/llui/llchatentry.h2
-rw-r--r--indra/llui/llcommandmanager.cpp6
-rw-r--r--indra/llui/llcommandmanager.h2
-rw-r--r--indra/llui/llflashtimer.cpp6
-rw-r--r--indra/llui/llflashtimer.h2
-rw-r--r--indra/llui/llfloater.cpp24
-rw-r--r--indra/llui/llfloaterreg.cpp5
-rw-r--r--indra/llui/llfloaterreg.h2
-rw-r--r--indra/llui/llfloaterreglistener.cpp37
-rw-r--r--indra/llui/llfloaterreglistener.h3
-rw-r--r--indra/llui/llfolderview.cpp2
-rw-r--r--indra/llui/llfolderviewitem.cpp116
-rw-r--r--indra/llui/llfolderviewitem.h9
-rw-r--r--indra/llui/llluafloater.cpp324
-rw-r--r--indra/llui/llluafloater.h54
-rw-r--r--indra/llui/llmenugl.cpp4
-rw-r--r--indra/llui/llmenugl.h18
-rw-r--r--indra/llui/llnotifications.cpp2
-rw-r--r--indra/llui/llnotifications.h2
-rw-r--r--indra/llui/llnotificationslistener.cpp16
-rw-r--r--indra/llui/llscrolllistctrl.cpp2
-rw-r--r--indra/llui/llstatbar.cpp10
-rw-r--r--indra/llui/llstyle.cpp25
-rw-r--r--indra/llui/llstyle.h11
-rw-r--r--indra/llui/lltextbase.cpp286
-rw-r--r--indra/llui/lltextbase.h46
-rw-r--r--indra/llui/lltexteditor.cpp9
-rw-r--r--indra/llui/lltexteditor.h13
-rw-r--r--indra/llui/lltextvalidate.cpp1
-rw-r--r--indra/llui/lltoolbar.cpp2
-rw-r--r--indra/llui/llui.cpp3
-rw-r--r--indra/llui/lluictrl.cpp14
-rw-r--r--indra/llui/lluictrl.h47
-rw-r--r--indra/llui/llview.cpp6
-rw-r--r--indra/llui/llviewereventrecorder.cpp11
39 files changed, 931 insertions, 240 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index a0314cb5f2..69e1b57245 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -49,6 +49,7 @@ set(llui_SOURCE_FILES
lllineeditor.cpp
llloadingindicator.cpp
lllocalcliprect.cpp
+ llluafloater.cpp
llmenubutton.cpp
llmenugl.cpp
llmodaldialog.cpp
@@ -164,6 +165,7 @@ set(llui_HEADER_FILES
lllineeditor.h
llloadingindicator.h
lllocalcliprect.h
+ llluafloater.h
llmenubutton.h
llmenugl.h
llmodaldialog.h
diff --git a/indra/llui/llbadge.cpp b/indra/llui/llbadge.cpp
index c6654ee0aa..42b6f1f07b 100644
--- a/indra/llui/llbadge.cpp
+++ b/indra/llui/llbadge.cpp
@@ -204,13 +204,13 @@ 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.mRight, screen_rect.mTop, 1.0f);
- vertices[1] = LLVector3(screen_rect.mLeft, 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::QUADS);
+ gGL.begin(LLRender::TRIANGLE_STRIP);
{
gGL.vertexBatchPreTransformed(vertices, 4);
}
diff --git a/indra/llui/llchat.h b/indra/llui/llchat.h
index 5f75ed2f8d..8adb3a87ef 100644
--- a/indra/llui/llchat.h
+++ b/indra/llui/llchat.h
@@ -89,7 +89,8 @@ public:
mPosAgent(),
mURL(),
mChatStyle(CHAT_STYLE_NORMAL),
- mSessionID()
+ mSessionID(),
+ mIsScript(false)
{ }
std::string mText; // UTF-8 line of text
@@ -107,6 +108,22 @@ public:
std::string mURL;
EChatStyle mChatStyle;
LLUUID mSessionID;
+
+ bool mIsScript;
};
+static const std::string LUA_PREFIX("[LUA]");
+
+inline
+std::string without_LUA_PREFIX(const std::string& string, bool is_lua)
+{
+ if (is_lua)
+ {
+ return string.substr(LUA_PREFIX.size());
+ }
+ else
+ {
+ return string;
+ }
+}
#endif
diff --git a/indra/llui/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_ */
diff --git a/indra/llui/llcommandmanager.cpp b/indra/llui/llcommandmanager.cpp
index 03717da80b..812a360190 100644
--- a/indra/llui/llcommandmanager.cpp
+++ b/indra/llui/llcommandmanager.cpp
@@ -32,6 +32,7 @@
#include "llcommandmanager.h"
#include "lldir.h"
#include "llerror.h"
+#include "llsdutil.h"
#include "llxuiparser.h"
@@ -189,3 +190,8 @@ bool LLCommandManager::load()
return true;
}
+
+LLSD LLCommandManager::getCommandNames()
+{
+ return llsd::toArray(mCommands, [](const auto &cmd) { return cmd->name(); });
+ }
diff --git a/indra/llui/llcommandmanager.h b/indra/llui/llcommandmanager.h
index e6df0d3a4b..69d631a398 100644
--- a/indra/llui/llcommandmanager.h
+++ b/indra/llui/llcommandmanager.h
@@ -192,6 +192,8 @@ public:
LLCommand * getCommand(const LLCommandId& commandId);
LLCommand * getCommand(const std::string& name);
+ LLSD getCommandNames();
+
static bool load();
protected:
diff --git a/indra/llui/llflashtimer.cpp b/indra/llui/llflashtimer.cpp
index c3db24c987..2711e8088d 100644
--- a/indra/llui/llflashtimer.cpp
+++ b/indra/llui/llflashtimer.cpp
@@ -35,7 +35,7 @@ LLFlashTimer::LLFlashTimer(callback_t cb, S32 count, F32 period)
mIsCurrentlyHighlighted(false),
mUnset(false)
{
- mEventTimer.stop();
+ stop();
// By default use settings from settings.xml to be able change them via Debug settings. See EXT-5973.
// Due to Timer is implemented as derived class from EventTimer it is impossible to change period
@@ -74,12 +74,12 @@ void LLFlashTimer::startFlashing()
{
mIsFlashingInProgress = true;
mIsCurrentlyHighlighted = true;
- mEventTimer.start();
+ start();
}
void LLFlashTimer::stopFlashing()
{
- mEventTimer.stop();
+ stop();
mIsFlashingInProgress = false;
mIsCurrentlyHighlighted = false;
mCurrentTickCount = 0;
diff --git a/indra/llui/llflashtimer.h b/indra/llui/llflashtimer.h
index b55ce53fc0..988b577ed2 100644
--- a/indra/llui/llflashtimer.h
+++ b/indra/llui/llflashtimer.h
@@ -46,7 +46,7 @@ public:
LLFlashTimer(callback_t cb = NULL, S32 count = 0, F32 period = 0.0);
~LLFlashTimer() {};
- /*virtual*/ bool tick();
+ bool tick() override;
void startFlashing();
void stopFlashing();
diff --git a/indra/llui/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/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index a818e72f59..c4e6061a12 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -624,3 +624,8 @@ U32 LLFloaterReg::getVisibleFloaterInstanceCount()
return count;
}
+
+LLSD LLFloaterReg::getFloaterNames()
+{
+ return llsd::toArray(sGroupMap, [](const auto &pair) { return pair.first; });
+}
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index 94a67c8d8b..2873080c99 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -153,6 +153,8 @@ public:
static void blockShowFloaters(bool value) { sBlockShowFloaters = value;}
static U32 getVisibleFloaterInstanceCount();
+
+ static LLSD getFloaterNames();
};
#endif
diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp
index 17641b8375..6e5f048c27 100644
--- a/indra/llui/llfloaterreglistener.cpp
+++ b/indra/llui/llfloaterreglistener.cpp
@@ -37,6 +37,8 @@
#include "llfloaterreg.h"
#include "llfloater.h"
#include "llbutton.h"
+#include "llluafloater.h"
+#include "resultset.h"
LLFloaterRegListener::LLFloaterRegListener():
LLEventAPI("LLFloaterReg",
@@ -72,6 +74,18 @@ LLFloaterRegListener::LLFloaterRegListener():
"Simulate clicking the named [\"button\"] in the visible floater named in [\"name\"]",
&LLFloaterRegListener::clickButton,
requiredNameButton);
+
+ add("showLuaFloater",
+ "Open the new floater using XML file specified in [\"xml_path\"] with ID in [\"reqid\"]",
+ &LLLuaFloater::showLuaFloater, {llsd::map("xml_path", LLSD(), "reqid", LLSD())});
+ add("getFloaterEvents",
+ "Return the table of Lua Floater events which are send to the script",
+ &LLFloaterRegListener::getLuaFloaterEvents);
+
+ add("getFloaterNames",
+ "Return result set key [\"floaters\"] for names of all registered floaters",
+ &LLFloaterRegListener::getFloaterNames,
+ llsd::map("reply", LLSD::String()));
}
void LLFloaterRegListener::getBuildMap(const LLSD& event) const
@@ -113,6 +127,24 @@ void LLFloaterRegListener::instanceVisible(const LLSD& event) const
event);
}
+struct NameResultSet: public LL::ResultSet
+{
+ NameResultSet():
+ LL::ResultSet("floaters"),
+ mNames(LLFloaterReg::getFloaterNames())
+ {}
+ LLSD mNames;
+
+ int getLength() const override { return narrow(mNames.size()); }
+ LLSD getSingle(int index) const override { return mNames[index]; }
+};
+
+void LLFloaterRegListener::getFloaterNames(const LLSD &event) const
+{
+ auto nameresult = new NameResultSet;
+ sendReply(llsd::map("floaters", nameresult->getKeyLength()), event);
+}
+
void LLFloaterRegListener::clickButton(const LLSD& event) const
{
// If the caller requests a reply, build the reply.
@@ -154,3 +186,8 @@ void LLFloaterRegListener::clickButton(const LLSD& event) const
LLEventPumps::instance().obtain(replyPump).post(reply);
}
}
+
+void LLFloaterRegListener::getLuaFloaterEvents(const LLSD &event) const
+{
+ Response response(llsd::map("events", LLLuaFloater::getEventsData()), event);
+}
diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h
index a36072892c..42e7178cbc 100644
--- a/indra/llui/llfloaterreglistener.h
+++ b/indra/llui/llfloaterreglistener.h
@@ -49,6 +49,9 @@ private:
void toggleInstance(const LLSD& event) const;
void instanceVisible(const LLSD& event) const;
void clickButton(const LLSD& event) const;
+ void getFloaterNames(const LLSD &event) const;
+
+ void getLuaFloaterEvents(const LLSD &event) const;
};
#endif /* ! defined(LL_LLFLOATERREGLISTENER_H) */
diff --git a/indra/llui/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<LLFolderViewItem> r("folder_view_item");
// statics
std::map<U8, LLFontGL*> 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<LLFolderViewItem>();
+ 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<LLFolderViewItem>();
- 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<S32>(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<S32>(mViewModelItem->getFilterStringOffset())) - 2;
- S32 right = left + font->getWidth(combined_string.c_str(), static_cast<S32>(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<S32>(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<S32>(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<S32>(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<S32>(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<U8, LLFontGL*> 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};
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp
new file mode 100644
index 0000000000..ccdadc6ae0
--- /dev/null
+++ b/indra/llui/llluafloater.cpp
@@ -0,0 +1,324 @@
+/**
+ * @file llluafloater.cpp
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ *
+ */
+
+#include "llluafloater.h"
+
+#include "fsyspath.h"
+#include "llevents.h"
+
+#include "llcheckboxctrl.h"
+#include "llcombobox.h"
+#include "llscrolllistctrl.h"
+#include "lltexteditor.h"
+
+const std::string LISTENER_NAME("LLLuaFloater");
+
+std::set<std::string> EVENT_LIST = {
+ "commit",
+ "double_click",
+ "mouse_enter",
+ "mouse_leave",
+ "mouse_down",
+ "mouse_up",
+ "right_mouse_down",
+ "right_mouse_up",
+ "post_build",
+ "floater_close",
+ "keystroke"
+};
+
+LLLuaFloater::LLLuaFloater(const LLSD &key) :
+ LLFloater(key),
+ mDispatchListener(LLUUID::generateNewID().asString(), "action"),
+ mReplyPumpName(key["reply"].asString()),
+ mReqID(key)
+{
+ auto ctrl_lookup = [this](const LLSD &event, std::function<LLSD(LLUICtrl*,const LLSD&)> cb)
+ {
+ LLUICtrl *ctrl = getChild<LLUICtrl>(event["ctrl_name"].asString());
+ if (!ctrl)
+ {
+ LL_WARNS("LuaFloater") << "Control not found: " << event["ctrl_name"] << LL_ENDL;
+ return LLSD();
+ }
+ return cb(ctrl, event);
+ };
+
+ LLSD requiredParams = llsd::map("ctrl_name", LLSD(), "value", LLSD());
+ mDispatchListener.add("set_enabled", "", [ctrl_lookup](const LLSD &event)
+ {
+ return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { ctrl->setEnabled(event["value"].asBoolean()); return LLSD(); });
+ }, requiredParams);
+ mDispatchListener.add("set_visible", "", [ctrl_lookup](const LLSD &event)
+ {
+ return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { ctrl->setVisible(event["value"].asBoolean()); return LLSD(); });
+ }, requiredParams);
+ mDispatchListener.add("set_value", "", [ctrl_lookup](const LLSD &event)
+ {
+ return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { ctrl->setValue(event["value"]); return LLSD(); });
+ }, requiredParams);
+
+ mDispatchListener.add("add_list_element", "", [this](const LLSD &event)
+ {
+ LLScrollListCtrl *ctrl = getChild<LLScrollListCtrl>(event["ctrl_name"].asString());
+ if(ctrl)
+ {
+ LLSD element_data = event["value"];
+ if (element_data.isArray())
+ {
+ for (const auto &row : llsd::inArray(element_data))
+ {
+ ctrl->addElement(row);
+ }
+ }
+ else
+ {
+ ctrl->addElement(element_data);
+ }
+ }
+ }, requiredParams);
+
+ mDispatchListener.add("clear_list", "", [this](const LLSD &event)
+ {
+ LLScrollListCtrl *ctrl = getChild<LLScrollListCtrl>(event["ctrl_name"].asString());
+ if(ctrl)
+ {
+ ctrl->deleteAllItems();
+ }
+ }, llsd::map("ctrl_name", LLSD()));
+
+ mDispatchListener.add("add_text", "", [this](const LLSD &event)
+ {
+ LLTextEditor *editor = getChild<LLTextEditor>(event["ctrl_name"].asString());
+ if (editor)
+ {
+ editor->pasteTextWithLinebreaks(stringize(event["value"]));
+ editor->addLineBreakChar(true);
+ }
+ }, requiredParams);
+
+ mDispatchListener.add("set_label", "", [this](const LLSD &event)
+ {
+ LLButton *btn = getChild<LLButton>(event["ctrl_name"].asString());
+ if (btn)
+ {
+ btn->setLabel((event["value"]).asString());
+ }
+ }, requiredParams);
+
+ mDispatchListener.add("set_title", "", [this](const LLSD &event)
+ {
+ setTitle(event["value"].asString());
+ }, llsd::map("value", LLSD()));
+
+ mDispatchListener.add("get_value", "", [ctrl_lookup](const LLSD &event)
+ {
+ return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { return llsd::map("value", ctrl->getValue()); });
+ }, llsd::map("ctrl_name", LLSD(), "reqid", LLSD()));
+
+ mDispatchListener.add("get_selected_id", "", [this](const LLSD &event)
+ {
+ LLScrollListCtrl *ctrl = getChild<LLScrollListCtrl>(event["ctrl_name"].asString());
+ if (!ctrl)
+ {
+ LL_WARNS("LuaFloater") << "Control not found: " << event["ctrl_name"] << LL_ENDL;
+ return LLSD();
+ }
+ return llsd::map("value", ctrl->getCurrentID());
+ }, llsd::map("ctrl_name", LLSD(), "reqid", LLSD()));
+}
+
+LLLuaFloater::~LLLuaFloater()
+{
+ //post empty LLSD() to indicate done, in case it wasn't handled by the script after CLOSE_EVENT
+ post(LLSD());
+}
+
+bool LLLuaFloater::postBuild()
+{
+ for (LLView *view : *getChildList())
+ {
+ LLUICtrl *ctrl = dynamic_cast<LLUICtrl*>(view);
+ if (ctrl)
+ {
+ LLSD data;
+ data["ctrl_name"] = view->getName();
+
+ ctrl->setCommitCallback([this, data](LLUICtrl *ctrl, const LLSD &param)
+ {
+ LLSD event(data);
+ event["value"] = ctrl->getValue();
+ postEvent(event, "commit");
+ });
+ }
+ }
+
+ //optional field to send additional specified events to the script
+ if (mKey.has("extra_events"))
+ {
+ //the first value is ctrl name, the second contains array of events to send
+ for (const auto &[name, data] : llsd::inMap(mKey["extra_events"]))
+ {
+ for (const auto &event : llsd::inArray(data))
+ {
+ registerCallback(name, event);
+ }
+ }
+ }
+
+ //send pump name to the script after the floater is built
+ postEvent(llsd::map("command_name", mDispatchListener.getPumpName()), "post_build");
+
+ return true;
+}
+
+void LLLuaFloater::onClose(bool app_quitting)
+{
+ postEvent(llsd::map("app_quitting", app_quitting), "floater_close");
+}
+
+bool event_is(const std::string &event_name, const std::string &list_event)
+{
+ llassert(EVENT_LIST.find(list_event) != EVENT_LIST.end());
+ return (event_name == list_event);
+}
+
+void LLLuaFloater::registerCallback(const std::string &ctrl_name, const std::string &event)
+{
+ LLUICtrl *ctrl = getChild<LLUICtrl>(ctrl_name);
+ if (!ctrl) return;
+
+ LLSD data;
+ data["ctrl_name"] = ctrl_name;
+ data["event"] = event;
+
+ auto mouse_event_cb = [this, data](LLUICtrl *ctrl, const LLSD &param) { post(data); };
+
+ auto mouse_event_coords_cb = [this, data](LLUICtrl *ctrl, S32 x, S32 y, MASK mask)
+ {
+ LLSD event(data);
+ post(event.with("x", x).with("y", y));
+ };
+
+ auto post_with_value = [this, data](LLSD value)
+ {
+ LLSD event(data);
+ post(event.with("value", value));
+ };
+
+ if (event_is(event, "mouse_enter"))
+ {
+ ctrl->setMouseEnterCallback(mouse_event_cb);
+ }
+ else if (event_is(event, "mouse_leave"))
+ {
+ ctrl->setMouseLeaveCallback(mouse_event_cb);
+ }
+ else if (event_is(event, "mouse_down"))
+ {
+ ctrl->setMouseDownCallback(mouse_event_coords_cb);
+ }
+ else if (event_is(event, "mouse_up"))
+ {
+ ctrl->setMouseUpCallback(mouse_event_coords_cb);
+ }
+ else if (event_is(event, "right_mouse_down"))
+ {
+ ctrl->setRightMouseDownCallback(mouse_event_coords_cb);
+ }
+ else if (event_is(event, "right_mouse_up"))
+ {
+ ctrl->setRightMouseUpCallback(mouse_event_coords_cb);
+ }
+ else if (event_is(event, "double_click"))
+ {
+ LLScrollListCtrl *list = dynamic_cast<LLScrollListCtrl *>(ctrl);
+ if (list)
+ {
+ list->setDoubleClickCallback( [post_with_value, list](){ post_with_value(LLSD(list->getCurrentID())); });
+ }
+ else
+ {
+ ctrl->setDoubleClickCallback(mouse_event_coords_cb);
+ }
+ }
+ else if (event_is(event, "keystroke"))
+ {
+ LLTextEditor* text_editor = dynamic_cast<LLTextEditor*>(ctrl);
+ if (text_editor)
+ {
+ text_editor->setKeystrokeCallback([post_with_value](LLTextEditor *editor) { post_with_value(editor->getValue()); });
+ }
+ LLLineEditor* line_editor = dynamic_cast<LLLineEditor*>(ctrl);
+ if (line_editor)
+ {
+ line_editor->setKeystrokeCallback([post_with_value](LLLineEditor *editor, void* userdata) { post_with_value(editor->getValue()); }, NULL);
+ }
+ }
+ else
+ {
+ LL_WARNS("LuaFloater") << "Can't register callback for unknown event: " << event << " , control: " << ctrl_name << LL_ENDL;
+ }
+}
+
+void LLLuaFloater::post(const LLSD &data)
+{
+ // send event data to the script signed with ["reqid"] key
+ LLSD stamped_data(data);
+ mReqID.stamp(stamped_data);
+ LLEventPumps::instance().obtain(mReplyPumpName).post(stamped_data);
+}
+
+void LLLuaFloater::postEvent(LLSD data, const std::string &event_name)
+{
+ llassert(EVENT_LIST.find(event_name) != EVENT_LIST.end());
+ post(data.with("event", event_name));
+}
+
+void LLLuaFloater::showLuaFloater(const LLSD &data)
+{
+ fsyspath fs_path(data["xml_path"].asString());
+ std::string path = fs_path.lexically_normal().u8string();
+ if (!fs_path.is_absolute())
+ {
+ std::string lib_path = gDirUtilp->getExpandedFilename(LL_PATH_SCRIPTS, "lua");
+ path = (fsyspath(lib_path) / path).u8string();
+ }
+
+ LLLuaFloater *floater = new LLLuaFloater(data);
+ floater->buildFromFile(path);
+ floater->openFloater(floater->getKey());
+}
+
+LLSD LLLuaFloater::getEventsData()
+{
+ LLSD event_data;
+ for (auto &it : EVENT_LIST)
+ {
+ event_data.append(it);
+ }
+ return event_data;
+}
diff --git a/indra/llui/llluafloater.h b/indra/llui/llluafloater.h
new file mode 100644
index 0000000000..41132f926d
--- /dev/null
+++ b/indra/llui/llluafloater.h
@@ -0,0 +1,54 @@
+/**
+ * @file llluafloater.h
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLLUAFLOATER_H
+#define LL_LLLUAFLOATER_H
+
+#include "llfloater.h"
+#include "lleventdispatcher.h"
+#include "llevents.h"
+
+class LLLuaFloater : public LLFloater
+{
+public:
+ LLLuaFloater(const LLSD &key);
+ bool postBuild();
+ virtual ~LLLuaFloater();
+
+ void registerCallback(const std::string &ctrl_name, const std::string &event);
+ void onClose(bool app_quitting);
+
+ void post(const LLSD &data);
+ void postEvent(LLSD data, const std::string &event);
+ static void showLuaFloater(const LLSD &data);
+ static LLSD getEventsData();
+
+private:
+ LLReqID mReqID;
+ LLDispatchListener mDispatchListener;
+
+ std::string mReplyPumpName;
+};
+#endif
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 69ffa9a94f..cc770ca90a 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -2625,7 +2625,9 @@ void LLMenuGL::insert( S32 position, LLView * ctrl, bool arrange /*= true*/ )
{
LLMenuItemGL * item = dynamic_cast<LLMenuItemGL *>(ctrl);
- if (NULL == item || position < 0 || position >= mItems.size())
+ // If position == size(), std::advance() will return end() -- which is
+ // okay, because insert(end()) is the same as append().
+ if (NULL == item || position < 0 || position > mItems.size())
{
return;
}
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 66f84393fe..88608b20ab 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -562,9 +562,6 @@ public:
// add a context menu branch
bool appendContextSubMenu(LLMenuGL *menu);
- const LLFontGL *getFont() const { return mFont; }
-
- protected:
void createSpilloverBranch();
void cleanupSpilloverBranch();
// Add the menu item to this menu.
@@ -810,9 +807,10 @@ public:
void resetMenuTrigger() { mAltKeyTrigger = false; }
-private:
// add a menu - this will create a drop down menu.
- virtual bool appendMenu( LLMenuGL* menu );
+ virtual bool appendMenu(LLMenuGL *menu);
+
+private:
// rearrange the child rects so they fit the shape of the menu
// bar.
virtual void arrange( void );
@@ -948,16 +946,18 @@ public:
LLUICtrl::EnableCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2));
}
- static void addCommit(view_listener_t* listener, const std::string& name)
+ typedef LLUICtrl::CommitCallbackInfo cb_info;
+ static void addCommit(view_listener_t *listener, const std::string &name, cb_info::EUntrustedCall handle_untrusted = cb_info::UNTRUSTED_ALLOW)
{
- LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2));
+ LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name,
+ cb_info([listener](LLUICtrl*, const LLSD& param){ return listener->handleEvent(param); }, handle_untrusted));
}
- static void addMenu(view_listener_t* listener, const std::string& name)
+ static void addMenu(view_listener_t *listener, const std::string &name, cb_info::EUntrustedCall handle_untrusted = cb_info::UNTRUSTED_ALLOW)
{
// For now, add to both click and enable registries
addEnable(listener, name);
- addCommit(listener, name);
+ addCommit(listener, name, handle_untrusted);
}
static void cleanup()
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index cd80e7f63f..501ac26f9f 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -1243,7 +1243,7 @@ LLNotifications::LLNotifications()
mIgnoreAllNotifications(false)
{
mListener.reset(new LLNotificationsListener(*this));
- LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));
+ LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", { boost::bind(&LLNotifications::addFromCallback, this, _2) });
// touch the instance tracker for notification channels, so that it will still be around in our destructor
LLInstanceTracker<LLNotificationChannel, std::string>::instanceCount();
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 46286457cf..9b83da13ad 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -735,7 +735,7 @@ typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap;
// all of the built-in tests should attach to the "Visible" channel
//
class LLNotificationChannelBase :
- public LLEventTrackable,
+ public boost::signals2::trackable,
public LLRefCount
{
LOG_CLASS(LLNotificationChannelBase);
diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
index 9c1fc27c51..dc12834b3f 100644
--- a/indra/llui/llnotificationslistener.cpp
+++ b/indra/llui/llnotificationslistener.cpp
@@ -204,7 +204,7 @@ void LLNotificationsListener::ignore(const LLSD& params) const
}
}
-class LLNotificationsListener::Forwarder: public LLEventTrackable
+class LLNotificationsListener::Forwarder: public boost::signals2::trackable
{
LOG_CLASS(LLNotificationsListener::Forwarder);
public:
@@ -213,8 +213,10 @@ public:
mRespond(false)
{
// Connect to the specified channel on construction. Because
- // LLEventTrackable is a base, we should automatically disconnect when
- // destroyed.
+ // boost::signals2::trackable is a base, because we use boost::bind()
+ // below, and because connectPassedFilter() directly calls
+ // boost::signals2::signal::connect(), we should automatically
+ // disconnect when destroyed.
LLNotificationChannelPtr channelptr(llnotifications.getChannel(channel));
if (channelptr)
{
@@ -252,10 +254,10 @@ void LLNotificationsListener::forward(const LLSD& params)
if (! forward)
{
// This is a request to stop forwarding notifications on the specified
- // channel. The rest of the params don't matter.
- // Because mForwarders contains scoped_ptrs, erasing the map entry
- // DOES delete the heap Forwarder object. Because Forwarder derives
- // from LLEventTrackable, destroying it disconnects it from the
+ // channel. The rest of the params don't matter. Because mForwarders
+ // contains scoped_ptrs, erasing the map entry DOES delete the heap
+ // Forwarder object. Because Forwarder derives from
+ // boost::signals2::trackable, destroying it disconnects it from the
// channel.
mForwarders.erase(channel);
return;
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 445377d3a2..ea2caaa1c0 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -1975,7 +1975,7 @@ bool LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
// set up the callbacks for all of the avatar/group menu items
// (N.B. callbacks don't take const refs as id is local scope)
bool is_group = (mContextMenuType == MENU_GROUP);
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ ScopedRegistrarHelper registrar;
registrar.add("Url.ShowProfile", boost::bind(&LLScrollListCtrl::showProfile, id, is_group));
registrar.add("Url.SendIM", boost::bind(&LLScrollListCtrl::sendIM, id));
registrar.add("Url.AddFriend", boost::bind(&LLScrollListCtrl::addFriend, id));
diff --git a/indra/llui/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();
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<LLStyle> LLStyleSP;
+typedef LLPointer<const LLStyle> 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<LLStyle> LLStyleSP;
-typedef LLPointer<const LLStyle> LLStyleConstSP;
-
#endif // LL_LLSTYLE_H
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index e2d31085c4..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<S32>(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<LLIndexSegment> 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<LLIndexSegment> 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;
}
@@ -2091,7 +2110,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));
@@ -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,9 +2372,38 @@ S32 LLTextBase::removeFirstLine()
removeStringNoUndo(0, length);
return length;
}
+
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;
@@ -2379,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));
@@ -2399,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;
@@ -2417,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];
@@ -2439,8 +2477,13 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig
{
segmentp = new LLNormalTextSegment(sp, cur_length, cur_length + static_cast<S32>(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);
}
}
@@ -2449,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<S32>(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);
}
@@ -2487,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())
{
@@ -2499,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);
}
@@ -3231,7 +3284,8 @@ boost::signals2::connection LLTextBase::setIsObjectBlockedCallback(const is_bloc
//
LLTextSegment::~LLTextSegment()
-{}
+{
+}
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
@@ -3568,12 +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));
+ 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;
@@ -3701,6 +3770,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 +3801,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 +3831,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 +3878,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 +3972,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 +4007,16 @@ LLImageTextSegment::~LLImageTextSegment()
{
}
+// virtual
+LLTextSegmentPtr LLImageTextSegment::clone(LLTextBase& target) const
+{
+ LLStyleConstSP sp((&target == &mEditor) ? mStyle : mStyle->cloneConst());
+ 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..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 <string>
#include <vector>
@@ -45,6 +46,7 @@
class LLScrollContainer;
class LLContextMenu;
class LLUrlMatch;
+class LLTextBase;
///
/// A text segment is used to specify a subsection of a text string
@@ -62,6 +64,8 @@ public:
mEnd(end)
{}
virtual ~LLTextSegment();
+ virtual LLTextSegmentPtr clone(LLTextBase& terget) const { return new LLTextSegment(mStart, mEnd); }
+
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,8 @@ 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;
/*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const;
@@ -180,6 +186,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 +201,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 +212,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 +227,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 +245,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);
@@ -256,9 +268,10 @@ 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;
/*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);
@@ -270,17 +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*/ 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*/ 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 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:
@@ -510,6 +525,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);
@@ -607,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);
@@ -658,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:
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 3537c764b9..ecac800def 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -1131,7 +1131,7 @@ void LLTextEditor::removeChar()
// Add a single character to the text
S32 LLTextEditor::addChar(S32 pos, llwchar wc)
{
- if ((wstring_utf8_length(getWText()) + wchar_utf8_length(wc)) > mMaxTextByteLength)
+ if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) > mMaxTextByteLength)
{
LLUI::getInstance()->reportBadKeystroke();
return 0;
@@ -1166,12 +1166,12 @@ S32 LLTextEditor::addChar(S32 pos, llwchar wc)
void LLTextEditor::addChar(llwchar wc)
{
- if (!getEnabled())
+ if( !getEnabled() )
{
return;
}
- if (hasSelection())
+ if( hasSelection() )
{
deleteSelection(true);
}
@@ -1594,8 +1594,7 @@ void LLTextEditor::cleanStringForPaste(LLWString & clean_string)
}
}
-
-void LLTextEditor::pasteTextWithLinebreaks(LLWString & clean_string)
+void LLTextEditor::pasteTextWithLinebreaksImpl(const LLWString & clean_string)
{
std::basic_string<llwchar>::size_type start = 0;
std::basic_string<llwchar>::size_type pos = clean_string.find('\n',start);
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index e9e7070414..fab46a00e3 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -34,6 +34,7 @@
#include "llstyle.h"
#include "lleditmenuhandler.h"
#include "llviewborder.h" // for params
+#include "llstring.h"
#include "lltextbase.h"
#include "lltextvalidate.h"
@@ -249,7 +250,9 @@ protected:
// Undoable operations
void addChar(llwchar c); // at mCursorPos
S32 addChar(S32 pos, llwchar wc);
+public:
void addLineBreakChar(bool group_together = false);
+protected:
S32 overwriteChar(S32 pos, llwchar wc);
void removeChar();
S32 removeChar(S32 pos);
@@ -305,8 +308,16 @@ private:
//
void pasteHelper(bool is_primary);
void cleanStringForPaste(LLWString & clean_string);
- void pasteTextWithLinebreaks(LLWString & clean_string);
+public:
+ template <typename STRINGTYPE>
+ void pasteTextWithLinebreaks(const STRINGTYPE& clean_string)
+ {
+ pasteTextWithLinebreaksImpl(ll_convert(clean_string));
+ }
+ void pasteTextWithLinebreaksImpl(const LLWString & clean_string);
+
+private:
void onKeyStroke();
// Concrete TextCmd sub-classes used by the LLTextEditor base class
diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp
index 9a087d8230..84f8b9daf0 100644
--- a/indra/llui/lltextvalidate.cpp
+++ b/indra/llui/lltextvalidate.cpp
@@ -31,6 +31,7 @@
#include "lltextvalidate.h"
#include "llnotificationsutil.h"
+#include "lltimer.h"
#include "lltrans.h"
#include "llresmgr.h" // for LLLocale
diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp
index 5955a28fa3..6e6e332632 100644
--- a/indra/llui/lltoolbar.cpp
+++ b/indra/llui/lltoolbar.cpp
@@ -144,7 +144,7 @@ void LLToolBar::createContextMenu()
{
// Setup bindings specific to this instance for the context menu options
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar commit_reg;
+ CommitRegistrarHelper commit_reg(LLUICtrl::CommitCallbackRegistry::currentRegistrar());
commit_reg.add("Toolbars.EnableSetting", boost::bind(&LLToolBar::onSettingEnable, this, _2));
commit_reg.add("Toolbars.RemoveSelectedCommand", boost::bind(&LLToolBar::onRemoveSelectedCommand, this));
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index e36dae3955..b4299ae8e5 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -169,8 +169,7 @@ mHelpImpl(NULL)
LLFontGL::sShadowColor = LLUIColorTable::instance().getColor("ColorDropShadow");
- LLUICtrl::CommitCallbackRegistry::Registrar& reg = LLUICtrl::CommitCallbackRegistry::defaultRegistrar();
-
+ LLUICtrl::CommitRegistrarHelper reg(LLUICtrl::CommitCallbackRegistry::defaultRegistrar());
// Callbacks for associating controls with floater visibility:
reg.add("Floater.Toggle", [](LLUICtrl* ctrl, const LLSD& param) -> void { LLFloaterReg::toggleInstance(param.asStringRef()); });
reg.add("Floater.ToggleOrBringToFront", [](LLUICtrl* ctrl, const LLSD& param) -> void { LLFloaterReg::toggleInstanceOrBringToFront(param.asStringRef()); });
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index cbabb5a933..e3e8130f51 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -220,10 +220,10 @@ void LLUICtrl::initFromParams(const Params& p)
}
else
{
- commit_callback_t* initfunc = (CommitCallbackRegistry::getValue(p.init_callback.function_name));
- if (initfunc)
+ LLUICtrl::CommitCallbackInfo *info = (CommitCallbackRegistry::getValue(p.init_callback.function_name));
+ if (info && info->callback_func)
{
- (*initfunc)(this, p.init_callback.parameter);
+ (info->callback_func)(this, p.init_callback.parameter);
}
}
}
@@ -283,13 +283,13 @@ LLUICtrl::commit_signal_t::slot_type LLUICtrl::initCommitCallback(const CommitCa
{
std::string function_name = cb.function_name;
setFunctionName(function_name);
- commit_callback_t* func = (CommitCallbackRegistry::getValue(function_name));
- if (func)
+ LLUICtrl::CommitCallbackInfo *info = (CommitCallbackRegistry::getValue(function_name));
+ if (info && info->callback_func)
{
if (cb.parameter.isProvided())
- return boost::bind((*func), _1, cb.parameter);
+ return boost::bind((info->callback_func), _1, cb.parameter);
else
- return commit_signal_t::slot_type(*func);
+ return commit_signal_t::slot_type(info->callback_func);
}
else if (!function_name.empty())
{
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index 8cd9950917..2c73ff6b57 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -274,11 +274,56 @@ public:
template <typename F, typename DERIVED> class CallbackRegistry : public LLRegistrySingleton<std::string, F, DERIVED >
{};
+ struct CommitCallbackInfo
+ {
+ enum EUntrustedCall
+ {
+ UNTRUSTED_ALLOW,
+ UNTRUSTED_BLOCK,
+ UNTRUSTED_THROTTLE
+ };
+
+ CommitCallbackInfo(commit_callback_t func = {}, EUntrustedCall handle_untrusted = UNTRUSTED_ALLOW) :
+ callback_func(func),
+ handle_untrusted(handle_untrusted)
+ {
+ }
- class CommitCallbackRegistry : public CallbackRegistry<commit_callback_t, CommitCallbackRegistry>
+ public:
+ commit_callback_t callback_func;
+ EUntrustedCall handle_untrusted;
+ };
+ typedef LLUICtrl::CommitCallbackInfo cb_info;
+ class CommitCallbackRegistry : public CallbackRegistry<CommitCallbackInfo, CommitCallbackRegistry>
{
LLSINGLETON_EMPTY_CTOR(CommitCallbackRegistry);
};
+
+ class CommitRegistrarHelper
+ {
+ public:
+ CommitRegistrarHelper(LLUICtrl::CommitCallbackRegistry::Registrar &registrar) : mRegistrar(registrar) {}
+
+ template <typename... ARGS> void add(const std::string &name, ARGS &&...args)
+ {
+ mRegistrar.add(name, {std::forward<ARGS>(args)...});
+ }
+ private:
+ LLUICtrl::CommitCallbackRegistry::Registrar &mRegistrar;
+ };
+
+ class ScopedRegistrarHelper
+ {
+ public:
+ template <typename... ARGS> void add(const std::string &name, ARGS &&...args)
+ {
+ mRegistrar.add(name, {std::forward<ARGS>(args)...});
+ }
+
+ private:
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar mRegistrar;
+ };
+
// the enable callback registry is also used for visiblity callbacks
class EnableCallbackRegistry : public CallbackRegistry<enable_callback_t, EnableCallbackRegistry>
{
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 7d6c937b85..0206e46b57 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -1370,8 +1370,10 @@ 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) = [%d, %d]", getName().c_str(),
+ debug_rect.mLeft, mParentView->getRect().getHeight() - debug_rect.mTop,
+ 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);
}
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<std::string>(uni_char) << "\n" << LL_ENDL;
- event.insert("char",
- LLSD( wstring_to_utf8str(LLWString( 1,uni_char)) )
- );
+ event.insert("char", LLSD(ll_convert_to<std::string>(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