summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/llaccordionctrl.cpp1
-rw-r--r--indra/llui/llaccordionctrltab.cpp54
-rw-r--r--indra/llui/llemojidictionary.cpp11
-rw-r--r--indra/llui/llemojihelper.cpp10
-rw-r--r--indra/llui/llfloater.cpp2
-rw-r--r--indra/llui/llfolderview.cpp1
-rw-r--r--indra/llui/llfolderviewitem.cpp30
-rw-r--r--indra/llui/llfolderviewitem.h1
-rw-r--r--indra/llui/lltextbase.cpp52
-rw-r--r--indra/llui/lltextbase.h5
-rw-r--r--indra/llui/lltoolbar.cpp2
-rw-r--r--indra/llui/lltoolbar.h2
-rw-r--r--indra/llui/llviewereventrecorder.cpp2
13 files changed, 149 insertions, 24 deletions
diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp
index 495ba2f40f..2cd394476e 100644
--- a/indra/llui/llaccordionctrl.cpp
+++ b/indra/llui/llaccordionctrl.cpp
@@ -494,6 +494,7 @@ void LLAccordionCtrl::arrangeMultiple()
void LLAccordionCtrl::arrange()
{
+ LL_PROFILE_ZONE_SCOPED;
updateNoTabsHelpTextVisibility();
if (mAccordionTabs.empty())
diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp
index ac66525030..828bfb289b 100644
--- a/indra/llui/llaccordionctrltab.cpp
+++ b/indra/llui/llaccordionctrltab.cpp
@@ -248,10 +248,22 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw()
void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::reshape(S32 width, S32 height, bool called_from_parent /* = true */)
{
S32 header_height = mHeaderTextbox->getTextPixelHeight();
+ LLRect old_header_rect = mHeaderTextbox->getRect();
LLRect textboxRect(HEADER_TEXT_LEFT_OFFSET, (height + header_height) / 2, width, (height - header_height) / 2);
- mHeaderTextbox->reshape(textboxRect.getWidth(), textboxRect.getHeight());
- mHeaderTextbox->setRect(textboxRect);
+ if (old_header_rect.getHeight() != textboxRect.getHeight()
+ || old_header_rect.mLeft != textboxRect.mLeft
+ || old_header_rect.mTop != textboxRect.mTop
+ || old_header_rect.getWidth() > textboxRect.getWidth() // reducing header's width
+ || (old_header_rect.getWidth() < textboxRect.getWidth() && old_header_rect.getWidth() < mHeaderTextbox->getTextPixelWidth()))
+ {
+ // Expensive text reflow
+ // Update if position or height changes
+ // Update if width reduces
+ // But do not update if text already fits and width increases (arguably LLTextBox::reshape should be smarter, not Accordion)
+ mHeaderTextbox->reshape(textboxRect.getWidth(), textboxRect.getHeight());
+ mHeaderTextbox->setRect(textboxRect);
+ }
if (mHeaderTextbox->getTextPixelWidth() > mHeaderTextbox->getRect().getWidth())
{
@@ -416,8 +428,11 @@ void LLAccordionCtrlTab::reshape(S32 width, S32 height, bool called_from_parent
LLRect headerRect;
headerRect.setLeftTopAndSize(0, height, width, HEADER_HEIGHT);
- mHeader->setRect(headerRect);
- mHeader->reshape(headerRect.getWidth(), headerRect.getHeight());
+ if (mHeader->getRect() != headerRect)
+ {
+ mHeader->setRect(headerRect);
+ mHeader->reshape(headerRect.getWidth(), headerRect.getHeight());
+ }
if (!mDisplayChildren)
return;
@@ -464,7 +479,34 @@ void LLAccordionCtrlTab::onUpdateScrollToChild(const LLUICtrl *cntrl)
// Translate to parent coordinatess to check if we are in visible rectangle
rect.translate(getRect().mLeft, getRect().mBottom);
- if (!getRect().contains(rect))
+ bool needs_to_scroll = false;
+ const LLRect &acc_rect = getRect();
+ if (!acc_rect.contains(rect))
+ {
+ if (acc_rect.mTop < rect.mBottom || acc_rect.mBottom > rect.mTop)
+ {
+ // Content fully not in view
+ needs_to_scroll = true;
+ }
+ else if (acc_rect.getHeight() >= rect.getHeight())
+ {
+ // Content can be displayed fully, but only partially in view
+ needs_to_scroll = true;
+ }
+ else if (acc_rect.mTop <= rect.mTop || acc_rect.mBottom >= rect.mBottom)
+ {
+ // Intersects, but too big to be displayed fully
+ S32 covered_height = acc_rect.mTop > rect.mTop ? rect.mTop - acc_rect.mBottom : acc_rect.mTop - rect.mBottom;
+ constexpr F32 covered_ratio = 0.7f;
+ if (covered_height < covered_ratio * acc_rect.getHeight())
+ {
+ // Try to show bigger portion of the content
+ needs_to_scroll = true;
+ }
+ }
+ // else too big and in the middle of the view as is
+ }
+ if (needs_to_scroll)
{
// for accordition's scroll, height is in pixels
// Back to local coords and calculate position for scroller
@@ -932,7 +974,7 @@ void LLAccordionCtrlTab::adjustContainerPanel(const LLRect& child_rect)
show_hide_scrollbar(child_rect);
updateLayout(child_rect);
}
- else
+ else if (mContainerPanel->getRect() != child_rect)
{
mContainerPanel->reshape(child_rect.getWidth(), child_rect.getHeight());
mContainerPanel->setRect(child_rect);
diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp
index 925608e47e..16e6f0591a 100644
--- a/indra/llui/llemojidictionary.cpp
+++ b/indra/llui/llemojidictionary.cpp
@@ -390,14 +390,17 @@ void LLEmojiDictionary::loadEmojis()
continue;
}
+ std::string category;
std::list<std::string> categories = loadCategories(sd);
if (categories.empty())
{
- LL_WARNS() << "Skipping invalid emoji descriptor (no categories)" << LL_ENDL;
- continue;
+ // Should already have a localization for "other symbols"
+ category = "other symbols";
+ }
+ else
+ {
+ category = categories.front();
}
-
- std::string category = categories.front();
if (std::find(mSkipCategories.begin(), mSkipCategories.end(), category) != mSkipCategories.end())
{
diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp
index b2c59ce775..7cdd19bebc 100644
--- a/indra/llui/llemojihelper.cpp
+++ b/indra/llui/llemojihelper.cpp
@@ -117,7 +117,17 @@ void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, c
S32 top = floater_y - HELPER_FLOATER_OFFSET_Y + rect.getHeight();
rect.setLeftTopAndSize(left, top, rect.getWidth(), rect.getHeight());
pHelperFloater->setRect(rect);
+
+ // Hack: Trying to open floater, search for a match,
+ // and hide floater immediately if no match found,
+ // instead of checking prior to opening
+ //
+ // Supress sounds in case floater won't be shown.
+ // Todo: add some kind of shouldShow(short_code)
+ U8 sound_flags = pHelperFloater->getSoundFlags();
+ pHelperFloater->setSoundFlags(LLView::SILENT);
pHelperFloater->openFloater(LLSD().with("hint", short_code));
+ pHelperFloater->setSoundFlags(sound_flags);
}
void LLEmojiHelper::hideHelper(const LLUICtrl* ctrl_p, bool strict)
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index fd07b2ec5d..52a5e3dbd6 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -2274,7 +2274,7 @@ void LLFloater::drawConeToOwner(F32 &context_cone_opacity,
LLRect local_rect = getLocalRect();
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLGLEnable(GL_CULL_FACE);
+ LLGLEnable cull_face(GL_CULL_FACE);
gGL.begin(LLRender::TRIANGLE_STRIP);
{
gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp
index b664065532..db4ab8487e 100644
--- a/indra/llui/llfolderview.cpp
+++ b/indra/llui/llfolderview.cpp
@@ -1510,6 +1510,7 @@ bool LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )
&& ( count > 0 && (hasVisibleChildren()) ))) && // show menu only if selected items are visible
!hide_folder_menu)
{
+ LL_INFOS("Inventory") << "Opening inventory menu from path: " << getPathname() << LL_ENDL;
if (mCallbackRegistrar)
{
mCallbackRegistrar->pushScope();
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index 9ca77dbe46..878f1cb856 100644
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -1884,10 +1884,18 @@ void LLFolderViewFolder::updateHasFavorites(bool new_childs_value)
void LLFolderViewFolder::onIdleUpdateFavorites(void* data)
{
LLFolderViewFolder* self = reinterpret_cast<LLFolderViewFolder*>(data);
+ if (self->mFavoritesDirtyFlags == FAVORITE_CLEANUP)
+ {
+ // parent or child already processed the update, clean the callback
+ self->mFavoritesDirtyFlags = 0;
+ gIdleCallbacks.deleteFunction(&LLFolderViewFolder::onIdleUpdateFavorites, data);
+ return;
+ }
+
if (self->mFavoritesDirtyFlags == 0)
{
- // already processed either on previous run or by a different callback
- gIdleCallbacks.deleteFunction(&LLFolderViewFolder::onIdleUpdateFavorites, self);
+ llassert(false); // should not happen, everything that sets to 0 should clean callback
+ gIdleCallbacks.deleteFunction(&LLFolderViewFolder::onIdleUpdateFavorites, data);
return;
}
@@ -1915,7 +1923,7 @@ void LLFolderViewFolder::onIdleUpdateFavorites(void* data)
// Parent will remove onIdleUpdateFavorites later, don't remove now,
// We are inside gIdleCallbacks. Removing 'self' callback is safe,
// but removing 'parent' can invalidate following iterator
- parent->mFavoritesDirtyFlags = 0;
+ parent->mFavoritesDirtyFlags = FAVORITE_CLEANUP;
}
parent = parent->getParentFolder();
}
@@ -1981,7 +1989,7 @@ void LLFolderViewFolder::onIdleUpdateFavorites(void* data)
// Parent will remove onIdleUpdateFavorites later, don't remove now,
// We are inside gIdleCallbacks. Removing 'self' callback is safe,
// but removing 'parent' can invalidate following iterator
- parent->mFavoritesDirtyFlags = 0;
+ parent->mFavoritesDirtyFlags = FAVORITE_CLEANUP;
}
parent = parent->getParentFolder();
}
@@ -1992,7 +2000,7 @@ void LLFolderViewFolder::onIdleUpdateFavorites(void* data)
// Parent will remove onIdleUpdateFavorites later, don't remove now.
// We are inside gIdleCallbacks. Removing 'self' callback is safe,
// but removing 'parent' can invalidate following iterator
- parent->mFavoritesDirtyFlags = 0;
+ parent->mFavoritesDirtyFlags = FAVORITE_CLEANUP;
}
parent = parent->getParentFolder();
}
@@ -2106,10 +2114,14 @@ void LLFolderViewFolder::setOpen(bool openitem)
{
// navigateToFolder can destroy this view
// delay it in case setOpen was called from click or key processing
- doOnIdleOneTime([this]()
- {
- getViewModelItem()->navigateToFolder();
- });
+ LLPointer<LLFolderViewModelItem> view_model_item = mViewModelItem;
+ doOnIdleOneTime([view_model_item]()
+ {
+ if (view_model_item.notNull())
+ {
+ view_model_item.get()->navigateToFolder();
+ }
+ });
}
else
{
diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h
index c9b003b892..23d794bf26 100644
--- a/indra/llui/llfolderviewitem.h
+++ b/indra/llui/llfolderviewitem.h
@@ -421,6 +421,7 @@ private:
constexpr static S32 FAVORITE_ADDED = 1;
constexpr static S32 FAVORITE_REMOVED = 2;
+ constexpr static S32 FAVORITE_CLEANUP = 4;
S32 mFavoritesDirtyFlags { 0 };
public:
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 3fe0df1848..44151a4355 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -185,6 +185,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
mURLClickSignal(NULL),
mIsFriendSignal(NULL),
mIsObjectBlockedSignal(NULL),
+ mIsObjectReachableSignal(NULL),
mMaxTextByteLength( p.max_text_length ),
mFont(p.font),
mFontShadow(p.font_shadow),
@@ -290,6 +291,7 @@ LLTextBase::~LLTextBase()
delete mURLClickSignal;
delete mIsFriendSignal;
delete mIsObjectBlockedSignal;
+ delete mIsObjectReachableSignal;
}
void LLTextBase::initFromParams(const LLTextBase::Params& p)
@@ -1036,8 +1038,37 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
{
LLStyleSP emoji_style;
LLEmojiDictionary* ed = LLEmojiDictionary::instanceExists() ? LLEmojiDictionary::getInstance() : NULL;
+ LLTextSegment* segmentp = nullptr;
+ segment_vec_t::iterator seg_iter;
+ if (segments && segments->size() > 0)
+ {
+ seg_iter = segments->begin();
+ segmentp = *seg_iter;
+ }
for (S32 text_kitty = 0, text_len = static_cast<S32>(wstr.size()); text_kitty < text_len; text_kitty++)
{
+ if (segmentp)
+ {
+ if (segmentp->getEnd() <= pos + text_kitty)
+ {
+ seg_iter++;
+ if (seg_iter != segments->end())
+ {
+ segmentp = *seg_iter;
+ }
+ else
+ {
+ segmentp = nullptr;
+ }
+ }
+ if (segmentp && !segmentp->getPermitsEmoji())
+ {
+ // Some segments, like LLInlineViewSegment do not permit splitting
+ // and should not be interrupted by emoji segments
+ continue;
+ }
+ }
+
llwchar code = wstr[text_kitty];
bool isEmoji = ed ? ed->isEmoji(code) : LLStringOps::isEmoji(code);
if (isEmoji)
@@ -1446,6 +1477,8 @@ void LLTextBase::reshape(S32 width, S32 height, bool called_from_parent)
// up-to-date mVisibleTextRect
updateRects();
+ // Todo: This might be wrong. updateRects already sets needsReflow conditionaly.
+ // Reflow is expensive and doing it at any twith can be too much.
needsReflow();
}
}
@@ -2281,6 +2314,15 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
unblockButton->setVisible(is_blocked);
}
}
+
+ if (mIsObjectReachableSignal)
+ {
+ bool is_reachable = *(*mIsObjectReachableSignal)(LLUUID(LLUrlAction::getObjectId(url)));
+ if (LLView* zoom_btn = menu->getChild<LLView>("zoom_in"))
+ {
+ zoom_btn->setEnabled(is_reachable);
+ }
+ }
menu->show(x, y);
LLMenuGL::showPopup(this, menu, x, y);
}
@@ -3387,6 +3429,15 @@ boost::signals2::connection LLTextBase::setIsObjectBlockedCallback(const is_bloc
return mIsObjectBlockedSignal->connect(cb);
}
+boost::signals2::connection LLTextBase::setIsObjectReachableCallback(const is_obj_reachable_signal_t::slot_type& cb)
+{
+ if (!mIsObjectReachableSignal)
+ {
+ mIsObjectReachableSignal = new is_obj_reachable_signal_t();
+ }
+ return mIsObjectReachableSignal->connect(cb);
+}
+
//
// LLTextSegment
//
@@ -3426,6 +3477,7 @@ S32 LLTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offs
void LLTextSegment::updateLayout(const LLTextBase& editor) {}
F32 LLTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect) { return draw_rect.mLeft; }
bool LLTextSegment::canEdit() const { return false; }
+bool LLTextSegment::getPermitsEmoji() const { return true; }
void LLTextSegment::unlinkFromDocument(LLTextBase*) {}
void LLTextSegment::linkToDocument(LLTextBase*) {}
const LLUIColor& LLTextSegment::getColor() const { static const LLUIColor white = LLUIColorTable::instance().getColor("White", LLColor4::white); return white; }
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 8ca653acb9..50767a35b3 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -87,6 +87,7 @@ public:
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;
+ virtual bool getPermitsEmoji() const;
virtual void unlinkFromDocument(class LLTextBase* editor);
virtual void linkToDocument(class LLTextBase* editor);
@@ -255,6 +256,7 @@ public:
/*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 false; }
+ /*virtual*/ bool getPermitsEmoji() const { return false; }
/*virtual*/ void unlinkFromDocument(class LLTextBase* editor);
/*virtual*/ void linkToDocument(class LLTextBase* editor);
@@ -325,6 +327,7 @@ public:
typedef boost::signals2::signal<bool (const LLUUID& user_id)> is_friend_signal_t;
typedef boost::signals2::signal<bool (const LLUUID& blocked_id, const std::string from)> is_blocked_signal_t;
+ typedef boost::signals2::signal<bool (const LLUUID& obj_id)> is_obj_reachable_signal_t;
struct LineSpacingParams : public LLInitParam::ChoiceBlock<LineSpacingParams>
{
@@ -535,6 +538,7 @@ public:
boost::signals2::connection setURLClickedCallback(const commit_signal_t::slot_type& cb);
boost::signals2::connection setIsFriendCallback(const is_friend_signal_t::slot_type& cb);
boost::signals2::connection setIsObjectBlockedCallback(const is_blocked_signal_t::slot_type& cb);
+ boost::signals2::connection setIsObjectReachableCallback(const is_obj_reachable_signal_t::slot_type& cb);
void setWordWrap(bool wrap);
LLScrollContainer* getScrollContainer() const { return mScroller; }
@@ -783,6 +787,7 @@ protected:
// Used to check if user with given ID is avatar's friend
is_friend_signal_t* mIsFriendSignal;
is_blocked_signal_t* mIsObjectBlockedSignal;
+ is_obj_reachable_signal_t* mIsObjectReachableSignal;
LLUIString mLabel; // text label that is visible when no user text provided
};
diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp
index 5955a28fa3..56ab6e9bae 100644
--- a/indra/llui/lltoolbar.cpp
+++ b/indra/llui/lltoolbar.cpp
@@ -1054,7 +1054,7 @@ bool LLToolBar::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
// if drop is set, it's time to call the callback to get the operation done
if (handled && drop)
{
- handled = mHandleDropCallback(cargo_data, x, y, this);
+ handled = mHandleDropCallback(cargo_data, cargo_type, x, y, this);
}
// We accept only single tool drop on toolbars
diff --git a/indra/llui/lltoolbar.h b/indra/llui/lltoolbar.h
index 5556406fbd..a3f044c256 100644
--- a/indra/llui/lltoolbar.h
+++ b/indra/llui/lltoolbar.h
@@ -41,7 +41,7 @@ class LLIconCtrl;
typedef boost::function<void (S32 x, S32 y, LLToolBarButton* button)> tool_startdrag_callback_t;
typedef boost::function<bool (S32 x, S32 y, const LLUUID& uuid, LLAssetType::EType type)> tool_handledrag_callback_t;
-typedef boost::function<bool (void* data, S32 x, S32 y, LLToolBar* toolbar)> tool_handledrop_callback_t;
+typedef boost::function<bool (void* data, EDragAndDropType cargo_type, S32 x, S32 y, LLToolBar* toolbar)> tool_handledrop_callback_t;
class LLToolBarButton : public LLButton
{
diff --git a/indra/llui/llviewereventrecorder.cpp b/indra/llui/llviewereventrecorder.cpp
index 6d907d7e45..9eefba1390 100644
--- a/indra/llui/llviewereventrecorder.cpp
+++ b/indra/llui/llviewereventrecorder.cpp
@@ -34,8 +34,6 @@ LLViewerEventRecorder::LLViewerEventRecorder() {
logEvents = false;
// Remove any previous event log file
std::string old_log_ui_events_to_llsd_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.old");
- LLFile::remove(old_log_ui_events_to_llsd_file, ENOENT);
-
mLogFilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.llsd");
LLFile::rename(mLogFilename, old_log_ui_events_to_llsd_file, ENOENT);