Merge branch 'release/2025.04' of https://github.com/secondlife/viewer
# Conflicts: # indra/llui/llflatlistview.cpp # indra/llui/llstyle.cpp # indra/llui/llstyle.h # indra/llui/lltextbase.cpp # indra/llui/llurlmatch.cpp # indra/llui/llurlmatch.h # indra/llui/llurlregistry.cpp # indra/llui/llurlregistry.h # indra/newview/llavatarlist.cpp # indra/newview/llavatarlist.h # indra/newview/llavatarlistitem.cpp # indra/newview/llavatarlistitem.h # indra/newview/llfloaternewfeaturenotification.cpp # indra/newview/llinventorybridge.cpp # indra/newview/llmeshrepository.cpp # indra/newview/llpanelprofile.cpp # indra/newview/llviewerchat.cpp # indra/newview/llviewerfloaterreg.cpp # indra/newview/llvovolume.cpp # indra/newview/skins/default/colors.xmlmaster
commit
cf2f48de06
|
|
@ -398,7 +398,7 @@ protected:
|
|||
|
||||
private:
|
||||
bool mLLSDDirty;
|
||||
bool mDirty;
|
||||
bool mDirty; // gates updateSettings
|
||||
bool mReplaced; // super dirty!
|
||||
|
||||
static LLSD combineSDMaps(const LLSD &first, const LLSD &other);
|
||||
|
|
|
|||
|
|
@ -1936,6 +1936,7 @@ LLUUID LLSettingsSky::getCloudNoiseTextureId() const
|
|||
void LLSettingsSky::setCloudNoiseTextureId(const LLUUID &id)
|
||||
{
|
||||
mCloudTextureId = id;
|
||||
setDirtyFlag(true);
|
||||
setLLSDDirty();
|
||||
}
|
||||
|
||||
|
|
@ -1980,6 +1981,7 @@ LLVector2 LLSettingsSky::getCloudScrollRate() const
|
|||
void LLSettingsSky::setCloudScrollRate(const LLVector2 &val)
|
||||
{
|
||||
mScrollRate = val;
|
||||
setDirtyFlag(true);
|
||||
setLLSDDirty();
|
||||
}
|
||||
|
||||
|
|
@ -2138,6 +2140,7 @@ LLUUID LLSettingsSky::getMoonTextureId() const
|
|||
void LLSettingsSky::setMoonTextureId(LLUUID id)
|
||||
{
|
||||
mMoonTextureId = id;
|
||||
setDirtyFlag(true);
|
||||
setLLSDDirty();
|
||||
}
|
||||
|
||||
|
|
@ -2222,6 +2225,7 @@ LLUUID LLSettingsSky::getSunTextureId() const
|
|||
void LLSettingsSky::setSunTextureId(LLUUID id)
|
||||
{
|
||||
mSunTextureId = id;
|
||||
setDirtyFlag(true);
|
||||
setLLSDDirty();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -209,8 +209,14 @@ S32 LLPacketRing::receiveOrDropBufferedPacket(char *datap, bool drop)
|
|||
|
||||
if (!drop)
|
||||
{
|
||||
assert(packet_size > 0);
|
||||
memcpy(datap, packet->getData(), packet_size);
|
||||
if (packet_size > 0)
|
||||
{
|
||||
memcpy(datap, packet->getData(), packet_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -751,7 +751,14 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l
|
|||
|
||||
LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_glyph_type, bitmap_num);
|
||||
LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_glyph_type, bitmap_num);
|
||||
image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight());
|
||||
if (image_gl && image_raw)
|
||||
{
|
||||
image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight());
|
||||
}
|
||||
else
|
||||
{
|
||||
llassert(false); //images were just inserted by nextOpenPos, they shouldn't be missing
|
||||
}
|
||||
|
||||
return gi;
|
||||
}
|
||||
|
|
@ -944,7 +951,12 @@ bool LLFontFreetype::setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U1
|
|||
{
|
||||
LLImageRaw* image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, bitmap_num);
|
||||
llassert(!mIsFallback);
|
||||
llassert(image_raw && (image_raw->getComponents() == 4));
|
||||
if (!image_raw)
|
||||
{
|
||||
llassert(false);
|
||||
return false;
|
||||
}
|
||||
llassert(image_raw->getComponents() == 4);
|
||||
|
||||
// NOTE: inspired by LLImageRaw::setSubImage()
|
||||
U32* image_data = (U32*)image_raw->getData();
|
||||
|
|
@ -972,10 +984,17 @@ bool LLFontFreetype::setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U1
|
|||
void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride) const
|
||||
{
|
||||
LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Grayscale, bitmap_num);
|
||||
LLImageDataLock lock(image_raw);
|
||||
|
||||
llassert(!mIsFallback);
|
||||
llassert(image_raw && (image_raw->getComponents() == 2));
|
||||
if (!image_raw)
|
||||
{
|
||||
llassert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
LLImageDataLock lock(image_raw);
|
||||
|
||||
llassert(image_raw->getComponents() == 2);
|
||||
|
||||
U8 *target = image_raw->getData();
|
||||
llassert(target);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ set(llui_SOURCE_FILES
|
|||
llbadgeowner.cpp
|
||||
llbutton.cpp
|
||||
llchatentry.cpp
|
||||
llchatmentionhelper.cpp
|
||||
llcheckboxctrl.cpp
|
||||
llclipboard.cpp
|
||||
llcombobox.cpp
|
||||
|
|
@ -134,6 +135,7 @@ set(llui_HEADER_FILES
|
|||
llcallbackmap.h
|
||||
llchatentry.h
|
||||
llchat.h
|
||||
llchatmentionhelper.h
|
||||
llcheckboxctrl.h
|
||||
llclipboard.h
|
||||
llcombobox.h
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ LLChatEntry::LLChatEntry(const Params& p)
|
|||
mCurrentHistoryLine = mLineHistory.begin();
|
||||
|
||||
mAutoIndent = false;
|
||||
mShowChatMentionPicker = true;
|
||||
keepSelectionOnReturn(true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,151 @@
|
|||
/**
|
||||
* @file llchatmentionhelper.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2025&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2025, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llchatmentionhelper.h"
|
||||
#include "llfloater.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "lluictrl.h"
|
||||
|
||||
constexpr char CHAT_MENTION_HELPER_FLOATER[] = "chat_mention_picker";
|
||||
|
||||
bool LLChatMentionHelper::isActive(const LLUICtrl* ctrl) const
|
||||
{
|
||||
return mHostHandle.get() == ctrl;
|
||||
}
|
||||
|
||||
bool LLChatMentionHelper::isCursorInNameMention(const LLWString& wtext, S32 cursor_pos, S32* mention_start_pos) const
|
||||
{
|
||||
if (cursor_pos <= 0 || cursor_pos > static_cast<S32>(wtext.size()))
|
||||
return false;
|
||||
|
||||
// Find the beginning of the current word
|
||||
S32 start = cursor_pos - 1;
|
||||
while (start > 0 && wtext[start - 1] != U32(' ') && wtext[start - 1] != U32('\n'))
|
||||
{
|
||||
--start;
|
||||
}
|
||||
|
||||
if (wtext[start] != U32('@'))
|
||||
return false;
|
||||
|
||||
if (mention_start_pos)
|
||||
*mention_start_pos = start;
|
||||
|
||||
S32 word_length = cursor_pos - start;
|
||||
|
||||
if (word_length == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the name after '@'
|
||||
std::string name = wstring_to_utf8str(wtext.substr(start + 1, word_length - 1));
|
||||
LLStringUtil::toLower(name);
|
||||
for (const auto& av_name : mAvatarNames)
|
||||
{
|
||||
if (av_name == name || av_name.find(name) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLChatMentionHelper::showHelper(LLUICtrl* host_ctrl, S32 local_x, S32 local_y, const std::string& av_name, std::function<void(std::string)> cb)
|
||||
{
|
||||
if (mHelperHandle.isDead())
|
||||
{
|
||||
LLFloater* av_picker_floater = LLFloaterReg::getInstance(CHAT_MENTION_HELPER_FLOATER);
|
||||
mHelperHandle = av_picker_floater->getHandle();
|
||||
mHelperCommitConn = av_picker_floater->setCommitCallback([&](LLUICtrl* ctrl, const LLSD& param) { onCommitName(param.asString()); });
|
||||
}
|
||||
setHostCtrl(host_ctrl);
|
||||
mNameCommitCb = cb;
|
||||
|
||||
S32 floater_x, floater_y;
|
||||
if (!host_ctrl->localPointToOtherView(local_x, local_y, &floater_x, &floater_y, gFloaterView))
|
||||
{
|
||||
LL_WARNS() << "Cannot show helper for non-floater controls." << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
LLFloater* av_picker_floater = mHelperHandle.get();
|
||||
LLRect rect = av_picker_floater->getRect();
|
||||
rect.setLeftTopAndSize(floater_x, floater_y + rect.getHeight(), rect.getWidth(), rect.getHeight());
|
||||
av_picker_floater->setRect(rect);
|
||||
av_picker_floater->openFloater(LLSD().with("av_name", av_name));
|
||||
}
|
||||
|
||||
void LLChatMentionHelper::hideHelper(const LLUICtrl* ctrl)
|
||||
{
|
||||
if ((ctrl && !isActive(ctrl)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
setHostCtrl(nullptr);
|
||||
}
|
||||
|
||||
bool LLChatMentionHelper::handleKey(const LLUICtrl* ctrl, KEY key, MASK mask)
|
||||
{
|
||||
if (mHelperHandle.isDead() || !isActive(ctrl))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return mHelperHandle.get()->handleKey(key, mask, true);
|
||||
}
|
||||
|
||||
void LLChatMentionHelper::onCommitName(std::string name_url)
|
||||
{
|
||||
if (!mHostHandle.isDead() && mNameCommitCb)
|
||||
{
|
||||
mNameCommitCb(name_url);
|
||||
}
|
||||
}
|
||||
|
||||
void LLChatMentionHelper::setHostCtrl(LLUICtrl* host_ctrl)
|
||||
{
|
||||
const LLUICtrl* pCurHostCtrl = mHostHandle.get();
|
||||
if (pCurHostCtrl != host_ctrl)
|
||||
{
|
||||
mHostCtrlFocusLostConn.disconnect();
|
||||
mHostHandle.markDead();
|
||||
mNameCommitCb = {};
|
||||
|
||||
if (!mHelperHandle.isDead())
|
||||
{
|
||||
mHelperHandle.get()->closeFloater();
|
||||
}
|
||||
|
||||
if (host_ctrl)
|
||||
{
|
||||
mHostHandle = host_ctrl->getHandle();
|
||||
mHostCtrlFocusLostConn = host_ctrl->setFocusLostCallback(std::bind([&]() { hideHelper(getHostCtrl()); }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* @file llchatmentionhelper.h
|
||||
* @brief Header file for LLChatMentionHelper
|
||||
*
|
||||
* $LicenseInfo:firstyear=2025&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2025, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "llhandle.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
class LLFloater;
|
||||
class LLUICtrl;
|
||||
|
||||
class LLChatMentionHelper : public LLSingleton<LLChatMentionHelper>
|
||||
{
|
||||
LLSINGLETON(LLChatMentionHelper) {}
|
||||
~LLChatMentionHelper() override {}
|
||||
|
||||
public:
|
||||
|
||||
bool isActive(const LLUICtrl* ctrl) const;
|
||||
bool isCursorInNameMention(const LLWString& wtext, S32 cursor_pos, S32* mention_start_pos = nullptr) const;
|
||||
void showHelper(LLUICtrl* host_ctrl, S32 local_x, S32 local_y, const std::string& av_name, std::function<void(std::string)> commit_cb);
|
||||
void hideHelper(const LLUICtrl* ctrl = nullptr);
|
||||
|
||||
bool handleKey(const LLUICtrl* ctrl, KEY key, MASK mask);
|
||||
void onCommitName(std::string name_url);
|
||||
|
||||
void updateAvatarList(std::vector<std::string> av_names) { mAvatarNames = av_names; }
|
||||
|
||||
protected:
|
||||
void setHostCtrl(LLUICtrl* host_ctrl);
|
||||
LLUICtrl* getHostCtrl() const { return mHostHandle.get(); }
|
||||
|
||||
private:
|
||||
LLHandle<LLUICtrl> mHostHandle;
|
||||
LLHandle<LLFloater> mHelperHandle;
|
||||
boost::signals2::connection mHostCtrlFocusLostConn;
|
||||
boost::signals2::connection mHelperCommitConn;
|
||||
std::function<void(std::string)> mNameCommitCb;
|
||||
|
||||
std::vector<std::string> mAvatarNames;
|
||||
};
|
||||
|
|
@ -474,6 +474,7 @@ LLFlatListView::LLFlatListView(const LLFlatListView::Params& p)
|
|||
, mNoItemsCommentTextbox(NULL)
|
||||
, mIsConsecutiveSelection(false)
|
||||
, mKeepSelectionVisibleOnReshape(p.keep_selection_visible_on_reshape)
|
||||
, mFocusOnItemClicked(true)
|
||||
, mMagicalHackyHeightPadding(p.magical_hacky_height_padding)
|
||||
{
|
||||
mBorderThickness = getBorderWidth();
|
||||
|
|
@ -626,7 +627,10 @@ void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask)
|
|||
return;
|
||||
}
|
||||
|
||||
setFocus(true);
|
||||
if (mFocusOnItemClicked)
|
||||
{
|
||||
setFocus(true);
|
||||
}
|
||||
|
||||
bool select_item = !isSelected(item_pair);
|
||||
|
||||
|
|
|
|||
|
|
@ -307,6 +307,8 @@ public:
|
|||
|
||||
virtual S32 notify(const LLSD& info) override;
|
||||
|
||||
void setFocusOnItemClicked(bool b) { mFocusOnItemClicked = b; }
|
||||
|
||||
virtual ~LLFlatListView();
|
||||
|
||||
protected:
|
||||
|
|
@ -431,6 +433,8 @@ private:
|
|||
|
||||
bool mKeepSelectionVisibleOnReshape;
|
||||
|
||||
bool mFocusOnItemClicked;
|
||||
|
||||
/** All pairs of the list */
|
||||
pairs_list_t mItemPairs;
|
||||
|
||||
|
|
|
|||
|
|
@ -2607,9 +2607,24 @@ void LLLineEditor::resetPreedit()
|
|||
if (hasPreeditString())
|
||||
{
|
||||
const S32 preedit_pos = mPreeditPositions.front();
|
||||
mText.erase(preedit_pos, mPreeditPositions.back() - preedit_pos);
|
||||
mText.insert(preedit_pos, mPreeditOverwrittenWString);
|
||||
setCursor(preedit_pos);
|
||||
const S32 end = mPreeditPositions.back();
|
||||
const S32 len = end - preedit_pos;
|
||||
const S32 size = mText.length();
|
||||
if (preedit_pos < size
|
||||
&& end <= size
|
||||
&& preedit_pos >= 0
|
||||
&& len > 0)
|
||||
{
|
||||
mText.erase(preedit_pos, len);
|
||||
mText.insert(preedit_pos, mPreeditOverwrittenWString);
|
||||
setCursor(preedit_pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "Index out of bounds. Start: " << preedit_pos
|
||||
<< ", end:" << end
|
||||
<< ", full string length: " << size << LL_ENDL;
|
||||
}
|
||||
|
||||
mPreeditWString.clear();
|
||||
mPreeditOverwrittenWString.clear();
|
||||
|
|
|
|||
|
|
@ -38,11 +38,13 @@ LLStyle::Params::Params()
|
|||
color("color", LLColor4::black),
|
||||
readonly_color("readonly_color", LLColor4::black),
|
||||
selected_color("selected_color", LLColor4::black),
|
||||
highlight_bg_color("highlight_bg_color", LLColor4::green),
|
||||
alpha("alpha", 1.f),
|
||||
font("font", LLStyle::getDefaultFont()),
|
||||
image("image"),
|
||||
link_href("href"),
|
||||
is_link("is_link"),
|
||||
draw_highlight_bg("draw_highlight_bg", false),
|
||||
// <FS:Ansariel> Don't highlight URLs on hover if font style contains underline
|
||||
use_default_link_style("use_default_link_style", true),
|
||||
can_underline_on_hover("can_underline_on_hover", true)
|
||||
|
|
@ -55,12 +57,14 @@ LLStyle::LLStyle(const LLStyle::Params& p)
|
|||
mColor(p.color),
|
||||
mReadOnlyColor(p.readonly_color),
|
||||
mSelectedColor(p.selected_color),
|
||||
mHighlightBgColor(p.highlight_bg_color),
|
||||
mFont(p.font()),
|
||||
mLink(p.link_href),
|
||||
mIsLink(p.is_link.isProvided() ? p.is_link : !p.link_href().empty()),
|
||||
mDropShadow(p.drop_shadow),
|
||||
mImagep(p.image()),
|
||||
mAlpha(p.alpha)
|
||||
mAlpha(p.alpha),
|
||||
mDrawHighlightBg(p.draw_highlight_bg)
|
||||
{}
|
||||
|
||||
void LLStyle::setFont(const LLFontGL* font)
|
||||
|
|
|
|||
|
|
@ -43,12 +43,14 @@ public:
|
|||
Optional<LLFontGL::ShadowType> drop_shadow;
|
||||
Optional<LLUIColor> color,
|
||||
readonly_color,
|
||||
selected_color;
|
||||
selected_color,
|
||||
highlight_bg_color;
|
||||
Optional<F32> alpha;
|
||||
Optional<const LLFontGL*> font;
|
||||
Optional<LLUIImage*> image;
|
||||
Optional<std::string> link_href;
|
||||
Optional<bool> is_link;
|
||||
Optional<bool> draw_highlight_bg;
|
||||
// <FS:Ansariel> Don't highlight URLs on hover if font style contains underline
|
||||
Optional<bool> use_default_link_style;
|
||||
Optional<bool> can_underline_on_hover;
|
||||
|
|
@ -56,6 +58,14 @@ public:
|
|||
Params();
|
||||
};
|
||||
LLStyle(const Params& p = Params());
|
||||
|
||||
enum EUnderlineLink
|
||||
{
|
||||
UNDERLINE_ALWAYS = 0,
|
||||
UNDERLINE_ON_HOVER,
|
||||
UNDERLINE_NEVER
|
||||
};
|
||||
|
||||
public:
|
||||
const LLUIColor& getColor() const { return mColor; }
|
||||
void setColor(const LLUIColor &color) { mColor = color; }
|
||||
|
|
@ -88,6 +98,9 @@ public:
|
|||
|
||||
bool isImage() const { return mImagep.notNull(); }
|
||||
|
||||
bool getDrawHighlightBg() const { return mDrawHighlightBg; }
|
||||
const LLUIColor& getHighlightBgColor() const { return mHighlightBgColor; }
|
||||
|
||||
bool operator==(const LLStyle &rhs) const
|
||||
{
|
||||
return
|
||||
|
|
@ -95,11 +108,13 @@ public:
|
|||
&& mColor == rhs.mColor
|
||||
&& mReadOnlyColor == rhs.mReadOnlyColor
|
||||
&& mSelectedColor == rhs.mSelectedColor
|
||||
&& mHighlightBgColor == rhs.mHighlightBgColor
|
||||
&& mFont == rhs.mFont
|
||||
&& mLink == rhs.mLink
|
||||
&& mImagep == rhs.mImagep
|
||||
&& mDropShadow == rhs.mDropShadow
|
||||
&& mAlpha == rhs.mAlpha;
|
||||
&& mAlpha == rhs.mAlpha
|
||||
&& mDrawHighlightBg == rhs.mDrawHighlightBg;
|
||||
}
|
||||
|
||||
bool operator!=(const LLStyle& rhs) const { return !(*this == rhs); }
|
||||
|
|
@ -116,11 +131,13 @@ private:
|
|||
LLUIColor mColor;
|
||||
LLUIColor mReadOnlyColor;
|
||||
LLUIColor mSelectedColor;
|
||||
LLUIColor mHighlightBgColor;
|
||||
const LLFontGL* mFont;
|
||||
LLPointer<LLUIImage> mImagep;
|
||||
F32 mAlpha;
|
||||
bool mVisible;
|
||||
bool mIsLink;
|
||||
bool mDrawHighlightBg;
|
||||
};
|
||||
|
||||
typedef LLPointer<LLStyle> LLStyleSP;
|
||||
|
|
|
|||
|
|
@ -599,6 +599,62 @@ std::vector<LLRect> LLTextBase::getSelectionRects()
|
|||
return selection_rects;
|
||||
}
|
||||
|
||||
std::vector<std::pair<LLRect, LLUIColor>> LLTextBase::getHighlightedBgRects()
|
||||
{
|
||||
std::vector<std::pair<LLRect, LLUIColor>> highlight_rects;
|
||||
|
||||
LLRect content_display_rect = getVisibleDocumentRect();
|
||||
|
||||
// binary search for line that starts before top of visible buffer
|
||||
line_list_t::const_iterator line_iter =
|
||||
std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mTop, compare_bottom());
|
||||
line_list_t::const_iterator end_iter =
|
||||
std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mBottom, compare_top());
|
||||
|
||||
for (; line_iter != end_iter; ++line_iter)
|
||||
{
|
||||
segment_set_t::iterator segment_iter;
|
||||
S32 segment_offset;
|
||||
getSegmentAndOffset(line_iter->mDocIndexStart, &segment_iter, &segment_offset);
|
||||
|
||||
// Use F32 otherwise a string of multiple segments
|
||||
// will accumulate a large error
|
||||
F32 left_precise = (F32)line_iter->mRect.mLeft;
|
||||
F32 right_precise = (F32)line_iter->mRect.mLeft;
|
||||
|
||||
for (; segment_iter != mSegments.end(); ++segment_iter)
|
||||
{
|
||||
LLTextSegmentPtr segmentp = *segment_iter;
|
||||
|
||||
S32 segment_line_start = segmentp->getStart() + segment_offset;
|
||||
S32 segment_line_end = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd);
|
||||
|
||||
if (segment_line_start > segment_line_end)
|
||||
break;
|
||||
|
||||
F32 segment_width = 0;
|
||||
S32 segment_height = 0;
|
||||
|
||||
S32 num_chars = segment_line_end - segment_line_start;
|
||||
segmentp->getDimensionsF32(segment_offset, num_chars, segment_width, segment_height);
|
||||
right_precise += segment_width;
|
||||
|
||||
if (segmentp->getStyle()->getDrawHighlightBg())
|
||||
{
|
||||
LLRect selection_rect;
|
||||
selection_rect.mLeft = (S32)left_precise;
|
||||
selection_rect.mRight = (S32)right_precise;
|
||||
selection_rect.mBottom = line_iter->mRect.mBottom;
|
||||
selection_rect.mTop = line_iter->mRect.mTop;
|
||||
|
||||
highlight_rects.push_back(std::pair(selection_rect, segmentp->getStyle()->getHighlightBgColor()));
|
||||
}
|
||||
left_precise += segment_width;
|
||||
}
|
||||
}
|
||||
return highlight_rects;
|
||||
}
|
||||
|
||||
// Draws the black box behind the selected text
|
||||
void LLTextBase::drawSelectionBackground()
|
||||
{
|
||||
|
|
@ -668,6 +724,71 @@ void LLTextBase::drawSelectionBackground()
|
|||
}
|
||||
}
|
||||
|
||||
void LLTextBase::drawHighlightedBackground()
|
||||
{
|
||||
if (!mLineInfoList.empty())
|
||||
{
|
||||
std::vector<std::pair<LLRect, LLUIColor>> highlight_rects = getHighlightedBgRects();
|
||||
|
||||
if (highlight_rects.empty())
|
||||
return;
|
||||
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
|
||||
LLRect content_display_rect = getVisibleDocumentRect();
|
||||
|
||||
for (std::vector<std::pair<LLRect, LLUIColor>>::iterator rect_it = highlight_rects.begin();
|
||||
rect_it != highlight_rects.end(); ++rect_it)
|
||||
{
|
||||
LLRect selection_rect = rect_it->first;
|
||||
const LLColor4& color = rect_it->second;
|
||||
if (mScroller)
|
||||
{
|
||||
// If scroller is On content_display_rect has correct rect and safe to use as is
|
||||
// Note: we might need to account for border
|
||||
selection_rect.translate(mVisibleTextRect.mLeft - content_display_rect.mLeft, mVisibleTextRect.mBottom - content_display_rect.mBottom);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If scroller is Off content_display_rect will have rect from document, adjusted to text width, heigh and position
|
||||
// and we have to acount for offset depending on position
|
||||
S32 v_delta = 0;
|
||||
S32 h_delta = 0;
|
||||
switch (mVAlign)
|
||||
{
|
||||
case LLFontGL::TOP:
|
||||
v_delta = mVisibleTextRect.mTop - content_display_rect.mTop - mVPad;
|
||||
break;
|
||||
case LLFontGL::VCENTER:
|
||||
v_delta = (llmax(mVisibleTextRect.getHeight() - content_display_rect.mTop, -content_display_rect.mBottom) + (mVisibleTextRect.mBottom - content_display_rect.mBottom)) / 2;
|
||||
break;
|
||||
case LLFontGL::BOTTOM:
|
||||
v_delta = mVisibleTextRect.mBottom - content_display_rect.mBottom;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (mHAlign)
|
||||
{
|
||||
case LLFontGL::LEFT:
|
||||
h_delta = mVisibleTextRect.mLeft - content_display_rect.mLeft + mHPad;
|
||||
break;
|
||||
case LLFontGL::HCENTER:
|
||||
h_delta = (llmax(mVisibleTextRect.getWidth() - content_display_rect.mLeft, -content_display_rect.mRight) + (mVisibleTextRect.mRight - content_display_rect.mRight)) / 2;
|
||||
break;
|
||||
case LLFontGL::RIGHT:
|
||||
h_delta = mVisibleTextRect.mRight - content_display_rect.mRight;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
selection_rect.translate(h_delta, v_delta);
|
||||
}
|
||||
gl_rect_2d(selection_rect, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLTextBase::drawCursor()
|
||||
{
|
||||
F32 alpha = getDrawContext().mAlpha;
|
||||
|
|
@ -1559,6 +1680,7 @@ void LLTextBase::draw()
|
|||
drawChild(mDocumentView);
|
||||
}
|
||||
|
||||
drawHighlightedBackground();
|
||||
// [SL:KB] - Patch: Control-TextHighlight | Checked: 2013-12-30 (Catznip-3.6)
|
||||
if (mHighlightsDirty)
|
||||
refreshHighlights();
|
||||
|
|
@ -2438,20 +2560,20 @@ static LLUIImagePtr image_from_icon_name(const std::string& icon_name)
|
|||
}
|
||||
|
||||
|
||||
void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params)
|
||||
void LLTextBase::appendTextImpl(const std::string& new_text, const LLStyle::Params& input_params, bool force_slurl)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
|
||||
LLStyle::Params style_params(getStyleParams());
|
||||
style_params.overwriteFrom(input_params);
|
||||
|
||||
S32 part = (S32)LLTextParser::WHOLE;
|
||||
if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358).
|
||||
if ((mParseHTML || force_slurl) && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358).
|
||||
{
|
||||
S32 start=0,end=0;
|
||||
LLUrlMatch match;
|
||||
std::string text = new_text;
|
||||
while (LLUrlRegistry::instance().findUrl(text, match,
|
||||
boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3), isContentTrusted() || mAlwaysShowIcons))
|
||||
boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3), isContentTrusted() || mAlwaysShowIcons, force_slurl))
|
||||
{
|
||||
start = match.getStart();
|
||||
end = match.getEnd()+1;
|
||||
|
|
@ -2500,9 +2622,9 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
|
|||
|
||||
// output the styled Url
|
||||
// <FS:CR> FIRE-11437 - Don't supress font style for chat history name links
|
||||
//appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.underlineOnHoverOnly());
|
||||
//appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.getUnderline());
|
||||
appendAndHighlightTextImpl(match.getLabel(), part, link_params,
|
||||
input_params.can_underline_on_hover ? match.underlineOnHoverOnly() : false);
|
||||
input_params.can_underline_on_hover ? match.getUnderline() : LLStyle::UNDERLINE_NEVER);
|
||||
// </FS:CR>
|
||||
bool tooltip_required = !match.getTooltip().empty();
|
||||
|
||||
|
|
@ -2519,11 +2641,11 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
|
|||
// <FS:Ansariel> Custom URI query part color
|
||||
//link_params.color = LLColor4::grey;
|
||||
//link_params.readonly_color = LLColor4::grey;
|
||||
//appendAndHighlightTextImpl(label, part, link_params, match.underlineOnHoverOnly());
|
||||
//appendAndHighlightTextImpl(label, part, link_params, match.getUnderline());
|
||||
static LLUIColor query_part_color = LLUIColorTable::getInstance()->getColor("UriQueryPartColor", LLColor4::grey);
|
||||
link_params.color = query_part_color;
|
||||
link_params.readonly_color = query_part_color;
|
||||
appendAndHighlightTextImpl(label, part, link_params, input_params.can_underline_on_hover ? match.underlineOnHoverOnly() : false);
|
||||
appendAndHighlightTextImpl(label, part, link_params, input_params.can_underline_on_hover ? match.getUnderline() : LLStyle::UNDERLINE_NEVER);
|
||||
// </FS:Ansariel>
|
||||
|
||||
// set the tooltip for the query part of url
|
||||
|
|
@ -2715,7 +2837,7 @@ 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, S32 highlight_part, const LLStyle::Params& style_params, e_underline underline_link)
|
||||
{
|
||||
// Save old state
|
||||
S32 selection_start = mSelectionStart;
|
||||
|
|
@ -2745,7 +2867,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig
|
|||
S32 cur_length = getLength();
|
||||
LLStyleConstSP sp(new LLStyle(highlight_params));
|
||||
LLTextSegmentPtr segmentp;
|
||||
if (underline_on_hover_only || mSkipLinkUnderline)
|
||||
if ((underline_link == e_underline::UNDERLINE_ON_HOVER) || mSkipLinkUnderline)
|
||||
{
|
||||
// <FS:Ansariel> Only reset underline font style
|
||||
//highlight_params.font.style("NORMAL");
|
||||
|
|
@ -2778,7 +2900,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig
|
|||
S32 segment_start = old_length;
|
||||
S32 segment_end = old_length + static_cast<S32>(wide_text.size());
|
||||
LLStyleConstSP sp(new LLStyle(style_params));
|
||||
if (underline_on_hover_only || mSkipLinkUnderline)
|
||||
if ((underline_link == e_underline::UNDERLINE_ON_HOVER) || mSkipLinkUnderline)
|
||||
{
|
||||
LLStyle::Params normal_style_params(style_params);
|
||||
normal_style_params.font.style("NORMAL");
|
||||
|
|
@ -2812,7 +2934,7 @@ 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, S32 highlight_part, const LLStyle::Params& style_params, e_underline underline_link)
|
||||
{
|
||||
if (new_text.empty())
|
||||
{
|
||||
|
|
@ -2827,7 +2949,7 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlig
|
|||
if (pos != start)
|
||||
{
|
||||
std::string str = std::string(new_text,start,pos-start);
|
||||
appendAndHighlightTextImpl(str, highlight_part, style_params, underline_on_hover_only);
|
||||
appendAndHighlightTextImpl(str, highlight_part, style_params, underline_link);
|
||||
}
|
||||
appendLineBreakSegment(style_params);
|
||||
start = pos+1;
|
||||
|
|
@ -2835,7 +2957,7 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlig
|
|||
}
|
||||
|
||||
std::string str = std::string(new_text, start, new_text.length() - start);
|
||||
appendAndHighlightTextImpl(str, highlight_part, style_params, underline_on_hover_only);
|
||||
appendAndHighlightTextImpl(str, highlight_part, style_params, underline_link);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -3689,6 +3811,7 @@ LLNormalTextSegment::LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 e
|
|||
mLastGeneration(-1)
|
||||
{
|
||||
mFontHeight = mStyle->getFont()->getLineHeight();
|
||||
mCanEdit = !mStyle->getDrawHighlightBg();
|
||||
|
||||
LLUIImagePtr image = mStyle->getImage();
|
||||
if (image.notNull())
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "llstyle.h"
|
||||
#include "llkeywords.h"
|
||||
#include "llpanel.h"
|
||||
#include "llurlmatch.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -139,7 +140,7 @@ public:
|
|||
/*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);
|
||||
/*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect);
|
||||
/*virtual*/ bool canEdit() const { return true; }
|
||||
/*virtual*/ bool canEdit() const { return mCanEdit; }
|
||||
/*virtual*/ const LLUIColor& getColor() const { return mStyle->getColor(); }
|
||||
/*virtual*/ LLStyleConstSP getStyle() const { return mStyle; }
|
||||
/*virtual*/ void setStyle(LLStyleConstSP style) { mStyle = style; }
|
||||
|
|
@ -161,6 +162,8 @@ protected:
|
|||
virtual const LLWString& getWText() const;
|
||||
virtual const S32 getLength() const;
|
||||
|
||||
void setAllowEdit(bool can_edit) { mCanEdit = can_edit; }
|
||||
|
||||
protected:
|
||||
class LLTextBase& mEditor;
|
||||
LLStyleConstSP mStyle;
|
||||
|
|
@ -169,6 +172,8 @@ protected:
|
|||
std::string mTooltip;
|
||||
boost::signals2::connection mImageLoadedConnection;
|
||||
|
||||
bool mCanEdit { true };
|
||||
|
||||
// font rendering
|
||||
LLFontVertexBuffer mFontBufferPreSelection;
|
||||
LLFontVertexBuffer mFontBufferSelection;
|
||||
|
|
@ -647,6 +652,7 @@ protected:
|
|||
bool operator()(const LLTextSegmentPtr& a, const LLTextSegmentPtr& b) const;
|
||||
};
|
||||
typedef std::multiset<LLTextSegmentPtr, compare_segment_end> segment_set_t;
|
||||
typedef LLStyle::EUnderlineLink e_underline;
|
||||
|
||||
// member functions
|
||||
LLTextBase(const Params &p);
|
||||
|
|
@ -663,12 +669,13 @@ protected:
|
|||
// [/SL:KB]
|
||||
void drawCursor();
|
||||
void drawText();
|
||||
void drawHighlightedBackground();
|
||||
|
||||
// modify contents
|
||||
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, S32 highlight_part, const LLStyle::Params& stylep, e_underline underline_link = e_underline::UNDERLINE_ALWAYS);
|
||||
|
||||
|
||||
// manage segments
|
||||
|
|
@ -716,8 +723,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(), bool force_slurl = false);
|
||||
void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, e_underline underline_link = e_underline::UNDERLINE_ALWAYS);
|
||||
S32 normalizeUri(std::string& uri);
|
||||
|
||||
protected:
|
||||
// virtual
|
||||
|
|
@ -730,6 +738,7 @@ protected:
|
|||
}
|
||||
|
||||
std::vector<LLRect> getSelectionRects();
|
||||
std::vector<std::pair<LLRect, LLUIColor>> getHighlightedBgRects();
|
||||
|
||||
protected:
|
||||
// text segmentation and flow
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@
|
|||
#include "llurlregistry.h"
|
||||
#include "lltooltip.h"
|
||||
#include "llmenugl.h"
|
||||
#include "llchatmentionhelper.h"
|
||||
|
||||
#include <queue>
|
||||
#include "llcombobox.h"
|
||||
|
|
@ -271,6 +272,7 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
|
|||
mPrevalidator(p.prevalidator()),
|
||||
mShowContextMenu(p.show_context_menu),
|
||||
mShowEmojiHelper(p.show_emoji_helper),
|
||||
mShowChatMentionPicker(false),
|
||||
mEnableTooltipPaste(p.enable_tooltip_paste),
|
||||
mPassDelete(false),
|
||||
mKeepSelectionOnReturn(false),
|
||||
|
|
@ -780,6 +782,30 @@ void LLTextEditor::handleEmojiCommit(llwchar emoji)
|
|||
}
|
||||
}
|
||||
|
||||
void LLTextEditor::handleMentionCommit(std::string name_url)
|
||||
{
|
||||
S32 mention_start_pos;
|
||||
if (LLChatMentionHelper::instance().isCursorInNameMention(getWText(), mCursorPos, &mention_start_pos))
|
||||
{
|
||||
remove(mention_start_pos, mCursorPos - mention_start_pos, true);
|
||||
insert(mention_start_pos, utf8str_to_wstring(name_url), false, LLTextSegmentPtr());
|
||||
|
||||
std::string new_text(wstring_to_utf8str(getConvertedText()));
|
||||
clear();
|
||||
appendTextImpl(new_text, LLStyle::Params(), true);
|
||||
|
||||
segment_set_t::const_iterator it = getSegIterContaining(mention_start_pos);
|
||||
if (it != mSegments.end())
|
||||
{
|
||||
setCursorPos((*it)->getEnd() + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
setCursorPos(mention_start_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
bool handled = false;
|
||||
|
|
@ -1179,6 +1205,7 @@ void LLTextEditor::removeCharOrTab()
|
|||
}
|
||||
|
||||
tryToShowEmojiHelper();
|
||||
tryToShowMentionHelper();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1204,6 +1231,7 @@ void LLTextEditor::removeChar()
|
|||
setCursorPos(mCursorPos - 1);
|
||||
removeChar(mCursorPos);
|
||||
tryToShowEmojiHelper();
|
||||
tryToShowMentionHelper();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1294,6 +1322,7 @@ void LLTextEditor::addChar(llwchar wc)
|
|||
|
||||
setCursorPos(mCursorPos + addChar( mCursorPos, wc ));
|
||||
tryToShowEmojiHelper();
|
||||
tryToShowMentionHelper();
|
||||
|
||||
if (!mReadOnly && mAutoreplaceCallback != NULL)
|
||||
{
|
||||
|
|
@ -1352,6 +1381,31 @@ void LLTextEditor::tryToShowEmojiHelper()
|
|||
}
|
||||
}
|
||||
|
||||
void LLTextEditor::tryToShowMentionHelper()
|
||||
{
|
||||
if (mReadOnly || !mShowChatMentionPicker)
|
||||
return;
|
||||
|
||||
S32 mention_start_pos;
|
||||
LLWString text(getWText());
|
||||
if (LLChatMentionHelper::instance().isCursorInNameMention(text, mCursorPos, &mention_start_pos))
|
||||
{
|
||||
const LLRect cursor_rect(getLocalRectFromDocIndex(mention_start_pos));
|
||||
std::string name_part(wstring_to_utf8str(text.substr(mention_start_pos, mCursorPos - mention_start_pos)));
|
||||
name_part.erase(0, 1);
|
||||
auto cb = [this](std::string name_url)
|
||||
{
|
||||
handleMentionCommit(name_url);
|
||||
};
|
||||
LLChatMentionHelper::instance().showHelper(this, cursor_rect.mLeft, cursor_rect.mTop, name_part, cb);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLChatMentionHelper::instance().hideHelper();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLTextEditor::addLineBreakChar(bool group_together)
|
||||
{
|
||||
if( !getEnabled() )
|
||||
|
|
@ -2066,7 +2120,7 @@ bool LLTextEditor::handleKeyHere(KEY key, MASK mask )
|
|||
// not handled and let the parent take care of field movement.
|
||||
if (KEY_TAB == key && mTabsToNextField)
|
||||
{
|
||||
return false;
|
||||
return mShowChatMentionPicker && LLChatMentionHelper::instance().handleKey(this, key, mask);
|
||||
}
|
||||
|
||||
// <FS:Ansariel> FIRE-19933: Open context menu on context menu key press
|
||||
|
|
@ -2084,9 +2138,13 @@ bool LLTextEditor::handleKeyHere(KEY key, MASK mask )
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask))
|
||||
if (!mReadOnly)
|
||||
{
|
||||
return true;
|
||||
if ((mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) ||
|
||||
(mShowChatMentionPicker && LLChatMentionHelper::instance().handleKey(this, key, mask)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mEnableTooltipPaste &&
|
||||
|
|
@ -3302,3 +3360,21 @@ S32 LLTextEditor::spacesPerTab()
|
|||
{
|
||||
return SPACES_PER_TAB;
|
||||
}
|
||||
|
||||
LLWString LLTextEditor::getConvertedText() const
|
||||
{
|
||||
LLWString text = getWText();
|
||||
S32 diff = 0;
|
||||
for (auto segment : mSegments)
|
||||
{
|
||||
if (segment && segment->getStyle() && segment->getStyle()->getDrawHighlightBg())
|
||||
{
|
||||
S32 seg_length = segment->getEnd() - segment->getStart();
|
||||
std::string slurl = segment->getStyle()->getLinkHREF();
|
||||
|
||||
text.replace(segment->getStart() + diff, seg_length, utf8str_to_wstring(slurl));
|
||||
diff += (S32)slurl.size() - seg_length;
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,8 @@ public:
|
|||
void insertEmoji(llwchar emoji);
|
||||
void handleEmojiCommit(llwchar emoji);
|
||||
|
||||
void handleMentionCommit(std::string name_url);
|
||||
|
||||
// mousehandler overrides
|
||||
virtual bool handleMouseDown(S32 x, S32 y, MASK mask);
|
||||
virtual bool handleMouseUp(S32 x, S32 y, MASK mask);
|
||||
|
|
@ -227,6 +229,8 @@ public:
|
|||
|
||||
void setPassDelete(bool b) { mPassDelete = b; }
|
||||
|
||||
LLWString getConvertedText() const;
|
||||
|
||||
protected:
|
||||
// <FS:Ansariel> FIRE-19933: Open context menu on context menu key press
|
||||
//void showContextMenu(S32 x, S32 y);
|
||||
|
|
@ -274,6 +278,7 @@ protected:
|
|||
S32 remove(S32 pos, S32 length, bool group_with_next_op);
|
||||
|
||||
void tryToShowEmojiHelper();
|
||||
void tryToShowMentionHelper();
|
||||
void focusLostHelper();
|
||||
void updateAllowingLanguageInput();
|
||||
bool hasPreeditString() const;
|
||||
|
|
@ -311,6 +316,7 @@ protected:
|
|||
|
||||
bool mAutoIndent;
|
||||
bool mParseOnTheFly;
|
||||
bool mShowChatMentionPicker;
|
||||
|
||||
void updateLinkSegments();
|
||||
void keepSelectionOnReturn(bool keep) { mKeepSelectionOnReturn = keep; }
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
#include "llurlentry.h"
|
||||
#include "lluictrl.h"
|
||||
#include "lluri.h"
|
||||
#include "llurlmatch.h"
|
||||
#include "llurlregistry.h"
|
||||
#include "lluriparser.h"
|
||||
|
||||
|
|
@ -51,7 +50,7 @@
|
|||
// Utility functions
|
||||
std::string localize_slapp_label(const std::string& url, const std::string& full_name);
|
||||
|
||||
|
||||
LLUUID LLUrlEntryBase::sAgentID(LLUUID::null);
|
||||
LLUrlEntryBase::LLUrlEntryBase()
|
||||
{
|
||||
}
|
||||
|
|
@ -71,7 +70,7 @@ std::string LLUrlEntryBase::getIcon(const std::string &url)
|
|||
return mIcon;
|
||||
}
|
||||
|
||||
LLStyle::Params LLUrlEntryBase::getStyle() const
|
||||
LLStyle::Params LLUrlEntryBase::getStyle(const std::string &url) const
|
||||
{
|
||||
LLStyle::Params style_params;
|
||||
style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor");
|
||||
|
|
@ -735,10 +734,14 @@ std::string LLUrlEntryAgent::getTooltip(const std::string &string) const
|
|||
return LLTrans::getString("TooltipAgentUrl");
|
||||
}
|
||||
|
||||
bool LLUrlEntryAgent::underlineOnHoverOnly(const std::string &string) const
|
||||
LLStyle::EUnderlineLink LLUrlEntryAgent::getUnderline(const std::string& string) const
|
||||
{
|
||||
std::string url = getUrl(string);
|
||||
return LLStringUtil::endsWith(url, "/about") || LLStringUtil::endsWith(url, "/inspect");
|
||||
if (LLStringUtil::endsWith(url, "/about") || LLStringUtil::endsWith(url, "/inspect"))
|
||||
{
|
||||
return LLStyle::EUnderlineLink::UNDERLINE_ON_HOVER;
|
||||
}
|
||||
return LLStyle::EUnderlineLink::UNDERLINE_ALWAYS;
|
||||
}
|
||||
|
||||
std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
|
||||
|
|
@ -780,11 +783,12 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa
|
|||
}
|
||||
}
|
||||
|
||||
LLStyle::Params LLUrlEntryAgent::getStyle() const
|
||||
LLStyle::Params LLUrlEntryAgent::getStyle(const std::string &url) const
|
||||
{
|
||||
LLStyle::Params style_params = LLUrlEntryBase::getStyle();
|
||||
LLStyle::Params style_params = LLUrlEntryBase::getStyle(url);
|
||||
style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor");
|
||||
style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor");
|
||||
|
||||
return style_params;
|
||||
}
|
||||
|
||||
|
|
@ -819,6 +823,10 @@ std::string localize_slapp_label(const std::string& url, const std::string& full
|
|||
{
|
||||
return LLTrans::getString("SLappAgentRemoveFriend") + " " + full_name;
|
||||
}
|
||||
if (LLStringUtil::endsWith(url, "/mention"))
|
||||
{
|
||||
return "@" + full_name;
|
||||
}
|
||||
return full_name;
|
||||
}
|
||||
|
||||
|
|
@ -830,6 +838,34 @@ std::string LLUrlEntryAgent::getIcon(const std::string &url)
|
|||
return mIcon;
|
||||
}
|
||||
|
||||
///
|
||||
/// LLUrlEntryAgentMention Describes a chat mention Url, e.g.,
|
||||
/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/mention
|
||||
///
|
||||
LLUrlEntryAgentMention::LLUrlEntryAgentMention()
|
||||
{
|
||||
mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/mention", boost::regex::perl | boost::regex::icase);
|
||||
mMenuName = "menu_url_agent.xml";
|
||||
mIcon = std::string();
|
||||
}
|
||||
|
||||
LLStyle::EUnderlineLink LLUrlEntryAgentMention::getUnderline(const std::string& string) const
|
||||
{
|
||||
return LLStyle::EUnderlineLink::UNDERLINE_NEVER;
|
||||
}
|
||||
|
||||
LLStyle::Params LLUrlEntryAgentMention::getStyle(const std::string& url) const
|
||||
{
|
||||
LLStyle::Params style_params = LLUrlEntryAgent::getStyle(url);
|
||||
style_params.font.style = "NORMAL";
|
||||
style_params.draw_highlight_bg = true;
|
||||
|
||||
LLUUID agent_id(getIDStringFromUrl(url));
|
||||
style_params.highlight_bg_color = LLUIColorTable::instance().getColor((agent_id == sAgentID) ? "ChatSelfMentionHighlight" : "ChatMentionHighlight");
|
||||
|
||||
return style_params;
|
||||
}
|
||||
|
||||
//
|
||||
// LLUrlEntryAgentName describes a Second Life agent name Url, e.g.,
|
||||
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
|
||||
|
|
@ -891,7 +927,7 @@ std::string LLUrlEntryAgentName::getLabel(const std::string &url, const LLUrlLab
|
|||
}
|
||||
}
|
||||
|
||||
LLStyle::Params LLUrlEntryAgentName::getStyle() const
|
||||
LLStyle::Params LLUrlEntryAgentName::getStyle(const std::string &url) const
|
||||
{
|
||||
// don't override default colors
|
||||
return LLStyle::Params().is_link(false);
|
||||
|
|
@ -1074,9 +1110,9 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa
|
|||
}
|
||||
}
|
||||
|
||||
LLStyle::Params LLUrlEntryGroup::getStyle() const
|
||||
LLStyle::Params LLUrlEntryGroup::getStyle(const std::string &url) const
|
||||
{
|
||||
LLStyle::Params style_params = LLUrlEntryBase::getStyle();
|
||||
LLStyle::Params style_params = LLUrlEntryBase::getStyle(url);
|
||||
style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor");
|
||||
style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor");
|
||||
return style_params;
|
||||
|
|
@ -1155,7 +1191,6 @@ std::string LLUrlEntryChat::getLabel(const std::string &url, const LLUrlLabelCal
|
|||
}
|
||||
|
||||
// LLUrlEntryParcel statics.
|
||||
LLUUID LLUrlEntryParcel::sAgentID(LLUUID::null);
|
||||
LLUUID LLUrlEntryParcel::sSessionID(LLUUID::null);
|
||||
LLHost LLUrlEntryParcel::sRegionHost;
|
||||
bool LLUrlEntryParcel::sDisconnected(false);
|
||||
|
|
@ -1528,17 +1563,17 @@ std::string LLUrlEntrySLLabel::getTooltip(const std::string &string) const
|
|||
return LLUrlEntryBase::getTooltip(string);
|
||||
}
|
||||
|
||||
bool LLUrlEntrySLLabel::underlineOnHoverOnly(const std::string &string) const
|
||||
LLStyle::EUnderlineLink LLUrlEntrySLLabel::getUnderline(const std::string& string) const
|
||||
{
|
||||
std::string url = getUrl(string);
|
||||
LLUrlMatch match;
|
||||
LLUrlMatch match;
|
||||
if (LLUrlRegistry::instance().findUrl(url, match))
|
||||
{
|
||||
return match.underlineOnHoverOnly();
|
||||
return match.getUnderline();
|
||||
}
|
||||
|
||||
// unrecognized URL? should not happen
|
||||
return LLUrlEntryBase::underlineOnHoverOnly(string);
|
||||
return LLUrlEntryBase::getUnderline(string);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -1602,7 +1637,7 @@ std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelC
|
|||
return getUrl(url);
|
||||
}
|
||||
|
||||
LLStyle::Params LLUrlEntryNoLink::getStyle() const
|
||||
LLStyle::Params LLUrlEntryNoLink::getStyle(const std::string &url) const
|
||||
{
|
||||
// Don't render as URL (i.e. no context menu or hand cursor).
|
||||
return LLStyle::Params().is_link(false);
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ public:
|
|||
virtual std::string getIcon(const std::string &url);
|
||||
|
||||
/// Return the style to render the displayed text
|
||||
virtual LLStyle::Params getStyle() const;
|
||||
virtual LLStyle::Params getStyle(const std::string &url) const;
|
||||
|
||||
/// Given a matched Url, return a tooltip string for the hyperlink
|
||||
virtual std::string getTooltip(const std::string &string) const { return mTooltip; }
|
||||
|
|
@ -96,11 +96,12 @@ public:
|
|||
/// Return the name of a SL location described by this Url, if any
|
||||
virtual std::string getLocation(const std::string &url) const { return ""; }
|
||||
|
||||
/// Should this link text be underlined only when mouse is hovered over it?
|
||||
virtual bool underlineOnHoverOnly(const std::string &string) const { return false; }
|
||||
virtual LLStyle::EUnderlineLink getUnderline(const std::string& string) const { return LLStyle::EUnderlineLink::UNDERLINE_ALWAYS; }
|
||||
|
||||
virtual bool isTrusted() const { return false; }
|
||||
|
||||
virtual bool getSkipProfileIcon(const std::string& string) const { return false; }
|
||||
|
||||
virtual LLUUID getID(const std::string &string) const { return LLUUID::null; }
|
||||
|
||||
bool isLinkDisabled() const;
|
||||
|
|
@ -109,6 +110,8 @@ public:
|
|||
|
||||
virtual bool isSLURLvalid(const std::string &url) const { return true; };
|
||||
|
||||
static void setAgentID(const LLUUID& id) { sAgentID = id; }
|
||||
|
||||
protected:
|
||||
std::string getIDStringFromUrl(const std::string &url) const;
|
||||
std::string escapeUrl(const std::string &url) const;
|
||||
|
|
@ -130,6 +133,8 @@ protected:
|
|||
std::string mMenuName;
|
||||
std::string mTooltip;
|
||||
std::multimap<std::string, LLUrlEntryObserver> mObservers;
|
||||
|
||||
static LLUUID sAgentID;
|
||||
};
|
||||
|
||||
///
|
||||
|
|
@ -239,9 +244,11 @@ public:
|
|||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getIcon(const std::string &url);
|
||||
/*virtual*/ std::string getTooltip(const std::string &string) const;
|
||||
/*virtual*/ LLStyle::Params getStyle() const;
|
||||
/*virtual*/ LLStyle::Params getStyle(const std::string &url) const;
|
||||
/*virtual*/ LLUUID getID(const std::string &string) const;
|
||||
/*virtual*/ bool underlineOnHoverOnly(const std::string &string) const;
|
||||
|
||||
LLStyle::EUnderlineLink getUnderline(const std::string& string) const;
|
||||
|
||||
protected:
|
||||
/*virtual*/ void callObservers(const std::string &id, const std::string &label, const std::string& icon);
|
||||
private:
|
||||
|
|
@ -251,6 +258,19 @@ private:
|
|||
avatar_name_cache_connection_map_t mAvatarNameCacheConnections;
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryAgentMention Describes a chat mention Url, e.g.,
|
||||
/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/mention
|
||||
class LLUrlEntryAgentMention : public LLUrlEntryAgent
|
||||
{
|
||||
public:
|
||||
LLUrlEntryAgentMention();
|
||||
|
||||
LLStyle::Params getStyle(const std::string& url) const;
|
||||
LLStyle::EUnderlineLink getUnderline(const std::string& string) const;
|
||||
bool getSkipProfileIcon(const std::string& string) const { return true; };
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryAgentName Describes a Second Life agent name Url, e.g.,
|
||||
/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
|
||||
|
|
@ -272,7 +292,7 @@ public:
|
|||
mAvatarNameCacheConnections.clear();
|
||||
}
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ LLStyle::Params getStyle() const;
|
||||
/*virtual*/ LLStyle::Params getStyle(const std::string &url) const;
|
||||
protected:
|
||||
// override this to pull out relevant name fields
|
||||
virtual std::string getName(const LLAvatarName& avatar_name) = 0;
|
||||
|
|
@ -383,7 +403,7 @@ class LLUrlEntryGroup : public LLUrlEntryBase
|
|||
public:
|
||||
LLUrlEntryGroup();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ LLStyle::Params getStyle() const;
|
||||
/*virtual*/ LLStyle::Params getStyle(const std::string &url) const;
|
||||
/*virtual*/ LLUUID getID(const std::string &string) const;
|
||||
private:
|
||||
void onGroupNameReceived(const LLUUID& id, const std::string& name, bool is_group);
|
||||
|
|
@ -455,17 +475,15 @@ public:
|
|||
// Processes parcel label and triggers notifying observers.
|
||||
static void processParcelInfo(const LLParcelData& parcel_data);
|
||||
|
||||
// Next 4 setters are used to update agent and viewer connection information
|
||||
// Next setters are used to update agent and viewer connection information
|
||||
// upon events like user login, viewer disconnect and user changing region host.
|
||||
// These setters are made public to be accessible from newview and should not be
|
||||
// used in other cases.
|
||||
static void setAgentID(const LLUUID& id) { sAgentID = id; }
|
||||
static void setSessionID(const LLUUID& id) { sSessionID = id; }
|
||||
static void setRegionHost(const LLHost& host) { sRegionHost = host; }
|
||||
static void setDisconnected(bool disconnected) { sDisconnected = disconnected; }
|
||||
|
||||
private:
|
||||
static LLUUID sAgentID;
|
||||
static LLUUID sSessionID;
|
||||
static LLHost sRegionHost;
|
||||
static bool sDisconnected;
|
||||
|
|
@ -557,7 +575,7 @@ public:
|
|||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getUrl(const std::string &string) const;
|
||||
/*virtual*/ std::string getTooltip(const std::string &string) const;
|
||||
/*virtual*/ bool underlineOnHoverOnly(const std::string &string) const;
|
||||
LLStyle::EUnderlineLink getUnderline(const std::string& string) const;
|
||||
};
|
||||
|
||||
///
|
||||
|
|
@ -581,7 +599,7 @@ public:
|
|||
LLUrlEntryNoLink();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getUrl(const std::string &string) const;
|
||||
/*virtual*/ LLStyle::Params getStyle() const;
|
||||
/*virtual*/ LLStyle::Params getStyle(const std::string &url) const;
|
||||
};
|
||||
|
||||
///
|
||||
|
|
|
|||
|
|
@ -37,8 +37,9 @@ LLUrlMatch::LLUrlMatch() :
|
|||
mIcon(""),
|
||||
mMenuName(""),
|
||||
mLocation(""),
|
||||
mUnderlineOnHoverOnly(false),
|
||||
mTrusted(false)
|
||||
mUnderline(e_underline::UNDERLINE_ALWAYS),
|
||||
mTrusted(false),
|
||||
mSkipProfileIcon(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +49,7 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url, const std
|
|||
const std::string &menu, const std::string &location,
|
||||
// <FS:Ansariel> Store matched text
|
||||
const std::string& matched_text,
|
||||
const LLUUID& id, bool underline_on_hover_only, bool trusted)
|
||||
const LLUUID& id, e_underline underline, bool trusted, bool skip_icon)
|
||||
{
|
||||
mStart = start;
|
||||
mEnd = end;
|
||||
|
|
@ -62,8 +63,9 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url, const std
|
|||
mMenuName = menu;
|
||||
mLocation = location;
|
||||
mID = id;
|
||||
mUnderlineOnHoverOnly = underline_on_hover_only;
|
||||
mUnderline = underline;
|
||||
mTrusted = trusted;
|
||||
mSkipProfileIcon = skip_icon;
|
||||
// <FS:Ansariel> Store matched text
|
||||
mMatchedText = matched_text;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,12 +82,13 @@ public:
|
|||
// <FS:Ansariel> Store matched text
|
||||
std::string getMatchedText() const { return mMatchedText; }
|
||||
|
||||
/// Should this link text be underlined only when mouse is hovered over it?
|
||||
bool underlineOnHoverOnly() const { return mUnderlineOnHoverOnly; }
|
||||
|
||||
typedef LLStyle::EUnderlineLink e_underline;
|
||||
e_underline getUnderline() const { return mUnderline; }
|
||||
/// Return true if Url is trusted.
|
||||
bool isTrusted() const { return mTrusted; }
|
||||
|
||||
bool getSkipProfileIcon() const { return mSkipProfileIcon; }
|
||||
|
||||
/// Change the contents of this match object (used by LLUrlRegistry)
|
||||
void setValues(U32 start, U32 end, const std::string &url, const std::string &label,
|
||||
const std::string& query, const std::string &tooltip, const std::string &icon,
|
||||
|
|
@ -96,7 +97,7 @@ public:
|
|||
//const std::string &location, const LLUUID& id,
|
||||
const std::string &location, const std::string& matched_text, const LLUUID& id,
|
||||
// </FS:Ansariel>
|
||||
bool underline_on_hover_only = false, bool trusted = false);
|
||||
e_underline underline = e_underline::UNDERLINE_ALWAYS, bool trusted = false, bool skip_icon = false);
|
||||
|
||||
const LLUUID& getID() const { return mID; }
|
||||
private:
|
||||
|
|
@ -113,8 +114,9 @@ private:
|
|||
std::string mMatchedText;
|
||||
LLUUID mID;
|
||||
LLStyle::Params mStyle;
|
||||
bool mUnderlineOnHoverOnly;
|
||||
e_underline mUnderline;
|
||||
bool mTrusted;
|
||||
bool mSkipProfileIcon;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ LLUrlRegistry::LLUrlRegistry()
|
|||
{
|
||||
// mUrlEntry.reserve(20);
|
||||
// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
|
||||
mUrlEntry.reserve(30);
|
||||
mUrlEntry.reserve(31);
|
||||
// [/RLVa:KB]
|
||||
|
||||
// Urls are matched in the order that they were registered
|
||||
|
|
@ -74,6 +74,8 @@ LLUrlRegistry::LLUrlRegistry()
|
|||
registerUrl(new FSUrlEntryAgentSelf());// <FS:Ansariel> FIRE-30611: "You" in transcript is underlined
|
||||
// LLUrlEntryAgent*Name must appear before LLUrlEntryAgent since
|
||||
// LLUrlEntryAgent is a less specific (catchall for agent urls)
|
||||
mUrlEntryAgentMention = new LLUrlEntryAgentMention();
|
||||
registerUrl(mUrlEntryAgentMention);
|
||||
registerUrl(new LLUrlEntryAgent());
|
||||
registerUrl(new LLUrlEntryChat());
|
||||
registerUrl(new LLUrlEntryGroup());
|
||||
|
|
@ -219,7 +221,7 @@ static bool stringHasJira(const std::string &text)
|
|||
text.find("WEB") != std::string::npos);
|
||||
}
|
||||
|
||||
bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb, bool is_content_trusted)
|
||||
bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb, bool is_content_trusted, bool skip_non_mentions)
|
||||
{
|
||||
// avoid costly regexes if there is clearly no URL in the text
|
||||
if (! (stringHasUrl(text) || stringHasJira(text)))
|
||||
|
|
@ -240,6 +242,11 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
|
|||
continue;
|
||||
}
|
||||
|
||||
if (skip_non_mentions && (mUrlEntryAgentMention != *it))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LLUrlEntryBase *url_entry = *it;
|
||||
|
||||
U32 start = 0, end = 0;
|
||||
|
|
@ -314,14 +321,15 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
|
|||
match_entry->getQuery(url),
|
||||
match_entry->getTooltip(url),
|
||||
match_entry->getIcon(url),
|
||||
match_entry->getStyle(),
|
||||
match_entry->getStyle(url),
|
||||
match_entry->getMenuName(),
|
||||
match_entry->getLocation(url),
|
||||
// <FS:Ansariel> Store matched text
|
||||
text.substr(match_start, match_end - match_start + 1),
|
||||
match_entry->getID(url),
|
||||
match_entry->underlineOnHoverOnly(url),
|
||||
match_entry->isTrusted());
|
||||
match_entry->getUnderline(url),
|
||||
match_entry->isTrusted(),
|
||||
match_entry->getSkipProfileIcon(url));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -364,7 +372,9 @@ bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUr
|
|||
// <FS:Ansariel> Store matched text
|
||||
match.getMatchedText(),
|
||||
match.getID(),
|
||||
match.underlineOnHoverOnly());
|
||||
match.getUnderline(),
|
||||
false,
|
||||
match.getSkipProfileIcon());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ public:
|
|||
/// your callback is invoked if the matched Url's label changes in the future
|
||||
bool findUrl(const std::string &text, LLUrlMatch &match,
|
||||
const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback,
|
||||
bool is_content_trusted = false);
|
||||
bool is_content_trusted = false, bool skip_non_mentions = false);
|
||||
|
||||
/// a slightly less efficient version of findUrl for wide strings
|
||||
bool findUrl(const LLWString &text, LLUrlMatch &match,
|
||||
|
|
@ -101,6 +101,7 @@ private:
|
|||
LLUrlEntryBase* mUrlEntrySLLabel;
|
||||
LLUrlEntryBase* mUrlEntryNoLink;
|
||||
LLUrlEntryBase* mUrlEntryKeybinding;
|
||||
LLUrlEntryBase* mUrlEntryAgentMention;
|
||||
// <FS:Ansariel> Normalize only trusted URL
|
||||
LLUrlEntryBase* mUrlEntryTrustedUrl;
|
||||
// <FS:Ansariel> Wear folder SLUrl
|
||||
|
|
|
|||
|
|
@ -319,6 +319,7 @@ set(viewer_SOURCE_FILES
|
|||
llfloatercamera.cpp
|
||||
llfloatercamerapresets.cpp
|
||||
llfloaterchangeitemthumbnail.cpp
|
||||
llfloaterchatmentionpicker.cpp
|
||||
llfloaterchatvoicevolume.cpp
|
||||
llfloaterclassified.cpp
|
||||
llfloatercolorpicker.cpp
|
||||
|
|
@ -1137,6 +1138,7 @@ set(viewer_HEADER_FILES
|
|||
llfloaterbuyland.h
|
||||
llfloatercamerapresets.h
|
||||
llfloaterchangeitemthumbnail.h
|
||||
llfloaterchatmentionpicker.h
|
||||
llfloatercamera.h
|
||||
llfloaterchatvoicevolume.h
|
||||
llfloaterclassified.h
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
7.1.13
|
||||
7.1.14
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@
|
|||
#include "llconsole.h"
|
||||
#include "llfloaterabout.h" // for sysinfo button -Zi
|
||||
#include "llfloateravatarpicker.h"
|
||||
#include "llfloaterchatmentionpicker.h"
|
||||
#include "llfloateremojipicker.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "llfloatersearchreplace.h"
|
||||
|
|
@ -205,6 +206,8 @@ void FSFloaterIM::onFocusLost()
|
|||
LLIMModel::getInstance()->resetActiveSessionID();
|
||||
|
||||
LLChicletBar::getInstance()->getChicletPanel()->setChicletToggleState(mSessionID, false);
|
||||
|
||||
LLTransientDockableFloater::onFocusLost();
|
||||
}
|
||||
|
||||
void FSFloaterIM::onFocusReceived()
|
||||
|
|
@ -217,6 +220,10 @@ void FSFloaterIM::onFocusReceived()
|
|||
{
|
||||
LLIMModel::instance().sendNoUnreadMessages(mSessionID);
|
||||
}
|
||||
|
||||
LLFloaterChatMentionPicker::updateSessionID(mSessionID);
|
||||
|
||||
LLTransientDockableFloater::onFocusReceived();
|
||||
}
|
||||
|
||||
// virtual
|
||||
|
|
@ -369,7 +376,7 @@ void FSFloaterIM::sendMsgFromInputEditor(EChatType type)
|
|||
|
||||
if (mInputEditor)
|
||||
{
|
||||
LLWString text = mInputEditor->getWText();
|
||||
LLWString text = mInputEditor->getConvertedText();
|
||||
LLWStringUtil::trim(text);
|
||||
LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines.
|
||||
if (!text.empty())
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
#include "llcommandhandler.h"
|
||||
#include "llconsole.h"
|
||||
#include "lldraghandle.h"
|
||||
#include "llfloaterchatmentionpicker.h"
|
||||
#include "llfloateremojipicker.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "llfloatersearchreplace.h"
|
||||
|
|
@ -796,7 +797,7 @@ void FSFloaterNearbyChat::sendChat( EChatType type )
|
|||
{
|
||||
if (mInputEditor)
|
||||
{
|
||||
LLWString text = mInputEditor->getWText();
|
||||
LLWString text = mInputEditor->getConvertedText();
|
||||
LLWStringUtil::trim(text);
|
||||
LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines.
|
||||
if (!text.empty())
|
||||
|
|
@ -1036,3 +1037,11 @@ void FSFloaterNearbyChat::onEmojiPickerToggleBtnClicked()
|
|||
mInputEditor->setFocus(true);
|
||||
mInputEditor->showEmojiHelper();
|
||||
}
|
||||
|
||||
|
||||
void FSFloaterNearbyChat::onFocusReceived()
|
||||
{
|
||||
LLFloaterChatMentionPicker::updateSessionID(LLUUID::null);
|
||||
|
||||
LLFloater::onFocusReceived();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,6 +127,8 @@ private:
|
|||
void initEmojiRecentPanel();
|
||||
void onRecentEmojiPicked(const LLSD& value);
|
||||
|
||||
void onFocusReceived();
|
||||
|
||||
FSChatHistory* mChatHistory;
|
||||
FSChatHistory* mChatHistoryMuted;
|
||||
LLChatEntry* mInputEditor;
|
||||
|
|
|
|||
|
|
@ -544,7 +544,7 @@ static void deferred_ui_audio_callback(const LLUUID& uuid)
|
|||
|
||||
bool create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* base)
|
||||
{
|
||||
if(!match || !base || base->getPlainText())
|
||||
if (!match || match->getSkipProfileIcon() || !base || base->getPlainText())
|
||||
return false;
|
||||
|
||||
LLUUID match_id = match->getID();
|
||||
|
|
|
|||
|
|
@ -186,6 +186,7 @@ LLAvatarList::LLAvatarList(const Params& p)
|
|||
, mShowSpeakingIndicator(p.show_speaking_indicator)
|
||||
, mShowPermissions(p.show_permissions_granted)
|
||||
, mShowCompleteName(false)
|
||||
, mForceCompleteName(false)
|
||||
// [RLVa:KB] - Checked: RLVa-1.2.0
|
||||
, mRlvCheckShowNames(false)
|
||||
// [/RLVa:KB]
|
||||
|
|
@ -254,7 +255,7 @@ void LLAvatarList::setShowIcons(std::string param_name)
|
|||
|
||||
std::string LLAvatarList::getAvatarName(LLAvatarName av_name)
|
||||
{
|
||||
return mShowCompleteName? av_name.getCompleteName(false) : av_name.getDisplayName();
|
||||
return mShowCompleteName? av_name.getCompleteName(false, mForceCompleteName) : av_name.getDisplayName();
|
||||
}
|
||||
|
||||
// <FS:Ansariel> Update voice volume slider on RLVa shownames restriction update
|
||||
|
|
@ -389,7 +390,7 @@ void LLAvatarList::refresh()
|
|||
|
||||
// <FS:Ansariel> FIRE-12750: Name filter not working correctly
|
||||
//if (!have_filter || findInsensitive(getAvatarName(av_name), mNameFilter))
|
||||
if (!have_filter || findInsensitive(getNameForDisplay(buddy_id, av_name, mShowDisplayName, mShowUsername, mRlvCheckShowNames), mNameFilter))
|
||||
if (!have_filter || findInsensitive(getNameForDisplay(buddy_id, av_name, mShowDisplayName, mShowUsername, mForceCompleteName, mRlvCheckShowNames), mNameFilter))
|
||||
// </FS:Ansariel>
|
||||
{
|
||||
if (nadded >= ADD_LIMIT)
|
||||
|
|
@ -438,7 +439,7 @@ void LLAvatarList::refresh()
|
|||
have_names &= LLAvatarNameCache::get(buddy_id, &av_name);
|
||||
// <FS:Ansariel> FIRE-12750: Name filter not working correctly
|
||||
//if (!findInsensitive(getAvatarName(av_name), mNameFilter))
|
||||
if (!findInsensitive(getNameForDisplay(buddy_id, av_name, mShowDisplayName, mShowUsername, mRlvCheckShowNames), mNameFilter))
|
||||
if (!findInsensitive(getNameForDisplay(buddy_id, av_name, mShowDisplayName, mShowUsername, mForceCompleteName, mRlvCheckShowNames), mNameFilter))
|
||||
// </FS:Ansariel>
|
||||
{
|
||||
removeItemByUUID(buddy_id);
|
||||
|
|
@ -493,7 +494,7 @@ void LLAvatarList::updateAvatarNames()
|
|||
for( std::vector<LLPanel*>::const_iterator it = items.begin(); it != items.end(); it++)
|
||||
{
|
||||
LLAvatarListItem* item = static_cast<LLAvatarListItem*>(*it);
|
||||
item->setShowCompleteName(mShowCompleteName);
|
||||
item->setShowCompleteName(mShowCompleteName, mForceCompleteName);
|
||||
item->updateAvatarName();
|
||||
}
|
||||
mNeedUpdateNames = false;
|
||||
|
|
@ -515,7 +516,7 @@ bool LLAvatarList::filterHasMatches()
|
|||
|
||||
// <FS:Ansariel> FIRE-12750: Name filter not working correctly
|
||||
//if (have_name && !findInsensitive(getAvatarName(av_name), mNameFilter))
|
||||
if (have_name && !findInsensitive(getNameForDisplay(buddy_id, av_name, mShowDisplayName, mShowUsername, mRlvCheckShowNames), mNameFilter))
|
||||
if (have_name && !findInsensitive(getNameForDisplay(buddy_id, av_name, mShowDisplayName, mShowUsername, mForceCompleteName, mRlvCheckShowNames), mNameFilter))
|
||||
// </FS:Ansariel>
|
||||
{
|
||||
continue;
|
||||
|
|
@ -536,6 +537,11 @@ boost::signals2::connection LLAvatarList::setItemDoubleClickCallback(const mouse
|
|||
return mItemDoubleClickSignal.connect(cb);
|
||||
}
|
||||
|
||||
boost::signals2::connection LLAvatarList::setItemClickedCallback(const mouse_signal_t::slot_type& cb)
|
||||
{
|
||||
return mItemClickedSignal.connect(cb);
|
||||
}
|
||||
|
||||
//virtual
|
||||
S32 LLAvatarList::notifyParent(const LLSD& info)
|
||||
{
|
||||
|
|
@ -570,7 +576,7 @@ S32 LLAvatarList::notifyParent(const LLSD& info)
|
|||
void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, bool is_online, EAddPosition pos)
|
||||
{
|
||||
LLAvatarListItem* item = new LLAvatarListItem();
|
||||
item->setShowCompleteName(mShowCompleteName);
|
||||
item->setShowCompleteName(mShowCompleteName, mForceCompleteName);
|
||||
// [RLVa:KB] - Checked: RLVa-1.2.0
|
||||
item->setRlvCheckShowNames(mRlvCheckShowNames);
|
||||
// [/RLVa:KB]
|
||||
|
|
@ -590,6 +596,7 @@ void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, bool is
|
|||
item->showDisplayName(mShowDisplayName);
|
||||
|
||||
item->setDoubleClickCallback(boost::bind(&LLAvatarList::onItemDoubleClicked, this, _1, _2, _3, _4));
|
||||
item->setMouseDownCallback(boost::bind(&LLAvatarList::onItemClicked, this, _1, _2, _3, _4));
|
||||
|
||||
addItem(item, id, pos);
|
||||
}
|
||||
|
|
@ -715,9 +722,14 @@ void LLAvatarList::onItemDoubleClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask)
|
|||
// [/RLVa:KB]
|
||||
}
|
||||
|
||||
void LLAvatarList::onItemClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask)
|
||||
{
|
||||
mItemClickedSignal(ctrl, x, y, mask);
|
||||
}
|
||||
|
||||
// <FS:Ansariel> FIRE-12750: Name filter not working correctly
|
||||
// static
|
||||
std::string LLAvatarList::getNameForDisplay(const LLUUID& avatar_id, const LLAvatarName& av_name, bool show_displayname, bool show_username, bool rlv_check_shownames)
|
||||
std::string LLAvatarList::getNameForDisplay(const LLUUID& avatar_id, const LLAvatarName& av_name, bool show_displayname, bool show_username, bool force_use_complete_name, bool rlv_check_shownames)
|
||||
{
|
||||
bool fRlvCanShowName = (!rlv_check_shownames) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar_id));
|
||||
if (show_displayname && !show_username)
|
||||
|
|
@ -730,7 +742,7 @@ std::string LLAvatarList::getNameForDisplay(const LLUUID& avatar_id, const LLAva
|
|||
}
|
||||
else
|
||||
{
|
||||
return ( (fRlvCanShowName) ? av_name.getCompleteName() : RlvStrings::getAnonym(av_name) );
|
||||
return ( (fRlvCanShowName) ? av_name.getCompleteName(false, force_use_complete_name) : RlvStrings::getAnonym(av_name) );
|
||||
}
|
||||
}
|
||||
// </FS:Ansariel>
|
||||
|
|
|
|||
|
|
@ -114,17 +114,19 @@ public:
|
|||
// [/FS:CR]
|
||||
|
||||
// <FS:Ansariel> FIRE-12750: Name filter not working correctly
|
||||
static std::string getNameForDisplay(const LLUUID& avatar_id, const LLAvatarName& av_name, bool show_displayname, bool show_username, bool rlv_check_shownames);
|
||||
static std::string getNameForDisplay(const LLUUID& avatar_id, const LLAvatarName& av_name, bool show_displayname, bool show_username, bool force_use_complete_name, bool rlv_check_shownames);
|
||||
|
||||
boost::signals2::connection setRefreshCompleteCallback(const commit_signal_t::slot_type& cb);
|
||||
|
||||
boost::signals2::connection setItemDoubleClickCallback(const mouse_signal_t::slot_type& cb);
|
||||
|
||||
boost::signals2::connection setItemClickedCallback(const mouse_signal_t::slot_type& cb);
|
||||
|
||||
virtual S32 notifyParent(const LLSD& info);
|
||||
|
||||
void handleDisplayNamesOptionChanged();
|
||||
|
||||
void setShowCompleteName(bool show) { mShowCompleteName = show;};
|
||||
void setShowCompleteName(bool show, bool force = false) { mShowCompleteName = show; mForceCompleteName = force; };
|
||||
|
||||
protected:
|
||||
void refresh();
|
||||
|
|
@ -137,7 +139,8 @@ protected:
|
|||
void updateLastInteractionTimes();
|
||||
void rebuildNames();
|
||||
void onItemDoubleClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask);
|
||||
// void updateAvatarNames();
|
||||
void onItemClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask);
|
||||
// void updateAvatarNames();
|
||||
|
||||
private:
|
||||
|
||||
|
|
@ -152,6 +155,7 @@ private:
|
|||
bool mShowSpeakingIndicator;
|
||||
bool mShowPermissions;
|
||||
bool mShowCompleteName;
|
||||
bool mForceCompleteName;
|
||||
// [RLVa:KB] - RLVa-1.2.0
|
||||
bool mRlvCheckShowNames;
|
||||
// [/RLVa:KB]
|
||||
|
|
@ -168,6 +172,7 @@ private:
|
|||
|
||||
commit_signal_t mRefreshCompleteSignal;
|
||||
mouse_signal_t mItemDoubleClickSignal;
|
||||
mouse_signal_t mItemClickedSignal;
|
||||
|
||||
// <FS:Ansariel> Update voice volume slider on RLVa shownames restriction update
|
||||
boost::signals2::connection mRlvBehaviorCallbackConnection;
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ LLAvatarListItem::LLAvatarListItem(bool not_from_ui_factory/* = true*/)
|
|||
// [/RLVa:KB]
|
||||
mShowPermissions(false),
|
||||
mShowCompleteName(false),
|
||||
mForceCompleteName(false),
|
||||
mHovered(false),
|
||||
mAvatarNameCacheConnection(),
|
||||
mGreyOutUsername(""),
|
||||
|
|
@ -461,13 +462,11 @@ void LLAvatarListItem::setShowProfileBtn(bool show)
|
|||
|
||||
void LLAvatarListItem::showSpeakingIndicator(bool visible)
|
||||
{
|
||||
// Already done? Then do nothing.
|
||||
if (mSpeakingIndicator->getVisible() == (bool)visible)
|
||||
return;
|
||||
// Disabled to not contradict with SpeakingIndicatorManager functionality. EXT-3976
|
||||
// probably this method should be totally removed.
|
||||
// mSpeakingIndicator->setVisible(visible);
|
||||
// updateChildren();
|
||||
if (mSpeakingIndicator)
|
||||
{
|
||||
mSpeakingIndicator->setIsActiveChannel(visible);
|
||||
mSpeakingIndicator->setShowParticipantsSpeaking(visible);
|
||||
}
|
||||
}
|
||||
|
||||
void LLAvatarListItem::setAvatarIconVisible(bool visible)
|
||||
|
|
@ -594,8 +593,8 @@ void LLAvatarListItem::onAvatarNameCache(const LLAvatarName& av_name)
|
|||
{
|
||||
mAvatarNameCacheConnection.disconnect();
|
||||
//mGreyOutUsername = "";
|
||||
//std::string name_string = mShowCompleteName? av_name.getCompleteName(false) : av_name.getDisplayName();
|
||||
//if(av_name.getCompleteName() != av_name.getUserName())
|
||||
//std::string name_string = mShowCompleteName? av_name.getCompleteName(false, mForceCompleteName) : av_name.getDisplayName();
|
||||
//if(av_name.getCompleteName(false, mForceCompleteName) != av_name.getUserName())
|
||||
//{
|
||||
// mGreyOutUsername = "[ " + av_name.getUserName(true) + " ]";
|
||||
// LLStringUtil::toLower(mGreyOutUsername);
|
||||
|
|
@ -610,8 +609,8 @@ void LLAvatarListItem::onAvatarNameCache(const LLAvatarName& av_name)
|
|||
//else if (!mShowDisplayName && mShowUsername)
|
||||
// setAvatarName( (fRlvCanShowName) ? av_name.getUserName() : RlvStrings::getAnonym(av_name) );
|
||||
//else
|
||||
// setAvatarName( (fRlvCanShowName) ? av_name.getCompleteName() : RlvStrings::getAnonym(av_name) );
|
||||
setAvatarName(LLAvatarList::getNameForDisplay(mAvatarId, av_name, mShowDisplayName, mShowUsername, mRlvCheckShowNames));
|
||||
// setAvatarName( (fRlvCanShowName) ? av_name.getCompleteName(false, mForceCompleteName) : RlvStrings::getAnonym(av_name) );
|
||||
setAvatarName(LLAvatarList::getNameForDisplay(mAvatarId, av_name, mShowDisplayName, mShowUsername, mForceCompleteName, mRlvCheckShowNames));
|
||||
|
||||
// NOTE: If you change this, you will break sorting the contacts list
|
||||
// by username unless you go change the comparator too. -- TS
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ public:
|
|||
void setShowPermissions(bool show);
|
||||
void showLastInteractionTime(bool show);
|
||||
void setAvatarIconVisible(bool visible);
|
||||
void setShowCompleteName(bool show) { mShowCompleteName = show;};
|
||||
void setShowCompleteName(bool show, bool force = false) { mShowCompleteName = show; mForceCompleteName = force;};
|
||||
// [RLVa:KB] - Checked: RLVa-1.2.0
|
||||
void setRlvCheckShowNames(bool fRlvCheckShowNames);
|
||||
void updateRlvRestrictions();
|
||||
|
|
@ -265,6 +265,7 @@ private:
|
|||
bool mHovered;
|
||||
|
||||
bool mShowCompleteName;
|
||||
bool mForceCompleteName;
|
||||
std::string mGreyOutUsername;
|
||||
|
||||
void fetchAvatarName();
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ public:
|
|||
VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX |
|
||||
LLVertexBuffer::MAP_NORMAL |
|
||||
LLVertexBuffer::MAP_TANGENT | // Only PBR terrain uses this currently
|
||||
LLVertexBuffer::MAP_TEXCOORD0 | // Ownership overlay
|
||||
LLVertexBuffer::MAP_TEXCOORD1
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2711,7 +2711,6 @@ void LLEnvironment::setSharedEnvironment()
|
|||
{
|
||||
clearEnvironment(LLEnvironment::ENV_LOCAL);
|
||||
setSelectedEnvironment(LLEnvironment::ENV_LOCAL);
|
||||
updateEnvironment();
|
||||
}
|
||||
|
||||
void LLEnvironment::setExperienceEnvironment(LLUUID experience_id, LLUUID asset_id, F32 transition_time)
|
||||
|
|
|
|||
|
|
@ -89,9 +89,17 @@ bool LLFloaterBulkPermission::postBuild()
|
|||
{
|
||||
mBulkChangeNextOwnerTransfer = true;
|
||||
}
|
||||
|
||||
mQueueOutputList = getChild<LLScrollListCtrl>("queue output");
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLFloaterBulkPermission::onClose(bool app_quitting)
|
||||
{
|
||||
removeVOInventoryListener();
|
||||
LLFloater::onClose(app_quitting);
|
||||
}
|
||||
|
||||
void LLFloaterBulkPermission::doApply()
|
||||
{
|
||||
// Inspects a stream of selected object contents and adds modifiable ones to the given array.
|
||||
|
|
@ -216,7 +224,7 @@ void LLFloaterBulkPermission::onCommitCopy()
|
|||
bool LLFloaterBulkPermission::start()
|
||||
{
|
||||
// note: number of top-level objects to modify is mObjectIDs.size().
|
||||
getChild<LLScrollListCtrl>("queue output")->setCommentText(getString("start_text"));
|
||||
mQueueOutputList->setCommentText(getString("start_text"));
|
||||
return nextObject();
|
||||
}
|
||||
|
||||
|
|
@ -239,7 +247,7 @@ bool LLFloaterBulkPermission::nextObject()
|
|||
|
||||
if(isDone() && !mDone)
|
||||
{
|
||||
getChild<LLScrollListCtrl>("queue output")->setCommentText(getString("done_text"));
|
||||
mQueueOutputList->setCommentText(getString("done_text"));
|
||||
mDone = true;
|
||||
}
|
||||
return successful_start;
|
||||
|
|
@ -294,8 +302,6 @@ void LLFloaterBulkPermission::doCheckUncheckAll(bool check)
|
|||
|
||||
void LLFloaterBulkPermission::handleInventory(LLViewerObject* viewer_obj, LLInventoryObject::object_list_t* inv)
|
||||
{
|
||||
LLScrollListCtrl* list = getChild<LLScrollListCtrl>("queue output");
|
||||
|
||||
LLInventoryObject::object_list_t::const_iterator it = inv->begin();
|
||||
LLInventoryObject::object_list_t::const_iterator end = inv->end();
|
||||
for ( ; it != end; ++it)
|
||||
|
|
@ -362,7 +368,7 @@ void LLFloaterBulkPermission::handleInventory(LLViewerObject* viewer_obj, LLInve
|
|||
status_text.setArg("[STATUS]", "");
|
||||
}
|
||||
|
||||
list->setCommentText(status_text.getString());
|
||||
mQueueOutputList->setCommentText(status_text.getString());
|
||||
|
||||
//TODO if we are an object inside an object we should check a recuse flag and if set
|
||||
//open the inventory of the object and recurse - Michelle2 Zenovka
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ class LLFloaterBulkPermission : public LLFloater, public LLVOInventoryListener
|
|||
friend class LLFloaterReg;
|
||||
public:
|
||||
|
||||
bool postBuild();
|
||||
bool postBuild() override;
|
||||
void onClose(bool app_quitting) override;
|
||||
|
||||
private:
|
||||
|
||||
|
|
@ -57,7 +58,7 @@ private:
|
|||
/*virtual*/ void inventoryChanged(LLViewerObject* obj,
|
||||
LLInventoryObject::object_list_t* inv,
|
||||
S32 serial_num,
|
||||
void* queue);
|
||||
void* queue) override;
|
||||
|
||||
// This is called by inventoryChanged
|
||||
void handleInventory(LLViewerObject* viewer_obj,
|
||||
|
|
@ -85,7 +86,7 @@ private:
|
|||
|
||||
private:
|
||||
// UI
|
||||
LLScrollListCtrl* mMessages;
|
||||
LLScrollListCtrl* mQueueOutputList = nullptr;
|
||||
LLButton* mCloseBtn;
|
||||
|
||||
// Object Queue
|
||||
|
|
|
|||
|
|
@ -0,0 +1,189 @@
|
|||
/**
|
||||
* @file llfloaterchatmentionpicker.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2025&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2025, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloaterchatmentionpicker.h"
|
||||
|
||||
#include "llavatarlist.h"
|
||||
#include "llfloaterimcontainer.h"
|
||||
#include "llchatmentionhelper.h"
|
||||
#include "llparticipantlist.h"
|
||||
|
||||
LLUUID LLFloaterChatMentionPicker::sSessionID(LLUUID::null);
|
||||
|
||||
LLFloaterChatMentionPicker::LLFloaterChatMentionPicker(const LLSD& key)
|
||||
: LLFloater(key), mAvatarList(NULL)
|
||||
{
|
||||
// This floater should hover on top of our dependent (with the dependent having the focus)
|
||||
setFocusStealsFrontmost(false);
|
||||
setBackgroundVisible(false);
|
||||
setAutoFocus(false);
|
||||
}
|
||||
|
||||
bool LLFloaterChatMentionPicker::postBuild()
|
||||
{
|
||||
mAvatarList = getChild<LLAvatarList>("avatar_list");
|
||||
mAvatarList->setShowCompleteName(true, true);
|
||||
mAvatarList->setFocusOnItemClicked(false);
|
||||
mAvatarList->setItemClickedCallback([this](LLUICtrl* ctrl, S32 x, S32 y, MASK mask)
|
||||
{
|
||||
if (LLAvatarListItem* item = dynamic_cast<LLAvatarListItem*>(ctrl))
|
||||
{
|
||||
selectResident(item->getAvatarId());
|
||||
}
|
||||
});
|
||||
mAvatarList->setRefreshCompleteCallback([this](LLUICtrl* ctrl, const LLSD& param)
|
||||
{
|
||||
if (mAvatarList->numSelected() == 0)
|
||||
{
|
||||
mAvatarList->selectFirstItem();
|
||||
}
|
||||
});
|
||||
|
||||
return LLFloater::postBuild();
|
||||
}
|
||||
|
||||
void LLFloaterChatMentionPicker::onOpen(const LLSD& key)
|
||||
{
|
||||
buildAvatarList();
|
||||
mAvatarList->setNameFilter(key.has("av_name") ? key["av_name"].asString() : "");
|
||||
|
||||
gFloaterView->adjustToFitScreen(this, false);
|
||||
}
|
||||
|
||||
uuid_vec_t LLFloaterChatMentionPicker::getParticipantIds()
|
||||
{
|
||||
/*
|
||||
LLParticipantList* item = dynamic_cast<LLParticipantList*>(LLFloaterIMContainer::getInstance()->getSessionModel(sSessionID));
|
||||
if (!item)
|
||||
{
|
||||
LL_WARNS() << "Participant list is missing" << LL_ENDL;
|
||||
return {};
|
||||
}
|
||||
|
||||
uuid_vec_t avatar_ids;
|
||||
LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = item->getChildrenBegin();
|
||||
LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = item->getChildrenEnd();
|
||||
while (current_participant_model != end_participant_model)
|
||||
{
|
||||
LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>(*current_participant_model);
|
||||
if (participant_model)
|
||||
{
|
||||
avatar_ids.push_back(participant_model->getUUID());
|
||||
}
|
||||
current_participant_model++;
|
||||
}
|
||||
return avatar_ids;
|
||||
*/
|
||||
return{};
|
||||
}
|
||||
|
||||
void LLFloaterChatMentionPicker::buildAvatarList()
|
||||
{
|
||||
uuid_vec_t& avatar_ids = mAvatarList->getIDs();
|
||||
avatar_ids = getParticipantIds();
|
||||
updateAvatarList(avatar_ids);
|
||||
mAvatarList->setDirty();
|
||||
}
|
||||
|
||||
void LLFloaterChatMentionPicker::selectResident(const LLUUID& id)
|
||||
{
|
||||
if (id.isNull())
|
||||
return;
|
||||
|
||||
setValue(stringize("secondlife:///app/agent/", id.asString(), "/mention "));
|
||||
onCommit();
|
||||
LLChatMentionHelper::instance().hideHelper();
|
||||
}
|
||||
|
||||
void LLFloaterChatMentionPicker::onClose(bool app_quitting)
|
||||
{
|
||||
if (!app_quitting)
|
||||
{
|
||||
LLChatMentionHelper::instance().hideHelper();
|
||||
}
|
||||
}
|
||||
|
||||
bool LLFloaterChatMentionPicker::handleKey(KEY key, MASK mask, bool called_from_parent)
|
||||
{
|
||||
if (mask == MASK_NONE)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case KEY_UP:
|
||||
case KEY_DOWN:
|
||||
return mAvatarList->handleKey(key, mask, called_from_parent);
|
||||
case KEY_RETURN:
|
||||
case KEY_TAB:
|
||||
selectResident(mAvatarList->getSelectedUUID());
|
||||
return true;
|
||||
case KEY_ESCAPE:
|
||||
LLChatMentionHelper::instance().hideHelper();
|
||||
return true;
|
||||
case KEY_LEFT:
|
||||
case KEY_RIGHT:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return LLFloater::handleKey(key, mask, called_from_parent);
|
||||
}
|
||||
|
||||
void LLFloaterChatMentionPicker::goneFromFront()
|
||||
{
|
||||
LLChatMentionHelper::instance().hideHelper();
|
||||
}
|
||||
|
||||
void LLFloaterChatMentionPicker::updateSessionID(LLUUID session_id)
|
||||
{
|
||||
sSessionID = session_id;
|
||||
|
||||
/*
|
||||
LLParticipantList* item = dynamic_cast<LLParticipantList*>(LLFloaterIMContainer::getInstance()->getSessionModel(sSessionID));
|
||||
if (!item)
|
||||
{
|
||||
LL_WARNS() << "Participant list is missing" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
uuid_vec_t avatar_ids = getParticipantIds();
|
||||
updateAvatarList(avatar_ids);
|
||||
}
|
||||
|
||||
void LLFloaterChatMentionPicker::updateAvatarList(uuid_vec_t& avatar_ids)
|
||||
{
|
||||
std::vector<std::string> av_names;
|
||||
for (auto& id : avatar_ids)
|
||||
{
|
||||
LLAvatarName av_name;
|
||||
LLAvatarNameCache::get(id, &av_name);
|
||||
av_names.push_back(utf8str_tolower(av_name.getAccountName()));
|
||||
av_names.push_back(utf8str_tolower(av_name.getDisplayName()));
|
||||
}
|
||||
LLChatMentionHelper::instance().updateAvatarList(av_names);
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* @file llfloaterchatmentionpicker.h
|
||||
*
|
||||
* $LicenseInfo:firstyear=2025&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2025, 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 LLFLOATERCHATMENTIONPICKER_H
|
||||
#define LLFLOATERCHATMENTIONPICKER_H
|
||||
|
||||
#include "llfloater.h"
|
||||
|
||||
class LLAvatarList;
|
||||
|
||||
class LLFloaterChatMentionPicker : public LLFloater
|
||||
{
|
||||
public:
|
||||
LLFloaterChatMentionPicker(const LLSD& key);
|
||||
|
||||
virtual bool postBuild() override;
|
||||
virtual void goneFromFront() override;
|
||||
|
||||
void buildAvatarList();
|
||||
|
||||
static uuid_vec_t getParticipantIds();
|
||||
static void updateSessionID(LLUUID session_id);
|
||||
static void updateAvatarList(uuid_vec_t& avatar_ids);
|
||||
|
||||
private:
|
||||
|
||||
void onOpen(const LLSD& key) override;
|
||||
void onClose(bool app_quitting) override;
|
||||
virtual bool handleKey(KEY key, MASK mask, bool called_from_parent) override;
|
||||
void selectResident(const LLUUID& id);
|
||||
|
||||
static LLUUID sSessionID;
|
||||
LLAvatarList* mAvatarList;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -495,7 +495,6 @@ void LLFloaterEditExtDayCycle::setEditDayCycle(const LLSettingsDay::ptr_t &pday)
|
|||
|
||||
updateEditEnvironment();
|
||||
LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_EDIT, LLEnvironment::TRANSITION_INSTANT);
|
||||
LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
|
||||
synchronizeTabs();
|
||||
updateTabs();
|
||||
refresh();
|
||||
|
|
@ -824,7 +823,6 @@ void LLFloaterEditExtDayCycle::onClearTrack()
|
|||
|
||||
updateEditEnvironment();
|
||||
LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_EDIT, LLEnvironment::TRANSITION_INSTANT);
|
||||
LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
|
||||
synchronizeTabs();
|
||||
updateTabs();
|
||||
refresh();
|
||||
|
|
|
|||
|
|
@ -242,9 +242,7 @@ void LLFloaterEnvironmentAdjust::captureCurrentEnvironment()
|
|||
environment.setEnvironment(LLEnvironment::ENV_LOCAL, mLiveSky, FLOATER_ENVIRONMENT_UPDATE);
|
||||
environment.setEnvironment(LLEnvironment::ENV_LOCAL, mLiveWater, FLOATER_ENVIRONMENT_UPDATE);
|
||||
}
|
||||
environment.setSelectedEnvironment(LLEnvironment::ENV_LOCAL);
|
||||
environment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
|
||||
|
||||
environment.setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT);
|
||||
}
|
||||
|
||||
void LLFloaterEnvironmentAdjust::onButtonReset()
|
||||
|
|
@ -258,7 +256,6 @@ void LLFloaterEnvironmentAdjust::onButtonReset()
|
|||
this->closeFloater();
|
||||
LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_LOCAL);
|
||||
LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL);
|
||||
LLEnvironment::instance().updateEnvironment();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -596,7 +596,7 @@ void LLFloaterIMNearbyChat::sendChat( EChatType type )
|
|||
{
|
||||
if (mInputEditor)
|
||||
{
|
||||
LLWString text = mInputEditor->getWText();
|
||||
LLWString text = mInputEditor->getConvertedText();
|
||||
LLWStringUtil::trim(text);
|
||||
LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines.
|
||||
if (!text.empty())
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ void LLFloaterIMSession::sendMsgFromInputEditor()
|
|||
{
|
||||
if (mInputEditor)
|
||||
{
|
||||
LLWString text = mInputEditor->getWText();
|
||||
LLWString text = mInputEditor->getConvertedText();
|
||||
LLWStringUtil::trim(text);
|
||||
LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines.
|
||||
if(!text.empty())
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include "llavatariconctrl.h"
|
||||
#include "llchatentry.h"
|
||||
#include "llchathistory.h"
|
||||
#include "llfloaterchatmentionpicker.h"
|
||||
#include "llchiclet.h"
|
||||
#include "llchicletbar.h"
|
||||
#include "lldraghandle.h"
|
||||
|
|
@ -487,6 +488,7 @@ void LLFloaterIMSessionTab::onFocusReceived()
|
|||
LLIMModel::instance().sendNoUnreadMessages(mSessionID);
|
||||
}
|
||||
|
||||
LLFloaterChatMentionPicker::updateSessionID(mSessionID);
|
||||
super::onFocusReceived();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,29 +43,28 @@ bool LLFloaterNewFeatureNotification::postBuild()
|
|||
setCanDrag(false);
|
||||
getChild<LLButton>("close_btn")->setCommitCallback(boost::bind(&LLFloaterNewFeatureNotification::onCloseBtn, this));
|
||||
|
||||
const std::string title_txt = "title_txt";
|
||||
const std::string dsc_txt = "description_txt";
|
||||
// <FS:Beq> FIRE-35393 stop crashing just cos whirly does something daft and blames Atlas for it
|
||||
std::string feature = getKey().asString();
|
||||
if(feature.empty() )
|
||||
if (getKey().isString())
|
||||
{
|
||||
LL_WARNS("FloaterNewFeature") << "Unexpected failure - No feature name NewFeatureNotification." << LL_ENDL;
|
||||
return false;
|
||||
const std::string title_txt = "title_txt";
|
||||
const std::string dsc_txt = "description_txt";
|
||||
|
||||
std::string feature = "_" + getKey().asString();
|
||||
if (hasString(title_txt + feature))
|
||||
{
|
||||
getChild<LLUICtrl>(title_txt)->setValue(getString(title_txt + feature));
|
||||
getChild<LLUICtrl>(dsc_txt)->setValue(getString(dsc_txt + feature));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show blank
|
||||
LL_WARNS() << "Feature \"" << getKey().asString() << "\" not found for feature notification" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (!hasString( title_txt + "_" + feature ) )
|
||||
else
|
||||
{
|
||||
LL_WARNS("FloaterNewFeature") << "No string for " << title_txt + "_" + feature << LL_ENDL;
|
||||
return false;
|
||||
// Show blank
|
||||
LL_WARNS() << "Feature notification without a feature" << LL_ENDL;
|
||||
}
|
||||
if (!hasString( dsc_txt + "_" + feature ) )
|
||||
{
|
||||
LL_WARNS("FloaterNewFeature") << "No string for " << dsc_txt + "_" + feature << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
// </FS:Beq>
|
||||
|
||||
getChild<LLUICtrl>(title_txt)->setValue(getString(title_txt + "_" + feature));
|
||||
getChild<LLUICtrl>(dsc_txt)->setValue(getString(dsc_txt + "_" + feature));
|
||||
|
||||
if (getKey().asString() == "gltf")
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3010,7 +3010,7 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
|
|||
is_movable = false;
|
||||
tooltip_msg = LLTrans::getString("TooltipCantMoveOutfitIntoOutfit");
|
||||
}
|
||||
else if ((dest_res == MY_OUTFITS_OUTFIT || dest_res == MY_OUTFITS_SUBOUTFIT) && inv_res == MY_OUTFITS_SUBFOLDER)
|
||||
else if (dest_res == MY_OUTFITS_OUTFIT || dest_res == MY_OUTFITS_SUBOUTFIT)
|
||||
{
|
||||
is_movable = false;
|
||||
tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit");
|
||||
|
|
@ -4906,7 +4906,6 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
|
|||
if (cat->getPreferredType() == LLFolderType::FT_OUTFIT)
|
||||
{
|
||||
// Want some but not all of the items from getClipboardEntries for outfits.
|
||||
//items.push_back(std::string("New Outfit Folder")); // <FS:Ansariel> Normal subfolder underneath an outfit folder makes no sense
|
||||
items.push_back(std::string("Rename"));
|
||||
items.push_back(std::string("thumbnail"));
|
||||
|
||||
|
|
@ -4939,9 +4938,8 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
|
|||
{
|
||||
// Not inside an outfit, but inside 'my outfits'
|
||||
items.push_back(std::string("New Outfit"));
|
||||
items.push_back(std::string("New Outfit Folder"));
|
||||
}
|
||||
|
||||
items.push_back(std::string("New Outfit Folder"));
|
||||
items.push_back(std::string("Rename"));
|
||||
items.push_back(std::string("thumbnail"));
|
||||
|
||||
|
|
|
|||
|
|
@ -3789,7 +3789,7 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat,
|
|||
is_movable = false;
|
||||
tooltip_msg = LLTrans::getString("TooltipCantMoveOutfitIntoOutfit");
|
||||
}
|
||||
else if ((dest_res == MY_OUTFITS_OUTFIT || dest_res == MY_OUTFITS_SUBOUTFIT) && inv_res == MY_OUTFITS_SUBFOLDER)
|
||||
else if (dest_res == MY_OUTFITS_OUTFIT || dest_res == MY_OUTFITS_SUBOUTFIT)
|
||||
{
|
||||
is_movable = false;
|
||||
tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit");
|
||||
|
|
|
|||
|
|
@ -789,8 +789,8 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
|
|||
if (res != MY_OUTFITS_OUTFIT && res != MY_OUTFITS_SUBOUTFIT)
|
||||
{
|
||||
items.push_back(std::string("New Outfit"));
|
||||
items.push_back(std::string("New Outfit Folder"));
|
||||
}
|
||||
items.push_back(std::string("New Outfit Folder"));
|
||||
items.push_back(std::string("Delete"));
|
||||
items.push_back(std::string("Rename"));
|
||||
if (!get_is_category_and_children_removable(&gInventory, selected_id, false))
|
||||
|
|
|
|||
|
|
@ -560,6 +560,66 @@ bool RequestStats::isDelayed() const
|
|||
return mTimer.getStarted() && !mTimer.hasExpired();
|
||||
}
|
||||
|
||||
F32 calculate_score(LLVOVolume* object)
|
||||
{
|
||||
if (!object)
|
||||
{
|
||||
return -1.f;
|
||||
}
|
||||
LLDrawable* drawable = object->mDrawable;
|
||||
if (!drawable)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (drawable->isState(LLDrawable::RIGGED) || object->isAttachment())
|
||||
{
|
||||
LLVOAvatar* avatar = object->getAvatar();
|
||||
LLDrawable* av_drawable = avatar ? avatar->mDrawable : nullptr;
|
||||
if (avatar && av_drawable)
|
||||
{
|
||||
// See LLVOVolume::calcLOD()
|
||||
F32 radius;
|
||||
if (avatar->isControlAvatar())
|
||||
{
|
||||
const LLVector3* box = avatar->getLastAnimExtents();
|
||||
LLVector3 diag = box[1] - box[0];
|
||||
radius = diag.magVec() * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Volume in a rigged mesh attached to a regular avatar.
|
||||
const LLVector3* box = avatar->getLastAnimExtents();
|
||||
LLVector3 diag = box[1] - box[0];
|
||||
radius = diag.magVec();
|
||||
|
||||
if (!avatar->isSelf() && !avatar->hasFirstFullAttachmentData())
|
||||
{
|
||||
// slightly deprioritize avatars that are still receiving data
|
||||
radius *= 0.9f;
|
||||
}
|
||||
}
|
||||
return radius / llmax(av_drawable->mDistanceWRTCamera, 1.f);
|
||||
}
|
||||
}
|
||||
return drawable->getRadius() / llmax(drawable->mDistanceWRTCamera, 1.f);
|
||||
}
|
||||
|
||||
void PendingRequestBase::updateScore()
|
||||
{
|
||||
mScore = 0;
|
||||
if (mTrackedData)
|
||||
{
|
||||
for (LLVOVolume* volume : mTrackedData->mVolumes)
|
||||
{
|
||||
F32 cur_score = calculate_score(volume);
|
||||
if (cur_score > 0)
|
||||
{
|
||||
mScore = llmax(mScore, cur_score);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLViewerFetchedTexture* LLMeshUploadThread::FindViewerTexture(const LLImportMaterial& material)
|
||||
{
|
||||
LLPointer< LLViewerFetchedTexture > * ppTex = static_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData);
|
||||
|
|
@ -2327,7 +2387,7 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes
|
|||
|
||||
if (gMeshRepo.mLoadingSkins.find(mesh_id) == gMeshRepo.mLoadingSkins.end())
|
||||
{
|
||||
gMeshRepo.mLoadingSkins[mesh_id] = {}; // add an empty vector to indicate to main thread that we are loading skin info
|
||||
gMeshRepo.mLoadingSkins[mesh_id]; // add an empty vector to indicate to main thread that we are loading skin info
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4320,13 +4380,13 @@ void LLMeshRepository::unregisterMesh(LLVOVolume* vobj)
|
|||
{
|
||||
for (auto& param : lod)
|
||||
{
|
||||
vector_replace_with_last(param.second, vobj);
|
||||
vector_replace_with_last(param.second.mVolumes, vobj);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& skin_pair : mLoadingSkins)
|
||||
{
|
||||
vector_replace_with_last(skin_pair.second, vobj);
|
||||
vector_replace_with_last(skin_pair.second.mVolumes, vobj);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4349,16 +4409,17 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para
|
|||
mesh_load_map::iterator iter = mLoadingMeshes[new_lod].find(mesh_id);
|
||||
if (iter != mLoadingMeshes[new_lod].end())
|
||||
{ //request pending for this mesh, append volume id to list
|
||||
auto it = std::find(iter->second.begin(), iter->second.end(), vobj);
|
||||
if (it == iter->second.end()) {
|
||||
iter->second.push_back(vobj);
|
||||
auto it = std::find(iter->second.mVolumes.begin(), iter->second.mVolumes.end(), vobj);
|
||||
if (it == iter->second.mVolumes.end()) {
|
||||
iter->second.addVolume(vobj);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//first request for this mesh
|
||||
mLoadingMeshes[new_lod][mesh_id].push_back(vobj);
|
||||
mPendingRequests.emplace_back(new PendingRequestLOD(mesh_params, new_lod));
|
||||
std::shared_ptr<PendingRequestBase> request(new PendingRequestLOD(mesh_params, new_lod));
|
||||
mPendingRequests.emplace_back(request);
|
||||
mLoadingMeshes[new_lod][mesh_id].initData(vobj, request);
|
||||
LLMeshRepository::sLODPending++;
|
||||
}
|
||||
}
|
||||
|
|
@ -4417,50 +4478,6 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para
|
|||
return new_lod;
|
||||
}
|
||||
|
||||
F32 calculate_score(LLVOVolume* object)
|
||||
{
|
||||
if (!object)
|
||||
{
|
||||
return -1.f;
|
||||
}
|
||||
LLDrawable* drawable = object->mDrawable;
|
||||
if (!drawable)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (drawable->isState(LLDrawable::RIGGED) || object->isAttachment())
|
||||
{
|
||||
LLVOAvatar* avatar = object->getAvatar();
|
||||
LLDrawable* av_drawable = avatar ? avatar->mDrawable : nullptr;
|
||||
if (avatar && av_drawable)
|
||||
{
|
||||
// See LLVOVolume::calcLOD()
|
||||
F32 radius;
|
||||
if (avatar->isControlAvatar())
|
||||
{
|
||||
const LLVector3* box = avatar->getLastAnimExtents();
|
||||
LLVector3 diag = box[1] - box[0];
|
||||
radius = diag.magVec() * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Volume in a rigged mesh attached to a regular avatar.
|
||||
const LLVector3* box = avatar->getLastAnimExtents();
|
||||
LLVector3 diag = box[1] - box[0];
|
||||
radius = diag.magVec();
|
||||
|
||||
if (!avatar->isSelf() && !avatar->hasFirstFullAttachmentData())
|
||||
{
|
||||
// slightly deprioritize avatars that are still receiving data
|
||||
radius *= 0.9f;
|
||||
}
|
||||
}
|
||||
return radius / llmax(av_drawable->mDistanceWRTCamera, 1.f);
|
||||
}
|
||||
}
|
||||
return drawable->getRadius() / llmax(drawable->mDistanceWRTCamera, 1.f);
|
||||
}
|
||||
|
||||
void LLMeshRepository::notifyLoadedMeshes()
|
||||
{ //called from main thread
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
|
||||
|
|
@ -4727,51 +4744,14 @@ void LLMeshRepository::notifyLoadedMeshes()
|
|||
|
||||
if (mPendingRequests.size() > push_count)
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED("Mesh score_map");
|
||||
LL_PROFILE_ZONE_NAMED("Mesh score update");
|
||||
// More requests than the high-water limit allows so
|
||||
// sort and forward the most important.
|
||||
|
||||
//calculate "score" for pending requests
|
||||
|
||||
//create score map
|
||||
std::map<LLUUID, F32> score_map;
|
||||
|
||||
for (U32 i = 0; i < LLVolumeLODGroup::NUM_LODS; ++i)
|
||||
// update "score" for pending requests
|
||||
for (std::shared_ptr<PendingRequestBase>& req_p : mPendingRequests)
|
||||
{
|
||||
for (mesh_load_map::iterator iter = mLoadingMeshes[i].begin(); iter != mLoadingMeshes[i].end(); ++iter)
|
||||
{
|
||||
F32 max_score = 0.f;
|
||||
for (auto obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter)
|
||||
{
|
||||
F32 cur_score = calculate_score(*obj_iter);
|
||||
if (cur_score >= 0.f)
|
||||
{
|
||||
max_score = llmax(max_score, cur_score);
|
||||
}
|
||||
}
|
||||
|
||||
score_map[iter->first] = max_score;
|
||||
}
|
||||
}
|
||||
for (mesh_load_map::iterator iter = mLoadingSkins.begin(); iter != mLoadingSkins.end(); ++iter)
|
||||
{
|
||||
F32 max_score = 0.f;
|
||||
for (auto obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter)
|
||||
{
|
||||
F32 cur_score = calculate_score(*obj_iter);
|
||||
if (cur_score >= 0.f)
|
||||
{
|
||||
max_score = llmax(max_score, cur_score);
|
||||
}
|
||||
}
|
||||
|
||||
score_map[iter->first] = max_score;
|
||||
}
|
||||
|
||||
//set "score" for pending requests
|
||||
for (std::unique_ptr<PendingRequestBase>& req_p : mPendingRequests)
|
||||
{
|
||||
req_p->setScore(score_map[req_p->getId()]);
|
||||
req_p->checkScore();
|
||||
}
|
||||
|
||||
//sort by "score"
|
||||
|
|
@ -4780,7 +4760,9 @@ void LLMeshRepository::notifyLoadedMeshes()
|
|||
}
|
||||
while (!mPendingRequests.empty() && push_count > 0)
|
||||
{
|
||||
std::unique_ptr<PendingRequestBase>& req_p = mPendingRequests.front();
|
||||
std::shared_ptr<PendingRequestBase>& req_p = mPendingRequests.front();
|
||||
// todo: check hasTrackedData here and erase request if none
|
||||
// since this is supposed to mean that request was removed
|
||||
switch (req_p->getRequestType())
|
||||
{
|
||||
case MESH_REQUEST_LOD:
|
||||
|
|
@ -4835,7 +4817,7 @@ void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo* info)
|
|||
skin_load_map::iterator iter = mLoadingSkins.find(info->mMeshID);
|
||||
if (iter != mLoadingSkins.end())
|
||||
{
|
||||
for (LLVOVolume* vobj : iter->second)
|
||||
for (LLVOVolume* vobj : iter->second.mVolumes)
|
||||
{
|
||||
if (vobj)
|
||||
{
|
||||
|
|
@ -4851,7 +4833,7 @@ void LLMeshRepository::notifySkinInfoUnavailable(const LLUUID& mesh_id)
|
|||
skin_load_map::iterator iter = mLoadingSkins.find(mesh_id);
|
||||
if (iter != mLoadingSkins.end())
|
||||
{
|
||||
for (LLVOVolume* vobj : iter->second)
|
||||
for (LLVOVolume* vobj : iter->second.mVolumes)
|
||||
{
|
||||
if (vobj)
|
||||
{
|
||||
|
|
@ -4915,7 +4897,7 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol
|
|||
}
|
||||
|
||||
//notify waiting LLVOVolume instances that their requested mesh is available
|
||||
for (LLVOVolume* vobj : obj_iter->second)
|
||||
for (LLVOVolume* vobj : obj_iter->second.mVolumes)
|
||||
{
|
||||
if (vobj)
|
||||
{
|
||||
|
|
@ -4945,7 +4927,7 @@ void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params,
|
|||
LLPrimitive::getVolumeManager()->unrefVolume(sys_volume);
|
||||
}
|
||||
|
||||
for (LLVOVolume* vobj : obj_iter->second)
|
||||
for (LLVOVolume* vobj : obj_iter->second.mVolumes)
|
||||
{
|
||||
if (vobj)
|
||||
{
|
||||
|
|
@ -4988,16 +4970,17 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, LLVOV
|
|||
skin_load_map::iterator iter = mLoadingSkins.find(mesh_id);
|
||||
if (iter != mLoadingSkins.end())
|
||||
{ //request pending for this mesh, append volume id to list
|
||||
auto it = std::find(iter->second.begin(), iter->second.end(), requesting_obj);
|
||||
if (it == iter->second.end()) {
|
||||
iter->second.push_back(requesting_obj);
|
||||
auto it = std::find(iter->second.mVolumes.begin(), iter->second.mVolumes.end(), requesting_obj);
|
||||
if (it == iter->second.mVolumes.end()) {
|
||||
iter->second.addVolume(requesting_obj);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//first request for this mesh
|
||||
mLoadingSkins[mesh_id].push_back(requesting_obj);
|
||||
mPendingRequests.emplace_back(new PendingRequestUUID(mesh_id, MESH_REQUEST_SKIN));
|
||||
std::shared_ptr<PendingRequestBase> request(new PendingRequestUUID(mesh_id, MESH_REQUEST_SKIN));
|
||||
mLoadingSkins[mesh_id].initData(requesting_obj, request);
|
||||
mPendingRequests.emplace_back(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,7 +168,6 @@ public:
|
|||
|
||||
void submitRequest(Request* request);
|
||||
static S32 llcdCallback(const char*, S32, S32);
|
||||
void cancel();
|
||||
|
||||
void setMeshData(LLCDMeshData& mesh, bool vertex_based);
|
||||
void doDecomposition();
|
||||
|
|
@ -206,19 +205,19 @@ private:
|
|||
LLFrameTimer mTimer;
|
||||
};
|
||||
|
||||
|
||||
class MeshLoadData;
|
||||
class PendingRequestBase
|
||||
{
|
||||
public:
|
||||
struct CompareScoreGreater
|
||||
{
|
||||
bool operator()(const std::unique_ptr<PendingRequestBase>& lhs, const std::unique_ptr<PendingRequestBase>& rhs)
|
||||
bool operator()(const std::shared_ptr<PendingRequestBase>& lhs, const std::shared_ptr<PendingRequestBase>& rhs)
|
||||
{
|
||||
return lhs->mScore > rhs->mScore; // greatest = first
|
||||
}
|
||||
};
|
||||
|
||||
PendingRequestBase() : mScore(0.f) {};
|
||||
PendingRequestBase() : mScore(0.f), mTrackedData(nullptr), mScoreDirty(true) {};
|
||||
virtual ~PendingRequestBase() {}
|
||||
|
||||
bool operator<(const PendingRequestBase& rhs) const
|
||||
|
|
@ -226,14 +225,34 @@ public:
|
|||
return mId < rhs.mId;
|
||||
}
|
||||
|
||||
void setScore(F32 score) { mScore = score; }
|
||||
F32 getScore() const { return mScore; }
|
||||
void checkScore()
|
||||
{
|
||||
constexpr F32 EXPIRE_TIME_SECS = 8.f;
|
||||
if (mScoreTimer.getElapsedTimeF32() > EXPIRE_TIME_SECS || mScoreDirty)
|
||||
{
|
||||
updateScore();
|
||||
mScoreDirty = false;
|
||||
mScoreTimer.reset();
|
||||
}
|
||||
};
|
||||
|
||||
LLUUID getId() const { return mId; }
|
||||
virtual EMeshRequestType getRequestType() const = 0;
|
||||
|
||||
void trackData(MeshLoadData* data) { mTrackedData = data; mScoreDirty = true; }
|
||||
void untrackData() { mTrackedData = nullptr; }
|
||||
bool hasTrackedData() { return mTrackedData != nullptr; }
|
||||
void setScoreDirty() { mScoreDirty = true; }
|
||||
|
||||
protected:
|
||||
F32 mScore;
|
||||
void updateScore();
|
||||
|
||||
LLUUID mId;
|
||||
F32 mScore;
|
||||
bool mScoreDirty;
|
||||
LLTimer mScoreTimer;
|
||||
MeshLoadData* mTrackedData;
|
||||
};
|
||||
|
||||
class PendingRequestLOD : public PendingRequestBase
|
||||
|
|
@ -267,6 +286,37 @@ private:
|
|||
EMeshRequestType mRequestType;
|
||||
};
|
||||
|
||||
|
||||
class MeshLoadData
|
||||
{
|
||||
public:
|
||||
MeshLoadData() {}
|
||||
~MeshLoadData()
|
||||
{
|
||||
if (std::shared_ptr<PendingRequestBase> request = mRequest.lock())
|
||||
{
|
||||
request->untrackData();
|
||||
}
|
||||
}
|
||||
void initData(LLVOVolume* vol, std::shared_ptr<PendingRequestBase>& request)
|
||||
{
|
||||
mVolumes.push_back(vol);
|
||||
request->trackData(this);
|
||||
mRequest = request;
|
||||
}
|
||||
void addVolume(LLVOVolume* vol)
|
||||
{
|
||||
mVolumes.push_back(vol);
|
||||
if (std::shared_ptr<PendingRequestBase> request = mRequest.lock())
|
||||
{
|
||||
request->setScoreDirty();
|
||||
}
|
||||
}
|
||||
std::vector<LLVOVolume*> mVolumes;
|
||||
private:
|
||||
std::weak_ptr<PendingRequestBase> mRequest;
|
||||
};
|
||||
|
||||
class LLMeshHeader
|
||||
{
|
||||
public:
|
||||
|
|
@ -845,7 +895,7 @@ public:
|
|||
static void metricsProgress(unsigned int count);
|
||||
static void metricsUpdate();
|
||||
|
||||
typedef std::unordered_map<LLUUID, std::vector<LLVOVolume*> > mesh_load_map;
|
||||
typedef std::unordered_map<LLUUID, MeshLoadData> mesh_load_map;
|
||||
mesh_load_map mLoadingMeshes[4];
|
||||
|
||||
// <FS:Ansariel> DAE export
|
||||
|
|
@ -859,11 +909,11 @@ public:
|
|||
|
||||
LLMutex* mMeshMutex;
|
||||
|
||||
typedef std::vector <std::unique_ptr<PendingRequestBase> > pending_requests_vec;
|
||||
typedef std::vector <std::shared_ptr<PendingRequestBase> > pending_requests_vec;
|
||||
pending_requests_vec mPendingRequests;
|
||||
|
||||
//list of mesh ids awaiting skin info
|
||||
typedef std::unordered_map<LLUUID, std::vector<LLVOVolume*> > skin_load_map;
|
||||
typedef std::unordered_map<LLUUID, MeshLoadData > skin_load_map;
|
||||
skin_load_map mLoadingSkins;
|
||||
|
||||
//list of mesh ids awaiting decompositions
|
||||
|
|
|
|||
|
|
@ -333,8 +333,8 @@ public:
|
|||
|
||||
const std::string verb = params[1].asString();
|
||||
// <FS:Ansariel> FIRE-9045: Inspect links always open full profile
|
||||
//if (verb == "about")
|
||||
if (verb == "about" || (gSavedSettings.getBOOL("FSInspectAvatarSlurlOpensProfile") && verb == "inspect"))
|
||||
//if (verb == "about" || verb == "mention")
|
||||
if (verb == "about" || verb == "mention" || (gSavedSettings.getBOOL("FSInspectAvatarSlurlOpensProfile") && verb == "inspect"))
|
||||
// </FS:Ansariel>
|
||||
{
|
||||
LLAvatarActions::showProfile(avatar_id);
|
||||
|
|
|
|||
|
|
@ -4590,7 +4590,7 @@ bool process_login_success_response(U32 &first_sim_size_x, U32 &first_sim_size_y
|
|||
|
||||
// Agent id needed for parcel info request in LLUrlEntryParcel
|
||||
// to resolve parcel name.
|
||||
LLUrlEntryParcel::setAgentID(gAgentID);
|
||||
LLUrlEntryBase::setAgentID(gAgentID);
|
||||
|
||||
text = response["session_id"].asString();
|
||||
if(!text.empty()) gAgentSessionID.set(text);
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ LLVector2 LLSurfacePatch::getTexCoords(const U32 x, const U32 y) const
|
|||
|
||||
|
||||
void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3 *vertex, LLVector3 *normal,
|
||||
LLVector2 *tex1) const
|
||||
LLVector2* tex0, LLVector2 *tex1) const
|
||||
{
|
||||
if (!mSurfacep || !mSurfacep->getRegion() || !mSurfacep->getGridsPerEdge() || !mVObjp)
|
||||
{
|
||||
|
|
@ -235,6 +235,7 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3
|
|||
llassert_always(vertex && normal && tex1);
|
||||
|
||||
U32 surface_stride = mSurfacep->getGridsPerEdge();
|
||||
U32 texture_stride = mSurfacep->getGridsPerEdge() - 1;
|
||||
U32 point_offset = x + y*surface_stride;
|
||||
|
||||
*normal = getNormal(x, y);
|
||||
|
|
@ -245,6 +246,12 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3
|
|||
pos_agent.mV[VZ] = *(mDataZ + point_offset);
|
||||
*vertex = pos_agent-mVObjp->getRegion()->getOriginAgent();
|
||||
|
||||
// tex0 is used for ownership overlay
|
||||
LLVector3 rel_pos = pos_agent - mSurfacep->getOriginAgent();
|
||||
LLVector3 tex_pos = rel_pos * (1.f / (texture_stride * mSurfacep->getMetersPerGrid()));
|
||||
tex0->mV[0] = tex_pos.mV[0];
|
||||
tex0->mV[1] = tex_pos.mV[1];
|
||||
|
||||
tex1->mV[0] = mSurfacep->getRegion()->getCompositionXY(llfloor(mOriginRegion.mV[0])+x, llfloor(mOriginRegion.mV[1])+y);
|
||||
|
||||
const F32 xyScale = 4.9215f*7.f; //0.93284f;
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ public:
|
|||
void calcNormalFlat(LLVector3& normal_out, const U32 x, const U32 y, const U32 index /* 0 or 1 */);
|
||||
|
||||
void eval(const U32 x, const U32 y, const U32 stride,
|
||||
LLVector3 *vertex, LLVector3 *normal, LLVector2 *tex1) const;
|
||||
LLVector3 *vertex, LLVector3 *normal, LLVector2* tex0, LLVector2 *tex1) const;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -204,8 +204,9 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion&
|
|||
{
|
||||
LLVector3 scratch3;
|
||||
LLVector3 pos3;
|
||||
LLVector2 tex0_temp;
|
||||
LLVector2 tex1_temp;
|
||||
patch->eval(i, j, stride, &pos3, &scratch3, &tex1_temp);
|
||||
patch->eval(i, j, stride, &pos3, &scratch3, &tex0_temp, &tex1_temp);
|
||||
(*pos++).set(pos3.mV[VX], pos3.mV[VY], pos3.mV[VZ]);
|
||||
*tex1++ = tex1_temp;
|
||||
vertex_total++;
|
||||
|
|
|
|||
|
|
@ -1352,27 +1352,39 @@ U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries)
|
|||
}
|
||||
for (U32 idx=0; idx<num_entries; idx++)
|
||||
{
|
||||
Entry entry;
|
||||
S32 bytes_read = aprfile->read((void*)(&entry), (S32)sizeof(Entry));
|
||||
if (bytes_read < sizeof(Entry))
|
||||
try
|
||||
{
|
||||
LL_WARNS() << "Corrupted header entries, failed at " << idx << " / " << num_entries << LL_ENDL;
|
||||
Entry entry;
|
||||
S32 bytes_read = aprfile->read((void*)(&entry), (S32)sizeof(Entry));
|
||||
if (bytes_read < sizeof(Entry))
|
||||
{
|
||||
LL_WARNS() << "Corrupted header entries, failed at " << idx << " / " << num_entries << LL_ENDL;
|
||||
return 0;
|
||||
}
|
||||
entries.push_back(entry);
|
||||
// LL_INFOS() << "ENTRY: " << entry.mTime << " TEX: " << entry.mID << " IDX: " << idx << " Size: " << entry.mImageSize << LL_ENDL;
|
||||
if (entry.mImageSize > entry.mBodySize)
|
||||
{
|
||||
mHeaderIDMap[entry.mID] = idx;
|
||||
mTexturesSizeMap[entry.mID] = entry.mBodySize;
|
||||
mTexturesSizeTotal += entry.mBodySize;
|
||||
}
|
||||
else
|
||||
{
|
||||
mFreeList.insert(idx);
|
||||
}
|
||||
}
|
||||
catch (std::bad_alloc&)
|
||||
{
|
||||
// Too little ram yet very large cache?
|
||||
// Should this actually crash viewer?
|
||||
entries.clear();
|
||||
LL_WARNS() << "Bad alloc trying to read texture entries from cache, mFreeList: " << (S32)mFreeList.size()
|
||||
<< ", added entries: " << idx << ", total entries: " << num_entries << LL_ENDL;
|
||||
closeHeaderEntriesFile();
|
||||
purgeAllTextures(false);
|
||||
return 0;
|
||||
}
|
||||
entries.push_back(entry);
|
||||
// LL_INFOS() << "ENTRY: " << entry.mTime << " TEX: " << entry.mID << " IDX: " << idx << " Size: " << entry.mImageSize << LL_ENDL;
|
||||
if(entry.mImageSize > entry.mBodySize)
|
||||
{
|
||||
mHeaderIDMap[entry.mID] = idx;
|
||||
mTexturesSizeMap[entry.mID] = entry.mBodySize;
|
||||
mTexturesSizeTotal += entry.mBodySize;
|
||||
}
|
||||
else
|
||||
{
|
||||
mFreeList.insert(idx);
|
||||
}
|
||||
}
|
||||
closeHeaderEntriesFile();
|
||||
return num_entries;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "llviewerregion.h"
|
||||
#include "llworld.h"
|
||||
#include "llinstantmessage.h" //SYSTEM_FROM
|
||||
#include "llurlregistry.h"
|
||||
#include "fskeywords.h"
|
||||
#include "lggcontactsets.h"
|
||||
#include "rlvhandler.h"
|
||||
|
|
@ -300,6 +301,13 @@ void LLViewerChat::formatChatMsg(const LLChat& chat, std::string& formated_msg)
|
|||
{
|
||||
std::string tmpmsg = chat.mText;
|
||||
|
||||
// show @name instead of slurl for chat mentions
|
||||
LLUrlMatch match;
|
||||
while (LLUrlRegistry::instance().findUrl(tmpmsg, match, LLUrlRegistryNullCallback, false, true))
|
||||
{
|
||||
tmpmsg.replace(match.getStart(), match.getEnd() - match.getStart() + 1, match.getLabel());
|
||||
}
|
||||
|
||||
if(chat.mChatStyle == CHAT_STYLE_IRC)
|
||||
{
|
||||
formated_msg = chat.mFromName + tmpmsg.substr(3);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@
|
|||
#include "llfloatercamera.h"
|
||||
#include "llfloatercamerapresets.h"
|
||||
#include "llfloaterchangeitemthumbnail.h"
|
||||
#include "llfloaterchatmentionpicker.h"
|
||||
#include "llfloaterchatvoicevolume.h"
|
||||
#include "llfloaterclassified.h"
|
||||
#include "llfloaterconversationlog.h"
|
||||
|
|
@ -426,6 +427,7 @@ void LLViewerFloaterReg::registerFloaters()
|
|||
//LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterIMNearbyChat::buildFloater);
|
||||
LLFloaterReg::add("fs_nearby_chat", "floater_fs_nearby_chat.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<FSFloaterNearbyChat>);
|
||||
// </FS:Ansariel> [FS communication UI]
|
||||
LLFloaterReg::add("chat_mention_picker", "floater_chat_mention_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatMentionPicker>);
|
||||
LLFloaterReg::add("classified", "floater_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterClassified>);
|
||||
LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>);
|
||||
LLFloaterReg::add("conversation", "floater_conversation_log.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationLog>);
|
||||
|
|
|
|||
|
|
@ -245,6 +245,7 @@ bool LLVOSurfacePatch::updateLOD()
|
|||
|
||||
void LLVOSurfacePatch::getTerrainGeometry(LLStrider<LLVector3> &verticesp,
|
||||
LLStrider<LLVector3> &normalsp,
|
||||
LLStrider<LLVector2> &texCoords0p,
|
||||
LLStrider<LLVector2> &texCoords1p,
|
||||
LLStrider<U16> &indicesp)
|
||||
{
|
||||
|
|
@ -259,18 +260,21 @@ void LLVOSurfacePatch::getTerrainGeometry(LLStrider<LLVector3> &verticesp,
|
|||
updateMainGeometry(facep,
|
||||
verticesp,
|
||||
normalsp,
|
||||
texCoords0p,
|
||||
texCoords1p,
|
||||
indicesp,
|
||||
index_offset);
|
||||
updateNorthGeometry(facep,
|
||||
verticesp,
|
||||
normalsp,
|
||||
texCoords0p,
|
||||
texCoords1p,
|
||||
indicesp,
|
||||
index_offset);
|
||||
updateEastGeometry(facep,
|
||||
verticesp,
|
||||
normalsp,
|
||||
texCoords0p,
|
||||
texCoords1p,
|
||||
indicesp,
|
||||
index_offset);
|
||||
|
|
@ -279,6 +283,7 @@ void LLVOSurfacePatch::getTerrainGeometry(LLStrider<LLVector3> &verticesp,
|
|||
void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,
|
||||
LLStrider<LLVector3> &verticesp,
|
||||
LLStrider<LLVector3> &normalsp,
|
||||
LLStrider<LLVector2> &texCoords0p,
|
||||
LLStrider<LLVector2> &texCoords1p,
|
||||
LLStrider<U16> &indicesp,
|
||||
U32 &index_offset)
|
||||
|
|
@ -317,9 +322,10 @@ void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,
|
|||
{
|
||||
x = i * render_stride;
|
||||
y = j * render_stride;
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
|
||||
verticesp++;
|
||||
normalsp++;
|
||||
texCoords0p++;
|
||||
texCoords1p++;
|
||||
}
|
||||
}
|
||||
|
|
@ -381,6 +387,7 @@ void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,
|
|||
void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
|
||||
LLStrider<LLVector3> &verticesp,
|
||||
LLStrider<LLVector3> &normalsp,
|
||||
LLStrider<LLVector2> &texCoords0p,
|
||||
LLStrider<LLVector2> &texCoords1p,
|
||||
LLStrider<U16> &indicesp,
|
||||
U32 &index_offset)
|
||||
|
|
@ -414,9 +421,10 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
|
|||
x = i * render_stride;
|
||||
y = 16 - render_stride;
|
||||
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
|
||||
verticesp++;
|
||||
normalsp++;
|
||||
texCoords0p++;
|
||||
texCoords1p++;
|
||||
}
|
||||
|
||||
|
|
@ -425,9 +433,10 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
|
|||
{
|
||||
x = i * render_stride;
|
||||
y = 16;
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
|
||||
verticesp++;
|
||||
normalsp++;
|
||||
texCoords0p++;
|
||||
texCoords1p++;
|
||||
}
|
||||
|
||||
|
|
@ -460,9 +469,10 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
|
|||
x = i * render_stride;
|
||||
y = 16 - render_stride;
|
||||
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
|
||||
verticesp++;
|
||||
normalsp++;
|
||||
texCoords0p++;
|
||||
texCoords1p++;
|
||||
}
|
||||
|
||||
|
|
@ -472,9 +482,10 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
|
|||
x = i * render_stride;
|
||||
y = 16;
|
||||
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
|
||||
verticesp++;
|
||||
normalsp++;
|
||||
texCoords0p++;
|
||||
texCoords1p++;
|
||||
}
|
||||
|
||||
|
|
@ -514,9 +525,10 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
|
|||
x = i * north_stride;
|
||||
y = 16 - render_stride;
|
||||
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
|
||||
verticesp++;
|
||||
normalsp++;
|
||||
texCoords0p++;
|
||||
texCoords1p++;
|
||||
}
|
||||
|
||||
|
|
@ -526,9 +538,10 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
|
|||
x = i * north_stride;
|
||||
y = 16;
|
||||
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
|
||||
verticesp++;
|
||||
normalsp++;
|
||||
texCoords0p++;
|
||||
texCoords1p++;
|
||||
}
|
||||
|
||||
|
|
@ -564,6 +577,7 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
|
|||
void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
|
||||
LLStrider<LLVector3> &verticesp,
|
||||
LLStrider<LLVector3> &normalsp,
|
||||
LLStrider<LLVector2> &texCoords0p,
|
||||
LLStrider<LLVector2> &texCoords1p,
|
||||
LLStrider<U16> &indicesp,
|
||||
U32 &index_offset)
|
||||
|
|
@ -592,9 +606,10 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
|
|||
x = 16 - render_stride;
|
||||
y = i * render_stride;
|
||||
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
|
||||
verticesp++;
|
||||
normalsp++;
|
||||
texCoords0p++;
|
||||
texCoords1p++;
|
||||
}
|
||||
|
||||
|
|
@ -603,9 +618,10 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
|
|||
{
|
||||
x = 16;
|
||||
y = i * render_stride;
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
|
||||
verticesp++;
|
||||
normalsp++;
|
||||
texCoords0p++;
|
||||
texCoords1p++;
|
||||
}
|
||||
|
||||
|
|
@ -638,9 +654,10 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
|
|||
x = 16 - render_stride;
|
||||
y = i * render_stride;
|
||||
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
|
||||
verticesp++;
|
||||
normalsp++;
|
||||
texCoords0p++;
|
||||
texCoords1p++;
|
||||
}
|
||||
// Iterate through the east patch's points
|
||||
|
|
@ -649,9 +666,10 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
|
|||
x = 16;
|
||||
y = i * render_stride;
|
||||
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
|
||||
verticesp++;
|
||||
normalsp++;
|
||||
texCoords0p++;
|
||||
texCoords1p++;
|
||||
}
|
||||
|
||||
|
|
@ -690,9 +708,10 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
|
|||
x = 16 - render_stride;
|
||||
y = i * east_stride;
|
||||
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
|
||||
verticesp++;
|
||||
normalsp++;
|
||||
texCoords0p++;
|
||||
texCoords1p++;
|
||||
}
|
||||
// Iterate through the east patch's points
|
||||
|
|
@ -701,9 +720,10 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
|
|||
x = 16;
|
||||
y = i * east_stride;
|
||||
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
|
||||
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
|
||||
verticesp++;
|
||||
normalsp++;
|
||||
texCoords0p++;
|
||||
texCoords1p++;
|
||||
}
|
||||
|
||||
|
|
@ -1022,12 +1042,14 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
|
|||
LLStrider<LLVector3> vertices_start;
|
||||
LLStrider<LLVector3> normals_start;
|
||||
LLStrider<LLVector4a> tangents_start;
|
||||
LLStrider<LLVector2> texcoords0_start; // ownership overlay
|
||||
LLStrider<LLVector2> texcoords2_start;
|
||||
LLStrider<U16> indices_start;
|
||||
|
||||
llassert_always(buffer->getVertexStrider(vertices_start));
|
||||
llassert_always(buffer->getNormalStrider(normals_start));
|
||||
llassert_always(buffer->getTangentStrider(tangents_start));
|
||||
llassert_always(buffer->getTexCoord0Strider(texcoords0_start));
|
||||
llassert_always(buffer->getTexCoord1Strider(texcoords2_start));
|
||||
llassert_always(buffer->getIndexStrider(indices_start));
|
||||
|
||||
|
|
@ -1037,6 +1059,7 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
|
|||
{
|
||||
LLStrider<LLVector3> vertices = vertices_start;
|
||||
LLStrider<LLVector3> normals = normals_start;
|
||||
LLStrider<LLVector2> texcoords0 = texcoords0_start;
|
||||
LLStrider<LLVector2> texcoords2 = texcoords2_start;
|
||||
LLStrider<U16> indices = indices_start;
|
||||
|
||||
|
|
@ -1049,7 +1072,7 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
|
|||
facep->setVertexBuffer(buffer);
|
||||
|
||||
LLVOSurfacePatch* patchp = (LLVOSurfacePatch*) facep->getViewerObject();
|
||||
patchp->getTerrainGeometry(vertices, normals, texcoords2, indices);
|
||||
patchp->getTerrainGeometry(vertices, normals, texcoords0, texcoords2, indices);
|
||||
|
||||
indices_index += facep->getIndicesCount();
|
||||
index_offset += facep->getGeomCount();
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ public:
|
|||
/*virtual*/ void updateFaceSize(S32 idx);
|
||||
void getTerrainGeometry(LLStrider<LLVector3> &verticesp,
|
||||
LLStrider<LLVector3> &normalsp,
|
||||
LLStrider<LLVector2> &texCoords0p,
|
||||
LLStrider<LLVector2> &texCoords1p,
|
||||
LLStrider<U16> &indicesp);
|
||||
|
||||
|
|
@ -109,18 +110,21 @@ protected:
|
|||
void updateMainGeometry(LLFace *facep,
|
||||
LLStrider<LLVector3> &verticesp,
|
||||
LLStrider<LLVector3> &normalsp,
|
||||
LLStrider<LLVector2> &texCoords0p,
|
||||
LLStrider<LLVector2> &texCoords1p,
|
||||
LLStrider<U16> &indicesp,
|
||||
U32 &index_offset);
|
||||
void updateNorthGeometry(LLFace *facep,
|
||||
LLStrider<LLVector3> &verticesp,
|
||||
LLStrider<LLVector3> &normalsp,
|
||||
LLStrider<LLVector2> &texCoords0p,
|
||||
LLStrider<LLVector2> &texCoords1p,
|
||||
LLStrider<U16> &indicesp,
|
||||
U32 &index_offset);
|
||||
void updateEastGeometry(LLFace *facep,
|
||||
LLStrider<LLVector3> &verticesp,
|
||||
LLStrider<LLVector3> &normalsp,
|
||||
LLStrider<LLVector2> &texCoords0p,
|
||||
LLStrider<LLVector2> &texCoords1p,
|
||||
LLStrider<U16> &indicesp,
|
||||
U32 &index_offset);
|
||||
|
|
|
|||
|
|
@ -1005,16 +1005,11 @@ void LLVOVolume::updateTextureVirtualSize(bool forced)
|
|||
// animated faces get moved to a smaller partition to reduce
|
||||
// side-effects of their updates (see shrinkWrap in
|
||||
// LLVOVolume::animateTextures).
|
||||
// <FS:Beq> FIRE-35018 (Bugsplat) Crash due to spatial group being null
|
||||
// mDrawable->getSpatialGroup()->dirtyGeom();
|
||||
// gPipeline.markRebuild(mDrawable->getSpatialGroup());
|
||||
auto spatial_group = mDrawable->getSpatialGroup();
|
||||
if (spatial_group)
|
||||
if (mDrawable->getSpatialGroup())
|
||||
{
|
||||
spatial_group->dirtyGeom();
|
||||
gPipeline.markRebuild(spatial_group);
|
||||
mDrawable->getSpatialGroup()->dirtyGeom();
|
||||
gPipeline.markRebuild(mDrawable->getSpatialGroup());
|
||||
}
|
||||
// </FS:Beq>
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1396,4 +1396,10 @@
|
|||
<color
|
||||
name="FpsDisplayVSyncLimitReachedColor"
|
||||
reference="Green" />
|
||||
<color
|
||||
name="ChatMentionHighlight"
|
||||
value="0.82 0.91 0.98 0.15" />
|
||||
<color
|
||||
name="ChatSelfMentionHighlight"
|
||||
value="0.85 0.75 0.40 0.5" />
|
||||
</colors>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<floater
|
||||
name="chat_mention_picker"
|
||||
title="CHOOSE RESIDENT"
|
||||
single_instance="true"
|
||||
can_minimize="false"
|
||||
can_tear_off="false"
|
||||
can_resize="true"
|
||||
auto_close="true"
|
||||
layout="topleft"
|
||||
min_width="250"
|
||||
chrome="true"
|
||||
height="125"
|
||||
width="310">
|
||||
<avatar_list
|
||||
allow_select="true"
|
||||
follows="all"
|
||||
height="120"
|
||||
width="306"
|
||||
ignore_online_status="true"
|
||||
layout="topleft"
|
||||
left="3"
|
||||
keep_one_selected="true"
|
||||
multi_select="false"
|
||||
show_info_btn="false"
|
||||
show_profile_btn="false"
|
||||
show_speaking_indicator="false"
|
||||
name="avatar_list"
|
||||
right="-1"
|
||||
top="2" />
|
||||
</floater>
|
||||
|
|
@ -976,8 +976,8 @@
|
|||
label_width="205"
|
||||
layout="topleft"
|
||||
left="10"
|
||||
min_val="-100"
|
||||
max_val="100"
|
||||
min_val="-10000"
|
||||
max_val="10000"
|
||||
name="gltfTextureScaleU"
|
||||
top_delta="-115"
|
||||
width="265" />
|
||||
|
|
@ -989,8 +989,8 @@
|
|||
label_width="205"
|
||||
layout="topleft"
|
||||
left="10"
|
||||
min_val="-100"
|
||||
max_val="100"
|
||||
min_val="-10000"
|
||||
max_val="10000"
|
||||
name="gltfTextureScaleV"
|
||||
width="265" />
|
||||
<spinner
|
||||
|
|
|
|||
Loading…
Reference in New Issue