summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/llmenubutton.cpp100
-rw-r--r--indra/llui/llmenubutton.h19
-rw-r--r--indra/llui/lltextbase.cpp34
-rw-r--r--indra/llui/lltoggleablemenu.cpp18
-rw-r--r--indra/llui/lltoggleablemenu.h5
-rw-r--r--indra/llui/lluistring.h10
-rw-r--r--indra/llui/llurlentry.cpp5
7 files changed, 134 insertions, 57 deletions
diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp
index c1b5efaa72..ac568a83e4 100644
--- a/indra/llui/llmenubutton.cpp
+++ b/indra/llui/llmenubutton.cpp
@@ -29,7 +29,7 @@
#include "llmenubutton.h"
// Linden library includes
-#include "llmenugl.h"
+#include "lltoggleablemenu.h"
#include "llstring.h"
#include "v4color.h"
@@ -44,22 +44,26 @@ LLMenuButton::Params::Params()
LLMenuButton::LLMenuButton(const LLMenuButton::Params& p)
: LLButton(p),
- mMenu(NULL),
- mMenuVisibleLastFrame(false),
+ mIsMenuShown(false),
mMenuPosition(MP_BOTTOM_LEFT)
{
std::string menu_filename = p.menu_filename;
if (!menu_filename.empty())
{
- mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
- if (!mMenu)
+ LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
+ if (!menu)
{
llwarns << "Error loading menu_button menu" << llendl;
+ return;
}
- }
- updateMenuOrigin();
+ menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2));
+
+ mMenuHandle = menu->getHandle();
+
+ updateMenuOrigin();
+ }
}
boost::signals2::connection LLMenuButton::setMouseDownCallback( const mouse_signal_t::slot_type& cb )
@@ -69,34 +73,34 @@ boost::signals2::connection LLMenuButton::setMouseDownCallback( const mouse_sign
void LLMenuButton::hideMenu()
{
- if(!mMenu) return;
- mMenu->setVisible(FALSE);
+ if(mMenuHandle.isDead()) return;
+
+ LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
+ if (menu)
+ {
+ menu->setVisible(FALSE);
+ }
}
-void LLMenuButton::setMenu(LLMenuGL* menu, EMenuPosition position /*MP_TOP_LEFT*/)
+LLToggleableMenu* LLMenuButton::getMenu()
{
- mMenu = menu;
- mMenuPosition = position;
+ return dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
}
-void LLMenuButton::draw()
+void LLMenuButton::setMenu(LLToggleableMenu* menu, EMenuPosition position /*MP_TOP_LEFT*/)
{
- //we save this off so next frame when we try to close it by
- //button click, and it hides menus before we get to it, we know
- mMenuVisibleLastFrame = mMenu && mMenu->getVisible();
-
- if (mMenuVisibleLastFrame)
- {
- setForcePressedState(true);
- }
+ if (!menu) return;
- LLButton::draw();
+ mMenuHandle = menu->getHandle();
+ mMenuPosition = position;
- setForcePressedState(false);
+ menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2));
}
BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
{
+ if (mMenuHandle.isDead()) return FALSE;
+
if( KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key))
{
// *HACK: We emit the mouse down signal to fire the callback bound to the
@@ -107,9 +111,10 @@ BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
return TRUE;
}
- if (mMenu && mMenu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)
+ LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
+ if (menu && menu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)
{
- mMenu->setVisible(FALSE);
+ menu->setVisible(FALSE);
return TRUE;
}
@@ -119,6 +124,7 @@ BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
BOOL LLMenuButton::handleMouseDown(S32 x, S32 y, MASK mask)
{
LLButton::handleMouseDown(x, y, mask);
+
toggleMenu();
return TRUE;
@@ -126,28 +132,38 @@ BOOL LLMenuButton::handleMouseDown(S32 x, S32 y, MASK mask)
void LLMenuButton::toggleMenu()
{
- if(!mMenu) return;
+ if(mMenuHandle.isDead()) return;
+
+ LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
+ if (!menu) return;
- if (mMenu->getVisible() || mMenuVisibleLastFrame)
+ // Store the button rectangle to toggle menu visibility if a mouse event
+ // occurred inside or outside the button rect.
+ menu->setButtonRect(this);
+
+ if (!menu->toggleVisibility() && mIsMenuShown)
{
- mMenu->setVisible(FALSE);
+ setForcePressedState(false);
+ mIsMenuShown = false;
}
else
{
- mMenu->buildDrawLabels();
- mMenu->arrangeAndClear();
- mMenu->updateParent(LLMenuGL::sMenuContainer);
+ menu->buildDrawLabels();
+ menu->arrangeAndClear();
+ menu->updateParent(LLMenuGL::sMenuContainer);
updateMenuOrigin();
- //mMenu->needsArrange(); //so it recalculates the visible elements
- LLMenuGL::showPopup(getParent(), mMenu, mX, mY);
+ LLMenuGL::showPopup(getParent(), menu, mX, mY);
+
+ setForcePressedState(true);
+ mIsMenuShown = true;
}
}
void LLMenuButton::updateMenuOrigin()
{
- if (!mMenu) return;
+ if (mMenuHandle.isDead()) return;
LLRect rect = getRect();
@@ -156,7 +172,7 @@ void LLMenuButton::updateMenuOrigin()
case MP_TOP_LEFT:
{
mX = rect.mLeft;
- mY = rect.mTop + mMenu->getRect().getHeight();
+ mY = rect.mTop + mMenuHandle.get()->getRect().getHeight();
break;
}
case MP_BOTTOM_LEFT:
@@ -167,3 +183,17 @@ void LLMenuButton::updateMenuOrigin()
}
}
}
+
+void LLMenuButton::onMenuVisibilityChange(const LLSD& param)
+{
+ bool new_visibility = param["visibility"].asBoolean();
+ bool is_closed_by_button_click = param["closed_by_button_click"].asBoolean();
+
+ // Reset the button "pressed" state only if the menu is shown by this particular
+ // menu button (not any other control) and is not being closed by a click on the button.
+ if (!new_visibility && !is_closed_by_button_click && mIsMenuShown)
+ {
+ setForcePressedState(false);
+ mIsMenuShown = false;
+ }
+}
diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h
index 81c3592b16..9e91b9e99d 100644
--- a/indra/llui/llmenubutton.h
+++ b/indra/llui/llmenubutton.h
@@ -29,7 +29,7 @@
#include "llbutton.h"
-class LLMenuGL;
+class LLToggleableMenu;
class LLMenuButton
: public LLButton
@@ -52,14 +52,13 @@ public:
boost::signals2::connection setMouseDownCallback( const mouse_signal_t::slot_type& cb );
- /*virtual*/ void draw();
/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask );
void hideMenu();
- LLMenuGL* getMenu() { return mMenu; }
- void setMenu(LLMenuGL* menu, EMenuPosition position = MP_TOP_LEFT);
+ LLToggleableMenu* getMenu();
+ void setMenu(LLToggleableMenu* menu, EMenuPosition position = MP_TOP_LEFT);
void setMenuPosition(EMenuPosition position) { mMenuPosition = position; }
@@ -70,12 +69,14 @@ protected:
void toggleMenu();
void updateMenuOrigin();
+ void onMenuVisibilityChange(const LLSD& param);
+
private:
- LLMenuGL* mMenu;
- bool mMenuVisibleLastFrame;
- EMenuPosition mMenuPosition;
- S32 mX;
- S32 mY;
+ LLHandle<LLView> mMenuHandle;
+ bool mIsMenuShown;
+ EMenuPosition mMenuPosition;
+ S32 mX;
+ S32 mY;
};
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 758df418e8..5721df6b36 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -2214,19 +2214,39 @@ bool LLTextBase::scrolledToEnd()
return mScroller->isAtBottom();
}
-
bool LLTextBase::setCursor(S32 row, S32 column)
{
- if (0 <= row && row < (S32)mLineInfoList.size())
+ if (row < 0 || column < 0) return false;
+
+ S32 n_lines = mLineInfoList.size();
+ for (S32 line = row; line < n_lines; ++line)
{
- S32 doc_pos = mLineInfoList[row].mDocIndexStart;
- column = llclamp(column, 0, mLineInfoList[row].mDocIndexEnd - mLineInfoList[row].mDocIndexStart - 1);
- doc_pos += column;
- updateCursorXPos();
+ const line_info& li = mLineInfoList[line];
+
+ if (li.mLineNum < row)
+ {
+ continue;
+ }
+ else if (li.mLineNum > row)
+ {
+ break; // invalid column specified
+ }
+
+ // Found the given row.
+ S32 line_length = li.mDocIndexEnd - li.mDocIndexStart;;
+ if (column >= line_length)
+ {
+ column -= line_length;
+ continue;
+ }
+ // Found the given column.
+ updateCursorXPos();
+ S32 doc_pos = li.mDocIndexStart + column;
return setCursorPos(doc_pos);
}
- return false;
+
+ return false; // invalid row or column specified
}
diff --git a/indra/llui/lltoggleablemenu.cpp b/indra/llui/lltoggleablemenu.cpp
index 0eb2dc1387..d29260750f 100644
--- a/indra/llui/lltoggleablemenu.cpp
+++ b/indra/llui/lltoggleablemenu.cpp
@@ -35,10 +35,22 @@ static LLDefaultChildRegistry::Register<LLToggleableMenu> r("toggleable_menu");
LLToggleableMenu::LLToggleableMenu(const LLToggleableMenu::Params& p)
: LLMenuGL(p),
mButtonRect(),
+ mVisibilityChangeSignal(NULL),
mClosedByButtonClick(false)
{
}
+LLToggleableMenu::~LLToggleableMenu()
+{
+ delete mVisibilityChangeSignal;
+}
+
+boost::signals2::connection LLToggleableMenu::setVisibilityChangeCallback(const commit_signal_t::slot_type& cb)
+{
+ if (!mVisibilityChangeSignal) mVisibilityChangeSignal = new commit_signal_t();
+ return mVisibilityChangeSignal->connect(cb);
+}
+
// virtual
void LLToggleableMenu::handleVisibilityChange (BOOL curVisibilityIn)
{
@@ -49,6 +61,12 @@ void LLToggleableMenu::handleVisibilityChange (BOOL curVisibilityIn)
{
mClosedByButtonClick = true;
}
+
+ if (mVisibilityChangeSignal)
+ {
+ (*mVisibilityChangeSignal)(this,
+ LLSD().with("visibility", curVisibilityIn).with("closed_by_button_click", mClosedByButtonClick));
+ }
}
void LLToggleableMenu::setButtonRect(const LLRect& rect, LLView* current_view)
diff --git a/indra/llui/lltoggleablemenu.h b/indra/llui/lltoggleablemenu.h
index f036cdfffb..2094bd776f 100644
--- a/indra/llui/lltoggleablemenu.h
+++ b/indra/llui/lltoggleablemenu.h
@@ -41,6 +41,10 @@ protected:
LLToggleableMenu(const Params&);
friend class LLUICtrlFactory;
public:
+ ~LLToggleableMenu();
+
+ boost::signals2::connection setVisibilityChangeCallback( const commit_signal_t::slot_type& cb );
+
virtual void handleVisibilityChange (BOOL curVisibilityIn);
const LLRect& getButtonRect() const { return mButtonRect; }
@@ -57,6 +61,7 @@ public:
protected:
bool mClosedByButtonClick;
LLRect mButtonRect;
+ commit_signal_t* mVisibilityChangeSignal;
};
#endif // LL_LLTOGGLEABLEMENU_H
diff --git a/indra/llui/lluistring.h b/indra/llui/lluistring.h
index eff2467bf0..4faa0e070e 100644
--- a/indra/llui/lluistring.h
+++ b/indra/llui/lluistring.h
@@ -58,10 +58,12 @@ class LLUIString
public:
// These methods all perform appropriate argument substitution
// and modify mOrig where appropriate
- LLUIString() : mArgs(NULL), mNeedsResult(false), mNeedsWResult(false) {}
+ LLUIString() : mArgs(NULL), mNeedsResult(false), mNeedsWResult(false) {}
LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args);
LLUIString(const std::string& instring) : mArgs(NULL) { assign(instring); }
+ ~LLUIString() { delete mArgs; }
+
void assign(const std::string& instring);
LLUIString& operator=(const std::string& s) { assign(s); return *this; }
@@ -81,14 +83,14 @@ public:
void clear();
void clearArgs() { if (mArgs) mArgs->clear(); }
-
+
// These utility functions are included for text editing.
// They do not affect mOrig and do not perform argument substitution
void truncate(S32 maxchars);
void erase(S32 charidx, S32 len);
void insert(S32 charidx, const LLWString& wchars);
void replace(S32 charidx, llwchar wc);
-
+
private:
// something changed, requiring reformatting of strings
void dirty();
@@ -100,7 +102,7 @@ private:
void updateResult() const;
void updateWResult() const;
LLStringUtil::format_map_t& getArgs();
-
+
std::string mOrig;
mutable std::string mResult;
mutable LLWString mWResult; // for displaying
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index f58c07754f..84678ef4db 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -972,7 +972,7 @@ std::string LLUrlEntryWorldMap::getLocation(const std::string &url) const
//
LLUrlEntryNoLink::LLUrlEntryNoLink()
{
- mPattern = boost::regex("<nolink>[^<]*</nolink>",
+ mPattern = boost::regex("<nolink>.*</nolink>",
boost::regex::perl|boost::regex::icase);
}
@@ -989,7 +989,8 @@ std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelC
LLStyle::Params LLUrlEntryNoLink::getStyle() const
{
- return LLStyle::Params();
+ // Don't render as URL (i.e. no context menu or hand cursor).
+ return LLStyle::Params().is_link(false);
}